From cd47125598c2672d2f0fbbc9a9e6830d9913abfa Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sun, 19 Jul 2026 18:12:29 +0200 Subject: [PATCH 001/242] reimplement OpenSHC::AI::AICState: first pass --- .../AI/AICState/abortAttackAndGoIdle.cpp | 23 ++++++++ .../addBuildingToTargetableBuildings.cpp | 24 +++++++++ .../AI/AICState/addEngineersToSelection.cpp | 45 ++++++++++++++++ .../AI/AICState/addEngineersToTribe.cpp | 35 +++++++++++++ src/OpenSHC/AI/AICState/aiFarmChoice.cpp | 22 ++++++++ src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp | 31 +++++++++++ .../AI/AICState/aiShouldBuildIronMine.cpp | 34 ++++++++++++ .../AI/AICState/aiShouldBuildPitchrig.cpp | 36 +++++++++++++ .../AI/AICState/aiShouldBuildQuarry.cpp | 34 ++++++++++++ .../AI/AICState/aiShouldBuildWoodcutter.cpp | 46 ++++++++++++++++ src/OpenSHC/AI/AICState/destroyHouse.cpp | 34 ++++++++++++ .../AI/AICState/getResourceRebuildDelay.cpp | 21 ++++++++ src/OpenSHC/AI/AICState/sellGoods.cpp | 29 +++++++++++ .../setCurrentAttackRaidParameter.cpp | 37 +++++++++++++ .../AI/AICState/setCurrentAttackStrength.cpp | 40 ++++++++++++++ .../AI/AICState/setNextFarmTypeToBuild.cpp | 29 +++++++++++ .../AICState/shouldNotBeBuildingArmoury.cpp | 18 +++++++ .../AICState/shouldNotBeBuildingGranary.cpp | 18 +++++++ .../AI/AICState/shouldNotBeBuildingHovel.cpp | 26 ++++++++++ .../AI/AICState/shouldNotBuildKillingPits.cpp | 19 +++++++ ...uldWaitWithBuildingAPositiveFearFactor.cpp | 52 +++++++++++++++++++ ...ouldWaitWithBuildingNegativeFearFactor.cpp | 38 ++++++++++++++ .../woodCuttersHutWhileNoWoodAvailable.cpp | 20 +++++++ 23 files changed, 711 insertions(+) create mode 100644 src/OpenSHC/AI/AICState/abortAttackAndGoIdle.cpp create mode 100644 src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp create mode 100644 src/OpenSHC/AI/AICState/addEngineersToSelection.cpp create mode 100644 src/OpenSHC/AI/AICState/addEngineersToTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/aiFarmChoice.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp create mode 100644 src/OpenSHC/AI/AICState/destroyHouse.cpp create mode 100644 src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp create mode 100644 src/OpenSHC/AI/AICState/sellGoods.cpp create mode 100644 src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp create mode 100644 src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp create mode 100644 src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp create mode 100644 src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp diff --git a/src/OpenSHC/AI/AICState/abortAttackAndGoIdle.cpp b/src/OpenSHC/AI/AICState/abortAttackAndGoIdle.cpp new file mode 100644 index 000000000..bdd9f7312 --- /dev/null +++ b/src/OpenSHC/AI/AICState/abortAttackAndGoIdle.cpp @@ -0,0 +1,23 @@ +#include "../AICState.func.hpp" + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D45E0 + void AICState::abortAttackAndGoIdle(int playerID) + { + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + MACRO_CALL_MEMBER(AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + MACRO_CALL_MEMBER(AICState_Func::addEngineersToTribe, this)(playerID); + MACRO_CALL_MEMBER(AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp b/src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp new file mode 100644 index 000000000..8f92126ff --- /dev/null +++ b/src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp @@ -0,0 +1,24 @@ +#include "../AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDA50 + void AICState::addBuildingToTargetableBuildings(int buildingID) + { + int _player = DAT_BuildingsState::instance.buildings[buildingID].owner; + if (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY) { + int* piVar1 = &DAT_GameState::instance.playerDataArray[_player].top100TargetableBuildingsTracker; + if ((*piVar1 < 100) && (DAT_BuildingsState::instance.buildings[buildingID].fireDuration == 0)) { + DAT_GameState::instance.playerDataArray[_player].top100TargetableBuildings[*piVar1] = (short)buildingID; + *piVar1 = *piVar1 + 1; + } + } + } + +} +} diff --git a/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp b/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp new file mode 100644 index 000000000..db3392918 --- /dev/null +++ b/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp @@ -0,0 +1,45 @@ +#include "../AICState.func.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC680 + int AICState::addEngineersToSelection(int playerID, int unitCount) + { + int tribeID; + uint unitID; + + tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + /* Unit offset 150 */ + Map::Units::Unit* _ptrUnit = &DAT_UnitsState::instance.units[1]; + do { + if (unitCount <= 0) { + return tribeID; + } + if ((((_ptrUnit->logicalState == Map::Units::ULS_NORMAL) && (_ptrUnit->owner == playerID)) + && (_ptrUnit->dying == 0)) + && (((_ptrUnit->unitType == Map::Units::UT_E_ENGINEER) && (_ptrUnit->aiUnitBehaviourType == 10)) + && ((_ptrUnit->tribeID == 0) + && ((_ptrUnit->state).generic != Map::Units::States::US_STAND_UPUnk)))) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, tribeID); + unitCount = unitCount + -1; + } + unitID = unitID + 1; + _ptrUnit = _ptrUnit + 1; + } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + return tribeID; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp b/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp new file mode 100644 index 000000000..e9c39df1a --- /dev/null +++ b/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp @@ -0,0 +1,35 @@ +#include "../AICState.func.hpp" + +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4040 + void AICState::addEngineersToTribe(int playerID) + { + int unitID; + + unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + /* Unit offset 150 */ + Map::Units::Unit* psVar1 = &DAT_UnitsState::instance.units[1]; + do { + /* if logicalState == normal && owner == playerID && unitType == 0x1e (engineer) + && aiUnitBehaviourType == 10 */ + if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == playerID)) + && (psVar1->dying == 0)) + && (((psVar1->unitType == Map::Units::UT_E_ENGINEER) && (psVar1->aiUnitBehaviourType == 10)) + && (psVar1->tribeID == 0))) { + MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 10); + } + unitID = unitID + 1; + psVar1 = psVar1 + 1; + } while (unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiFarmChoice.cpp b/src/OpenSHC/AI/AICState/aiFarmChoice.cpp new file mode 100644 index 000000000..82412eba9 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiFarmChoice.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB180 + int AICState::aiFarmChoice(PlayerID playerID) + + { + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + + /* ugly because EAX is always 1 or higher */ + return (&this->DAT_AICArray[(aiType - 1)].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp new file mode 100644 index 000000000..cd1bede8d --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB220 + uint AICState::aiShouldBuildFarm(PlayerID playerID) + { + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + int _farmCount + = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countFarms, DAT_BuildingsState::ptr)(playerID, 1); + if (_farmCount < 1) { + return 1; + } + AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + if (_farmCount >= (int)spec->maxFarms) { + return 0; + } + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / _farmCount + >= (int)spec->populationPerFarm; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp new file mode 100644 index 000000000..a9a7fde60 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp @@ -0,0 +1,34 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB4D0 + uint AICState::aiShouldBuildIronMine(PlayerID playerID) + { + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + if ((int)spec->populationPerIronmine <= 0) { + return 0; + } + int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_IRONMINE, 1); + if (iVar3 < 1) { + iVar3 = 1; + } else if (iVar3 >= (int)spec->maxIronmines) { + return 0; + } + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / iVar3 + >= (int)spec->populationPerIronmine; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp new file mode 100644 index 000000000..2ef6bf1f7 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp @@ -0,0 +1,36 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB540 + uint AICState::aiShouldBuildPitchrig(PlayerID param_1) + { + int const aiType = DAT_GameState::instance.playerDataArray[param_1].aiType; + if (aiType == AITA_NULL) { + return 0; + } + AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + if ((int)spec->populationPerPitchrig <= 0) { + return 0; + } + int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(param_1, Map::Buildings::BT_PITCHRIG, 1); + if (iVar3 < 1) { + iVar3 = 1; + } else { + if (iVar3 >= (int)spec->maxPitchrigs) { + return 0; + } + } + return DAT_GameState::instance.playerDataArray[param_1].currentPopulation / iVar3 + >= (int)spec->populationPerPitchrig; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp new file mode 100644 index 000000000..c8f602ef5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp @@ -0,0 +1,34 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB330 + uint AICState::aiShouldBuildQuarry(PlayerID playerID) + { + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + if ((int)spec->populationPerQuarry <= 0) { + return 0; + } + int _quarryCount = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_QUARRY, 1); + if (_quarryCount < 1) { + _quarryCount = 1; + } else if (_quarryCount >= (int)spec->maxQuarries) { + return 0; + } + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / _quarryCount + >= (int)spec->populationPerQuarry; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp new file mode 100644 index 000000000..4e78da7d0 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp @@ -0,0 +1,46 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB290 + uint AICState::aiShouldBuildWoodcutter(PlayerID playerID) + { + if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 1) { + return 0; + } + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + if ((int)spec->populationPerWoodcutter <= 0) { + return 0; + } + int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT, 1); + if (iVar3 < 1) { + iVar3 = 1; + } else { + if (iVar3 >= (int)spec->maxWoodcutters) { + return 0; + } + if ((5 < iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 91)) { + return 0; + } + if ((2 < iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 31)) { + return 0; + } + } + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / iVar3 + >= (int)spec->populationPerWoodcutter; + } +} +} diff --git a/src/OpenSHC/AI/AICState/destroyHouse.cpp b/src/OpenSHC/AI/AICState/destroyHouse.cpp new file mode 100644 index 000000000..e04f4d87f --- /dev/null +++ b/src/OpenSHC/AI/AICState/destroyHouse.cpp @@ -0,0 +1,34 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB810 + BOOLEnum AICState::destroyHouse(int playerID) + { + int _hovelID; + if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (_hovelID = DAT_GameState::instance.playerDataArray[playerID].currentPopulation, + _hovelID <= DAT_GameState::instance.playerDataArray[playerID].populationCap)) + && (8 < _hovelID)) + && (0x14 < DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk)) { + _hovelID = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_HOVEL); + if (_hovelID == 0) { + return FALSE; + } + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(_hovelID, playerID, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hovelID); + return TRUE; + } + return FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp b/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp new file mode 100644 index 000000000..9d8493888 --- /dev/null +++ b/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB150 + int AICState::getResourceRebuildDelay(int playerID) + + { + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + + return this->DAT_AICArray[(aiType - 1)].resourceRebuildDelay; + } +} +} diff --git a/src/OpenSHC/AI/AICState/sellGoods.cpp b/src/OpenSHC/AI/AICState/sellGoods.cpp new file mode 100644 index 000000000..d8dceeb33 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sellGoods.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CBFA0 + void AICState::sellGoods(int playerID, ResourceType resourceType, int amount) + { + int _yield = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::getSellPrice, DAT_GameState::ptr)( + playerID, resourceType, amount); + int* _pFinalGold = DAT_GameSynchronyState::instance.SEC_FinalResults.finalGold + playerID; + *_pFinalGold = *_pFinalGold + _yield; + int* _pGold = DAT_GameState::instance.playerDataArray[playerID].currentResources + 0xf; + *_pGold = *_pGold + _yield; + int* _pGoldSell = &DAT_GameState::instance.playerDataArray[playerID].marketGold; + *_pGoldSell = *_pGoldSell + _yield; + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::processResourceLoss, DAT_BuildingsState::ptr)( + playerID, resourceType, amount, 0); + MACRO_CALL_MEMBER(Game::GameStateStructures_Func::displayPlayerTradeVisualEffect, DAT_GameState::ptr)( + playerID, 1, -amount, resourceType); + } +} +} diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp new file mode 100644 index 000000000..92afcf357 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp @@ -0,0 +1,37 @@ +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDF10 + void AICState::setCurrentAttackRaidParameter(int playerID) + { + int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType != AITA_NULL) { + int _rng = (int)SEC_RNG::instance.currentNumber2; + MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + AICSpecification const* spec = &this->DAT_AICArray[_aiType - 1]; + int _gold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; + int _raidUnitsRandom = (int)spec->RaidUnitsRandom; + if (_gold < 1000) { + _raidUnitsRandom = 0; + } else if (4999 < _gold) { + _raidUnitsRandom = _raidUnitsRandom * 2; + } + if (DAT_GameState::instance + .playerDataArray[DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk] + .currentResources[0xf] + < 500) { + _raidUnitsRandom = -((int)spec->RaidUnitsBase / 2); + } + DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + = (_raidUnitsRandom * (_rng % 100)) / 100; + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp new file mode 100644 index 000000000..53cc9576f --- /dev/null +++ b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDE60 + void AICState::setCurrentAttackStrength(int playerID) + { + int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType != AITA_NULL) { + int _randomNumber = (int)SEC_RNG::instance.currentNumber2; + MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + int _attForceRandom = (int)this->DAT_AICArray[_aiType - 1].AttForceRandom; + int* _attackWave = &DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; + *_attackWave = *_attackWave + 1; + int _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength + = (_attForceRandom * (_randomNumber % 100)) / 100; + int _currentAttackWave = DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; + if (_currentGold < 10001) { + int* _ptrAttackStrength + = &DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; + *_ptrAttackStrength = *_ptrAttackStrength + _currentAttackWave * 5; + } else { + int* _ptrAttackStrength + = &DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; + *_ptrAttackStrength = *_ptrAttackStrength + _currentAttackWave * 7; + } + if (200 < DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength) { + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 200; + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp new file mode 100644 index 000000000..5e81a2a99 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB1B0 + int AICState::setNextFarmTypeToBuild(PlayerID playerID) + + { + int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == AITA_NULL) { + return 0; + } + int* _ptrAiFarmIndex = &DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex; + *_ptrAiFarmIndex = *_ptrAiFarmIndex + 1; + if (7 < DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex) { + DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; + } + if ((&this->DAT_AICArray[_aiType - 1].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] + == 0) { + DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; + } + return (&this->DAT_AICArray[_aiType - 1].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp new file mode 100644 index 000000000..cff5e2904 --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp @@ -0,0 +1,18 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004ECA60 + BOOLEnum AICState::shouldNotBeBuildingArmoury(PlayerID playerID, Commands::CommandBuildingType commandBuildingType) + { + if (commandBuildingType != Commands::CBT_ARMORY) { + return FALSE; + } + return DAT_GameState::instance.playerDataArray[playerID].isArmouryAlmostFilledUp == 0; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp new file mode 100644 index 000000000..93ea91df5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp @@ -0,0 +1,18 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004ECA30 + BOOLEnum AICState::shouldNotBeBuildingGranary(int playerID, Commands::CommandBuildingType commandBuildingType) + { + if (commandBuildingType != Commands::CBT_GRANARY) { + return FALSE; + } + return DAT_GameState::instance.playerDataArray[playerID].granaryIsAlmostFilledUp == FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp new file mode 100644 index 000000000..43483ef0a --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB5B0 + BOOLEnum AICState::shouldNotBeBuildingHovel(PlayerID playerID, Commands::CommandBuildingType param_2) + { + if (param_2 == Commands::CBT_HOVEL) { + int const populationCap = DAT_GameState::instance.playerDataArray[playerID].populationCap; + if (12 < populationCap) { + if (((populationCap <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation) + && (DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants < 5)) + && (DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk < 5)) { + return DAT_GameState::instance.playerDataArray[playerID].popularity < 5000; + } + return TRUE; + } + } + return FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp new file mode 100644 index 000000000..47697719a --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004ECA90 + BOOLEnum AICState::shouldNotBuildKillingPits(int playerID, Commands::CommandBuildingType commandBuildingType) + { + BOOLEnum _totalAbove99 = FALSE; + if (commandBuildingType == Commands::CBT_KILLINGPIT) { + _totalAbove99 = (BOOLEnum)(DAT_AIVState::instance.mapExtraInfo.playerTotalKillingPits[playerID] >= 100); + } + return _totalAbove99; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp new file mode 100644 index 000000000..676b02f35 --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp @@ -0,0 +1,52 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB700 + BOOLEnum AICState::shouldWaitWithBuildingAPositiveFearFactor(int playerID, Commands::CommandBuildingType param_2) + { + int* piVar1; + switch (param_2) { + case Commands::CBT_COMMUNAL_GARDEN1: + case Commands::CBT_COMMUNAL_GARDEN2: + case Commands::CBT_COMMUNAL_GARDEN3: + case Commands::CBT_COMMUNAL_GARDEN4: + case Commands::CBT_COMMUNAL_GARDEN5: + case Commands::CBT_SHRUB_GARDEN6: + case Commands::CBT_COMMUNAL_GARDEN7: + case Commands::CBT_COMMUNAL_GARDEN8: + case Commands::CBT_COMMUNAL_GARDEN9: + case Commands::CBT_TOWN_GARDEN10: + case Commands::CBT_TOWN_GARDEN11: + case Commands::CBT_TOWN_GARDEN12: + case Commands::CBT_MAYPOLE: + case Commands::CBT_STATUE1: + case Commands::CBT_STATUE2: + case Commands::CBT_STATUE3: + case Commands::CBT_STATUE4: + case Commands::CBT_STATUE5: + case Commands::CBT_SHRINE1: + case Commands::CBT_SHRINE2: + case Commands::CBT_SHRINE3: + case Commands::CBT_SHRINE4: + case Commands::CBT_SHRINE5: + case Commands::CBT_DANCINGBEAR: + case Commands::CBT_POND_1: + case Commands::CBT_SMALL_POND_3: + case Commands::CBT_LARGE_POND_3: + case Commands::CBT_LARGE_POND_4: + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay; + *piVar1 = *piVar1 + 1; + if (DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay < 200) { + return TRUE; + } + DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay = 0; + } + return FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp new file mode 100644 index 000000000..36ab16d6f --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp @@ -0,0 +1,38 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB610 + BOOLEnum AICState::shouldWaitWithBuildingNegativeFearFactor(int param_1, Commands::CommandBuildingType param_2) + { + int* piVar1; + switch (param_2) { + case Commands::CBT_GALLOWS: + case Commands::CBT_STOCKS: + case Commands::CBT_CESSPIT1: + case Commands::CBT_CESSPIT2: + case Commands::CBT_CESSPIT3: + case Commands::CBT_CESSPIT4: + case Commands::CBT_BURNINGSTAKE: + case Commands::CBT_GIBBET: + case Commands::CBT_DUNGEON: + case Commands::CBT_STRETCHINGRACK: + case Commands::CBT_RACKFLOGGING: + case Commands::CBT_CHOPPINGBLOCK: + case Commands::CBT_DUNKINGSTOOL: + if ((DAT_GameState::instance.playerDataArray[param_1].popularity < 5000) + || (piVar1 = &DAT_GameState::instance.playerDataArray[param_1].aivNegativeFearFactorDelay, + *piVar1 = *piVar1 + 1, + DAT_GameState::instance.playerDataArray[param_1].aivNegativeFearFactorDelay < 100)) { + return TRUE; + } + DAT_GameState::instance.playerDataArray[param_1].aivNegativeFearFactorDelay = 0; + } + return FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp b/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp new file mode 100644 index 000000000..851e01542 --- /dev/null +++ b/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp @@ -0,0 +1,20 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004ECAB0 + BOOLEnum AICState::woodCuttersHutWhileNoWoodAvailable( + undefined4 playerID, Commands::CommandBuildingType commandBuildingType) + { + if ((commandBuildingType == Commands::CBT_WOODCUTTERSHUT) + && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0)) { + return TRUE; + } + return FALSE; + } +} +} From 10a9b3dcc98e6d99ab40d83c8bec8ffcb1a98bea Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sun, 19 Jul 2026 22:16:23 +0200 Subject: [PATCH 002/242] pass 2 --- src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp | 25 ++++++++------- .../AI/AICState/aiShouldBuildWoodcutter.cpp | 19 ++++++------ src/OpenSHC/AI/AICState/buyGoods.cpp | 28 +++++++++++++++++ .../getCurrentDesiredAttackRaidUnitCount.cpp | 22 +++++++++++++ .../AI/AICState/hasNotEnoughSupplies.cpp | 27 ++++++++++++++++ .../AICState/setAttackCoordinationLevel.cpp | 31 +++++++++++++++++++ .../AI/AICState/setAttackPrimeInfo.cpp | 22 +++++++++++++ .../AI/AICState/setNextFarmTypeToBuild.cpp | 10 +++--- .../setSomeTimeToNowIfInIngameMenu.cpp | 19 ++++++++++++ .../AICState/setTriggerForAITauntResponse.cpp | 19 ++++++++++++ src/OpenSHC/AI/AICState/yieldCowThrow.cpp | 26 ++++++++++++++++ 11 files changed, 222 insertions(+), 26 deletions(-) create mode 100644 src/OpenSHC/AI/AICState/buyGoods.cpp create mode 100644 src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp create mode 100644 src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp create mode 100644 src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp create mode 100644 src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp create mode 100644 src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp create mode 100644 src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp create mode 100644 src/OpenSHC/AI/AICState/yieldCowThrow.cpp diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp index cd1bede8d..25aca2c0d 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp @@ -9,23 +9,24 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB220 - uint AICState::aiShouldBuildFarm(PlayerID playerID) + BOOLEnum AICState::aiShouldBuildFarm(PlayerID playerID) { - int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + int const _playerID = playerID; + unsigned int aiType = DAT_GameState::instance.playerDataArray[_playerID].aiType; if (aiType == AITA_NULL) { - return 0; + return aiType; // return 0 => return } - int _farmCount - = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countFarms, DAT_BuildingsState::ptr)(playerID, 1); - if (_farmCount < 1) { - return 1; + aiType -= 1; + int const _farmCount + = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countFarms, DAT_BuildingsState::ptr)(_playerID, 1); + if (_farmCount <= 0) { + return TRUE; } - AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; - if (_farmCount >= (int)spec->maxFarms) { - return 0; + if (_farmCount >= (int)this->DAT_AICArray[aiType].maxFarms) { + return FALSE; } - return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / _farmCount - >= (int)spec->populationPerFarm; + return DAT_GameState::instance.playerDataArray[_playerID].currentPopulation / _farmCount + >= (int)this->DAT_AICArray[aiType].populationPerFarm; } } } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp index 4e78da7d0..ce4ba794a 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp @@ -13,34 +13,35 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB290 uint AICState::aiShouldBuildWoodcutter(PlayerID playerID) { - if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 1) { + if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0) { return 0; } - int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (aiType == AITA_NULL) { return 0; } - AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; - if ((int)spec->populationPerWoodcutter <= 0) { + aiType -= 1; + // AICSpecification const* spec = &this->DAT_AICArray[aiType]; + if ((int)this->DAT_AICArray[aiType].populationPerWoodcutter <= 0) { return 0; } int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT, 1); - if (iVar3 < 1) { + if (iVar3 <= 0) { iVar3 = 1; } else { - if (iVar3 >= (int)spec->maxWoodcutters) { + if (iVar3 >= (int)this->DAT_AICArray[aiType].maxWoodcutters) { return 0; } - if ((5 < iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 91)) { + if ((6 <= iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 90)) { return 0; } - if ((2 < iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 31)) { + if ((3 <= iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 30)) { return 0; } } return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / iVar3 - >= (int)spec->populationPerWoodcutter; + >= (int)this->DAT_AICArray[aiType].populationPerWoodcutter; } } } diff --git a/src/OpenSHC/AI/AICState/buyGoods.cpp b/src/OpenSHC/AI/AICState/buyGoods.cpp new file mode 100644 index 000000000..d27a0501e --- /dev/null +++ b/src/OpenSHC/AI/AICState/buyGoods.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC000 + BOOLEnum AICState::buyGoods(int playerID, ResourceType resourceType, int amount) + { + int _cost = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::getBuyPrice, DAT_GameState::ptr)(playerID, resourceType, amount); + BOOLEnum _gain = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::processResourceGain, DAT_BuildingsState::ptr)(playerID, resourceType, amount); + if (_gain != FALSE) { + int* piVar1 = DAT_GameState::instance.playerDataArray[playerID].currentResources + 0xf; + *piVar1 = *piVar1 - _cost; + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].marketGold; + *piVar1 = *piVar1 - _cost; + MACRO_CALL_MEMBER(Game::GameStateStructures_Func::displayPlayerTradeVisualEffect, DAT_GameState::ptr)(playerID, 0, amount, resourceType); + return TRUE; + } + return FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp b/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp new file mode 100644 index 000000000..8be83b087 --- /dev/null +++ b/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Game/TrailType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D12A0 + int AICState::getCurrentDesiredAttackRaidUnitCount(int aiType, int playerID) + { + if (((DAT_GameCore::instance.gameMode_2 == Game::GM_SKIRMISH_AND_MULTIPLAYER) && + (DAT_GameCore::instance.isSkirmishTrail == TRUE)) && (DAT_GameCore::instance.currentTrailType == Game::TT_EXTREME)) { + return (int)((DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + this->DAT_AICArray[aiType].RaidUnitsBase) * 4) / 3; + } + return DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + this->DAT_AICArray[aiType].RaidUnitsBase; + } +} +} diff --git a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp new file mode 100644 index 000000000..0f772a912 --- /dev/null +++ b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp @@ -0,0 +1,27 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D00A0 + BOOLEnum AICState::hasNotEnoughSupplies(int playerID) + { + BOOLEnum BVar1 = TRUE; + if (((((DAT_GameState::instance.playerDataArray[playerID].marketplace.id != 0) || + (DAT_BuildingsState::instance.buildingCosts[0x1a].requiredWood <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) || + (0 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)) && + (((DAT_GameState::instance.playerDataArray[playerID].granary.id != 0 || + (DAT_BuildingsState::instance.buildingCosts[0x13].requiredWood <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) || + (1 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)))) && + (((0 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] || + (25 < DAT_GameState::instance.playerDataArray[playerID].popularity)) || + (0 < DAT_GameState::instance.playerDataArray[playerID].totalFood)))) { + BVar1 = FALSE; + } + return BVar1; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp new file mode 100644 index 000000000..4895c8e2b --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Random/RNG.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0110 + void AICState::setAttackCoordinationLevel(int playerID) + { + int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType != AITA_NULL) { + int _willingnessPercentage = (int)this->DAT_AICArray[_aiType - 1].AttCoordinationPreference + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; + if (90 < _willingnessPercentage) { + _willingnessPercentage = 90; + } + int _rng = (int)SEC_RNG::instance.currentNumber2; + MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + if (_rng % 100 < _willingnessPercentage / 2) { + DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = 2; + return; + } + DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = (uint)(_rng % 100 < _willingnessPercentage); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp new file mode 100644 index 000000000..172e3b81c --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDFD0 + void AICState::setAttackPrimeInfo(int playerID, int attackedPlayerID) + { + int _tile = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile; + DAT_TroopValueState::instance.attackInfo.startCon = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; + DAT_TroopValueState::instance.attackInfo.startZone = (int)(char)DAT_TileMapState::instance.AIZoneLayer[_tile]; + DAT_TroopValueState::instance.attackInfo.zoneSize = DAT_PathFindingState::instance.zoneSizesArray[(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]]; + DAT_TroopValueState::instance.attackInfo.unknownOne_0x20f90 = 1; + DAT_TroopValueState::instance.attackInfo.keepCon = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry]; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp index 5e81a2a99..5e876dac7 100644 --- a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp +++ b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp @@ -10,20 +10,20 @@ namespace AI { int AICState::setNextFarmTypeToBuild(PlayerID playerID) { - int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + unsigned int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (_aiType == AITA_NULL) { return 0; } + _aiType += -1; int* _ptrAiFarmIndex = &DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex; *_ptrAiFarmIndex = *_ptrAiFarmIndex + 1; - if (7 < DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex) { + if (8 <= DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex) { DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; } - if ((&this->DAT_AICArray[_aiType - 1].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] - == 0) { + if ((&this->DAT_AICArray[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] == 0) { DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; } - return (&this->DAT_AICArray[_aiType - 1].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + return (&this->DAT_AICArray[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; } } } diff --git a/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp b/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp new file mode 100644 index 000000000..01f0675d3 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Game/GameCore.func.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1090 + void AICState::setSomeTimeToNowIfInIngameMenu() + { + BOOLEnum BVar1 = MACRO_CALL_MEMBER(Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)(); + if (BVar1 != FALSE) { + this->DAT_SomeTime = timeGetTime(); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp b/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp new file mode 100644 index 000000000..3d849bf26 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Game/GameCore.func.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1090 + void AICState::setTriggerForAITauntResponse() + { + BOOLEnum BVar1 = MACRO_CALL_MEMBER(Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)(); + if (BVar1 != FALSE) { + this->aiTauntResponseTimeWindow = timeGetTime(); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/yieldCowThrow.cpp b/src/OpenSHC/AI/AICState/yieldCowThrow.cpp new file mode 100644 index 000000000..42c6a14d2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/yieldCowThrow.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFF60 + BOOLEnum AICState::yieldCowThrow(int playerID) + { + int* _pCounter; + int const _ai = DAT_GameState::instance.playerDataArray[playerID].aiType; + if ((((_ai != AITA_NULL) && (DAT_GameState::instance.mapAndTime.noCowThrowing == 0)) && + (this->DAT_AICArray[_ai - 1].CowThrowInterval != 0)) && + ((0 < DAT_GameState::instance.playerDataArray[playerID].counter && + (_pCounter = &DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter, + *_pCounter = *_pCounter + 1, + (int)this->DAT_AICArray[_ai - 1].CowThrowInterval < DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter)))) { + DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter = 0; + return TRUE; + } + return FALSE; + } +} +} From 11e30f43f4f59ad606eb1e4e594b88ab004cb534 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Mon, 20 Jul 2026 01:14:16 +0200 Subject: [PATCH 003/242] processed ghidra changes --- src/OpenSHC/AI/AICState/aiFarmChoice.cpp | 2 +- src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp | 6 ++--- .../AI/AICState/aiShouldBuildIronMine.cpp | 2 +- .../AI/AICState/aiShouldBuildPitchrig.cpp | 2 +- .../AI/AICState/aiShouldBuildQuarry.cpp | 2 +- .../AI/AICState/aiShouldBuildWoodcutter.cpp | 22 +++++++++---------- .../AI/AICState/getAIBuildInterval.cpp | 2 +- .../getCurrentDesiredAttackRaidUnitCount.cpp | 16 +++++++++----- .../AI/AICState/getResourceRebuildDelay.cpp | 2 +- .../AICState/setAttackCoordinationLevel.cpp | 9 ++++---- .../setCurrentAttackRaidParameter.cpp | 2 +- .../AI/AICState/setCurrentAttackStrength.cpp | 2 +- src/OpenSHC/AI/AICState/setFoodBuyPlan.cpp | 20 ++++++++--------- .../AI/AICState/setNextFarmTypeToBuild.cpp | 4 ++-- .../setSomeTimeToNowIfInIngameMenu.cpp | 19 ---------------- .../AICState/setTriggerForAITauntResponse.cpp | 3 +-- src/OpenSHC/AI/AICState/yieldCowThrow.cpp | 13 ++++++----- 17 files changed, 57 insertions(+), 71 deletions(-) delete mode 100644 src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp diff --git a/src/OpenSHC/AI/AICState/aiFarmChoice.cpp b/src/OpenSHC/AI/AICState/aiFarmChoice.cpp index 82412eba9..ca1d6515f 100644 --- a/src/OpenSHC/AI/AICState/aiFarmChoice.cpp +++ b/src/OpenSHC/AI/AICState/aiFarmChoice.cpp @@ -16,7 +16,7 @@ namespace AI { } /* ugly because EAX is always 1 or higher */ - return (&this->DAT_AICArray[(aiType - 1)].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + return (&this->aics[(aiType - 1)].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; } } } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp index 25aca2c0d..29132eb9c 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp @@ -9,7 +9,7 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB220 - BOOLEnum AICState::aiShouldBuildFarm(PlayerID playerID) + BOOLEnum AICState::aiShouldBuildFarm(int playerID) { int const _playerID = playerID; unsigned int aiType = DAT_GameState::instance.playerDataArray[_playerID].aiType; @@ -22,11 +22,11 @@ namespace AI { if (_farmCount <= 0) { return TRUE; } - if (_farmCount >= (int)this->DAT_AICArray[aiType].maxFarms) { + if (_farmCount >= (int)this->aics[aiType].maxFarms) { return FALSE; } return DAT_GameState::instance.playerDataArray[_playerID].currentPopulation / _farmCount - >= (int)this->DAT_AICArray[aiType].populationPerFarm; + >= (int)this->aics[aiType].populationPerFarm; } } } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp index a9a7fde60..7ddf0e041 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp @@ -16,7 +16,7 @@ namespace AI { if (aiType == AITA_NULL) { return 0; } - AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + AICSpecification const* spec = &this->aics[aiType - 1]; if ((int)spec->populationPerIronmine <= 0) { return 0; } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp index 2ef6bf1f7..0227c21c7 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp @@ -16,7 +16,7 @@ namespace AI { if (aiType == AITA_NULL) { return 0; } - AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + AICSpecification const* spec = &this->aics[aiType - 1]; if ((int)spec->populationPerPitchrig <= 0) { return 0; } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp index c8f602ef5..ac4afab74 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp @@ -16,7 +16,7 @@ namespace AI { if (aiType == AITA_NULL) { return 0; } - AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + AICSpecification const* spec = &this->aics[aiType - 1]; if ((int)spec->populationPerQuarry <= 0) { return 0; } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp index ce4ba794a..221047ca9 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp @@ -11,37 +11,37 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB290 - uint AICState::aiShouldBuildWoodcutter(PlayerID playerID) + BOOLEnum AICState::aiShouldBuildWoodcutter(int playerID) { if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0) { - return 0; + return FALSE; } int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (aiType == AITA_NULL) { - return 0; + return FALSE; } aiType -= 1; - // AICSpecification const* spec = &this->DAT_AICArray[aiType]; - if ((int)this->DAT_AICArray[aiType].populationPerWoodcutter <= 0) { - return 0; + // AICSpecification const* spec = &this->aics[aiType]; + if ((int)this->aics[aiType].populationPerWoodcutter <= 0) { + return FALSE; } int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT, 1); if (iVar3 <= 0) { iVar3 = 1; } else { - if (iVar3 >= (int)this->DAT_AICArray[aiType].maxWoodcutters) { - return 0; + if (iVar3 >= (int)this->aics[aiType].maxWoodcutters) { + return FALSE; } if ((6 <= iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 90)) { - return 0; + return FALSE; } if ((3 <= iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 30)) { - return 0; + return FALSE; } } return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / iVar3 - >= (int)this->DAT_AICArray[aiType].populationPerWoodcutter; + >= (int)this->aics[aiType].populationPerWoodcutter; } } } diff --git a/src/OpenSHC/AI/AICState/getAIBuildInterval.cpp b/src/OpenSHC/AI/AICState/getAIBuildInterval.cpp index d3ed4a5e8..8c35a40a5 100644 --- a/src/OpenSHC/AI/AICState/getAIBuildInterval.cpp +++ b/src/OpenSHC/AI/AICState/getAIBuildInterval.cpp @@ -15,7 +15,7 @@ namespace AI { return 0; } - return this->DAT_AICArray[(aiType - 1)].buildInterval; + return this->aics[(aiType - 1)].buildInterval; } } } diff --git a/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp b/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp index 8be83b087..b36972206 100644 --- a/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp +++ b/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp @@ -1,10 +1,9 @@ #include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Game/GameMode2.hpp" #include "OpenSHC/Game/TrailType.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { @@ -12,11 +11,16 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D12A0 int AICState::getCurrentDesiredAttackRaidUnitCount(int aiType, int playerID) { - if (((DAT_GameCore::instance.gameMode_2 == Game::GM_SKIRMISH_AND_MULTIPLAYER) && - (DAT_GameCore::instance.isSkirmishTrail == TRUE)) && (DAT_GameCore::instance.currentTrailType == Game::TT_EXTREME)) { - return (int)((DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + this->DAT_AICArray[aiType].RaidUnitsBase) * 4) / 3; + if (((DAT_GameCore::instance.gameMode_2 == Game::GM_SKIRMISH_AND_MULTIPLAYER) + && (DAT_GameCore::instance.isSkirmishTrail == TRUE)) + && (DAT_GameCore::instance.currentTrailType == Game::TT_EXTREME)) { + return (int)((DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + + this->aics[aiType].RaidUnitsBase) + * 4) + / 3; } - return DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + this->DAT_AICArray[aiType].RaidUnitsBase; + return DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + + this->aics[aiType].RaidUnitsBase; } } } diff --git a/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp b/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp index 9d8493888..d20a9e2f9 100644 --- a/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp +++ b/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp @@ -15,7 +15,7 @@ namespace AI { return 0; } - return this->DAT_AICArray[(aiType - 1)].resourceRebuildDelay; + return this->aics[(aiType - 1)].resourceRebuildDelay; } } } diff --git a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp index 4895c8e2b..2a27d6607 100644 --- a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp +++ b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp @@ -1,8 +1,7 @@ +#include "OpenSHC/Random/RNG.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" -#include "OpenSHC/Random/RNG.func.hpp" - #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/SEC_RNG.hpp" @@ -14,7 +13,8 @@ namespace AI { { int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (_aiType != AITA_NULL) { - int _willingnessPercentage = (int)this->DAT_AICArray[_aiType - 1].AttCoordinationPreference + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; + int _willingnessPercentage = (int)this->aics[_aiType - 1].AttCoordinationPreference + + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; if (90 < _willingnessPercentage) { _willingnessPercentage = 90; } @@ -24,7 +24,8 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = 2; return; } - DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = (uint)(_rng % 100 < _willingnessPercentage); + DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel + = (uint)(_rng % 100 < _willingnessPercentage); } } } diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp index 92afcf357..21e9aeba4 100644 --- a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp +++ b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp @@ -15,7 +15,7 @@ namespace AI { if (_aiType != AITA_NULL) { int _rng = (int)SEC_RNG::instance.currentNumber2; MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - AICSpecification const* spec = &this->DAT_AICArray[_aiType - 1]; + AICSpecification const* spec = &this->aics[_aiType - 1]; int _gold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; int _raidUnitsRandom = (int)spec->RaidUnitsRandom; if (_gold < 1000) { diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp index 53cc9576f..a762c3c96 100644 --- a/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp +++ b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp @@ -15,7 +15,7 @@ namespace AI { if (_aiType != AITA_NULL) { int _randomNumber = (int)SEC_RNG::instance.currentNumber2; MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - int _attForceRandom = (int)this->DAT_AICArray[_aiType - 1].AttForceRandom; + int _attForceRandom = (int)this->aics[_aiType - 1].AttForceRandom; int* _attackWave = &DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; *_attackWave = *_attackWave + 1; int _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; diff --git a/src/OpenSHC/AI/AICState/setFoodBuyPlan.cpp b/src/OpenSHC/AI/AICState/setFoodBuyPlan.cpp index c1221fa89..981ad02d9 100644 --- a/src/OpenSHC/AI/AICState/setFoodBuyPlan.cpp +++ b/src/OpenSHC/AI/AICState/setFoodBuyPlan.cpp @@ -29,39 +29,39 @@ namespace AI { // Check each food type and queue purchase if current stock is below minimum // Apples: special handling with >= 0 check (allows -1 to disable) - int const minimumApples = this->DAT_AICArray[aiConfigIndex].minimumApples; + int const minimumApples = this->aics[aiConfigIndex].minimumApples; int* currentResources = DAT_GameState::ptr->playerDataArray[playerID].currentResources; if (minimumApples >= 0 && currentResources[ResourceType::RT_APPLE] < minimumApples) { DAT_GameState::ptr->playerDataArray[playerID].resourcesToAcquireArray[ResourceType::RT_APPLE] - = this->DAT_AICArray[aiConfigIndex].tradeAmountFood; + = this->aics[aiConfigIndex].tradeAmountFood; } // Cheese: standard check with > 0 - int const minimumCheese = this->DAT_AICArray[aiConfigIndex].minimumCheese; + int const minimumCheese = this->aics[aiConfigIndex].minimumCheese; if (minimumCheese > 0 && currentResources[ResourceType::RT_CHEESE] < minimumCheese) { DAT_GameState::ptr->playerDataArray[playerID].resourcesToAcquireArray[ResourceType::RT_CHEESE] - = this->DAT_AICArray[aiConfigIndex].tradeAmountFood; + = this->aics[aiConfigIndex].tradeAmountFood; } // Bread: standard check with > 0 - int const minimumBread = this->DAT_AICArray[aiConfigIndex].minimumBread; + int const minimumBread = this->aics[aiConfigIndex].minimumBread; if (minimumBread > 0 && currentResources[ResourceType::RT_BREAD] < minimumBread) { DAT_GameState::ptr->playerDataArray[playerID].resourcesToAcquireArray[ResourceType::RT_BREAD] - = this->DAT_AICArray[aiConfigIndex].tradeAmountFood; + = this->aics[aiConfigIndex].tradeAmountFood; } // Wheat: standard check with > 0 - int const minimumWheat = this->DAT_AICArray[aiConfigIndex].minimumWheat; + int const minimumWheat = this->aics[aiConfigIndex].minimumWheat; if (minimumWheat > 0 && currentResources[ResourceType::RT_WHEAT] < minimumWheat) { DAT_GameState::ptr->playerDataArray[playerID].resourcesToAcquireArray[ResourceType::RT_WHEAT] - = this->DAT_AICArray[aiConfigIndex].tradeAmountFood; + = this->aics[aiConfigIndex].tradeAmountFood; } // Hops: standard check with > 0 - int const minimumHop = this->DAT_AICArray[aiConfigIndex].minimumHop; + int const minimumHop = this->aics[aiConfigIndex].minimumHop; if (minimumHop > 0 && currentResources[ResourceType::RT_HOPS] < minimumHop) { DAT_GameState::ptr->playerDataArray[playerID].resourcesToAcquireArray[ResourceType::RT_HOPS] - = this->DAT_AICArray[aiConfigIndex].tradeAmountFood; + = this->aics[aiConfigIndex].tradeAmountFood; } } } diff --git a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp index 5e876dac7..8f0706f81 100644 --- a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp +++ b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp @@ -20,10 +20,10 @@ namespace AI { if (8 <= DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex) { DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; } - if ((&this->DAT_AICArray[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] == 0) { + if ((&this->aics[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] == 0) { DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; } - return (&this->DAT_AICArray[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + return (&this->aics[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; } } } diff --git a/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp b/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp deleted file mode 100644 index 01f0675d3..000000000 --- a/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "OpenSHC/AI/AICState.hpp" - -#include "OpenSHC/Game/GameCore.func.hpp" - -#include "OpenSHC/Globals/DAT_GameCore.hpp" - -namespace OpenSHC { -namespace AI { - - // FUNCTION: STRONGHOLDCRUSADER 0x004D1090 - void AICState::setSomeTimeToNowIfInIngameMenu() - { - BOOLEnum BVar1 = MACRO_CALL_MEMBER(Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)(); - if (BVar1 != FALSE) { - this->DAT_SomeTime = timeGetTime(); - } - } -} -} diff --git a/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp b/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp index 3d849bf26..1b9dcf37b 100644 --- a/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp +++ b/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp @@ -1,6 +1,5 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Game/GameCore.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameCore.hpp" diff --git a/src/OpenSHC/AI/AICState/yieldCowThrow.cpp b/src/OpenSHC/AI/AICState/yieldCowThrow.cpp index 42c6a14d2..16c993e2f 100644 --- a/src/OpenSHC/AI/AICState/yieldCowThrow.cpp +++ b/src/OpenSHC/AI/AICState/yieldCowThrow.cpp @@ -11,12 +11,13 @@ namespace AI { { int* _pCounter; int const _ai = DAT_GameState::instance.playerDataArray[playerID].aiType; - if ((((_ai != AITA_NULL) && (DAT_GameState::instance.mapAndTime.noCowThrowing == 0)) && - (this->DAT_AICArray[_ai - 1].CowThrowInterval != 0)) && - ((0 < DAT_GameState::instance.playerDataArray[playerID].counter && - (_pCounter = &DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter, - *_pCounter = *_pCounter + 1, - (int)this->DAT_AICArray[_ai - 1].CowThrowInterval < DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter)))) { + if ((((_ai != AITA_NULL) && (DAT_GameState::instance.mapAndTime.noCowThrowing == 0)) + && (this->aics[_ai - 1].CowThrowInterval != 0)) + && ((0 < DAT_GameState::instance.playerDataArray[playerID].counter + && (_pCounter = &DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter, + *_pCounter = *_pCounter + 1, + (int)this->aics[_ai - 1].CowThrowInterval + < DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter)))) { DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter = 0; return TRUE; } From dfbd12a078c7199e08cbf9741617382ed3cafea5 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Mon, 20 Jul 2026 01:40:55 +0200 Subject: [PATCH 004/242] more rough unchecked reimplementations --- .../aiCommandTribe11StandGroundToGate.cpp | 31 ++++++++++ .../aiCommandTribe13DefensiveWave.cpp | 28 +++++++++ .../AICState/aiCommandWallAssaultTribes.cpp | 37 ++++++++++++ .../AICState/hasNoTroopsOrAllAreDiggers.cpp | 57 +++++++++++++++++++ .../AICState/ifHasTribe0SendUnitsToKeep.cpp | 19 +++++++ .../AI/AICState/makeOutpostTribesAttack.cpp | 29 ++++++++++ .../sendAITribe_0xf_toAttackPatrol.cpp | 30 ++++++++++ .../AICState/sendTribeAtOffset1ToCampfire.cpp | 19 +++++++ src/OpenSHC/AI/AICState/sendTribeToAttack.cpp | 28 +++++++++ .../AI/AICState/sendUnitsToCampfire.cpp | 21 +++++++ src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp | 21 +++++++ ...htTribe0xc0TribesToAggressiveAndAttack.cpp | 37 ++++++++++++ ...x11ToAggressiveAndAttackIfConditionMet.cpp | 30 ++++++++++ .../setTribe0xCtoAggressiveAndAttack.cpp | 28 +++++++++ .../setTribe0xbToAggressiveAndAttack.cpp | 28 +++++++++ .../AICState/shouldDestroyWoodCutterUnk.cpp | 46 +++++++++++++++ ...rketArmoryGranaryBarracksMercenarypost.cpp | 24 ++++++++ 17 files changed, 513 insertions(+) create mode 100644 src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp create mode 100644 src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp create mode 100644 src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp create mode 100644 src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp create mode 100644 src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp create mode 100644 src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp create mode 100644 src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp create mode 100644 src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp create mode 100644 src/OpenSHC/AI/AICState/sendTribeToAttack.cpp create mode 100644 src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp create mode 100644 src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp create mode 100644 src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp create mode 100644 src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp create mode 100644 src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp create mode 100644 src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp new file mode 100644 index 000000000..6057d9080 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF470 + void AICState::aiCommandTribe11StandGroundToGate(int playerID) + { + int iVar1; + int iVar2; + if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], iVar2 != 0)) && + (DAT_TribesState::instance.tribes[iVar2].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb])) && + (DAT_TribesState::instance.tribes[iVar2].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[iVar2].unitStance = Map::Units::Behavior::USE_STAND_GROUND; + iVar1 = MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)(iVar2); + if (iVar1 == 0) { + MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)(iVar2); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp new file mode 100644 index 000000000..5f9524b07 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF270 + void AICState::aiCommandTribe13DefensiveWave(int param_1) + { + int tribeID; + if ((DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) && + (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xd], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xd]) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f4); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp new file mode 100644 index 000000000..55c81532f --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp @@ -0,0 +1,37 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF660 + void AICState::aiCommandWallAssaultTribes(int param_1) + { + int tribeID; + int iVar1; + short* psVar2; + if (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) { + iVar1 = 0; + psVar2 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + 0xbe; + do { + tribeID = (int)*psVar2; + if (((tribeID != 0) && + (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar1 + 0xbe])) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + } + iVar1 = iVar1 + 1; + psVar2 = psVar2 + 1; + } while (iVar1 < 2); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp new file mode 100644 index 000000000..b4f0895ac --- /dev/null +++ b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp @@ -0,0 +1,57 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFFD0 + BOOLEnum AICState::hasNoTroopsOrAllAreDiggers(int playerID) + { + int _totalBackup; + int _totalBackup2; + int _total1; + int _totalTroops; + int _halfOfDiggingTroops; + int _totalBackupLate; + int _totalBackupLate2; + + _total1 = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + + DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops; + _halfOfDiggingTroops = 0; + if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState == 6) { + if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 17) { + _totalBackup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + } + else { + _totalBackupLate = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + _totalBackup = (int)(_totalBackupLate + (_totalBackupLate >> 0x1f & 7U)) >> 3; + } + _totalTroops = _total1 + DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops + + _totalBackup + + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + } + else { + _halfOfDiggingTroops = DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops / 2; + if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 13) { + _totalBackup2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + } + else { + _totalBackupLate2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + _totalBackup2 = (int)(_totalBackupLate2 + (_totalBackupLate2 >> 0x1f & 7U)) >> 3; + } + _totalTroops = _total1 + _totalBackup2 + + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + } + if ((1 < _totalTroops) && ((4 < _totalTroops || (_halfOfDiggingTroops <= _totalTroops * 2)))) { + return FALSE; + } + return TRUE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp new file mode 100644 index 000000000..fb68e2842 --- /dev/null +++ b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2830 + void AICState::ifHasTribe0SendUnitsToKeep(int playerID) + { + int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0]; + if ((0 < tribeID) && + (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0])) { + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp new file mode 100644 index 000000000..8168e916d --- /dev/null +++ b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3960 + void AICState::makeOutpostTribesAttack() + { + uint _tribeID; + int _countDown; + short* _tribeIDs; + int* _tribeUIDs; + _tribeUIDs = this->tribeUIDArray; + _tribeIDs = this->tribeIDArray; + _countDown = 1000; + do { + _tribeID = (uint)*_tribeIDs; + if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid == *_tribeUIDs)) { + MACRO_CALL_MEMBER(AICState_Func::decideOnTribeAttackLocation, this)(_tribeID); + } + _tribeIDs = _tribeIDs + 1; + _tribeUIDs = _tribeUIDs + 1; + _countDown = _countDown + -1; + } while (_countDown != 0); + } +} +} diff --git a/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp b/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp new file mode 100644 index 000000000..e39cd8bcd --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp @@ -0,0 +1,30 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF4F0 + void AICState::sendAITribe_0xf_toAttackPatrol(int playerID) + { + int _tribeID; + /* bug: only sends 0xf, while 0xf+1 could also be send if defined by 'AIC: AttUnitPatrolGroupsCount' */ + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (_tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xf], _tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xf]) && + (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::sendAttackingPatrolTribeToComputedDestination, DAT_TroopValueState::ptr)(_tribeID); + return; + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp new file mode 100644 index 000000000..d54d90ecd --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2870 + void AICState::sendTribeAtOffset1ToCampfire(int playerID) + { + int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[1]; + if ((0 < _tribeID) && + (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[1])) { + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp b/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp new file mode 100644 index 000000000..70816a822 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF750 + void AICState::sendTribeToAttack(int playerID) + { + int tribeID; + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbd], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbd]) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3fb); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp b/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp new file mode 100644 index 000000000..3438b8701 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD110 + void AICState::sendUnitsToCampfire(int tribeID, int playerID) + { + if (0 < DAT_GameState::instance.playerDataArray[playerID].campground.id) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, DAT_GameState::instance.playerDataArray[playerID].campground.xEntry, DAT_GameState::instance.playerDataArray[playerID].campground.yEntry, 0); + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp new file mode 100644 index 000000000..79a4d2d29 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD0C0 + void AICState::sendUnitsToKeep(undefined4 tribeID, int playerID) + { + int iVar1 = DAT_GameState::instance.playerDataArray[playerID].keep.id; + if (0 < iVar1) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, (int)(short)DAT_BuildingsState::instance.buildings[iVar1].x + 3, (int)(short)DAT_BuildingsState::instance.buildings[iVar1].y + 4, 0); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp new file mode 100644 index 000000000..16bce6ec3 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp @@ -0,0 +1,37 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF5E0 + void AICState::setEightTribe0xc0TribesToAggressiveAndAttack(int playerID) + { + int _tribeID; + int iVar1; + short* psVar2; + if (DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) { + iVar1 = 0; + psVar2 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xc0; + do { + _tribeID = (int)*psVar2; + if (((_tribeID != 0) && + (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar1 + 0xc0])) && + (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(_tribeID, Map::Units::STBT_0x3f2); + } + iVar1 = iVar1 + 1; + psVar2 = psVar2 + 1; + } while (iVar1 < 8); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp b/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp new file mode 100644 index 000000000..c92c7b451 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp @@ -0,0 +1,30 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF560 + void AICState::setTribe0x11ToAggressiveAndAttackIfConditionMet(int param_1) + { + int tribeID; + if (((0 < *(int*)((int)DAT_TroopValueState::instance.attackInfo.moatValuesArray + param_1 * 0x177bc + -4)) && + (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL)) && + (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0x11], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0x11]) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f7); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp new file mode 100644 index 000000000..45520c9d5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF400 + void AICState::setTribe0xCtoAggressiveAndAttack(int playerID) + { + int tribeID; + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xc], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xc]) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp new file mode 100644 index 000000000..259138f45 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF6E0 + void AICState::setTribe0xbToAggressiveAndAttack(int playerID) + { + int tribeID; + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb]) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp new file mode 100644 index 000000000..68feb468c --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp @@ -0,0 +1,46 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/AI/AIVState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_AIVState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB890 + BOOLEnum AICState::shouldDestroyWoodCutterUnk(int playerID) + { + int _hut; + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return FALSE; + } + if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 1) { + _hut = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT); + } + else { + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] < 0x15) { + return FALSE; + } + if (DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 2) { + return FALSE; + } + if (DAT_GameState::instance.playerDataArray[playerID].someCount10 < 25) { + return FALSE; + } + _hut = DAT_GameState::instance.playerDataArray[playerID].someCount11; + } + if (_hut == 0) { + return FALSE; + } + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)((int)(short)DAT_BuildingsState::instance.buildings[_hut].x, (int)(short)DAT_BuildingsState::instance.buildings[_hut].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(_hut, playerID, 50); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hut); + return TRUE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp new file mode 100644 index 000000000..3a98835e1 --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB9F0 + BOOLEnum AICState::shouldNotBuildMarketArmoryGranaryBarracksMercenarypost(int playerID, Commands::CommandBuildingType param_2) + { + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) { + if ((0 < DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker) && (param_2 != Commands::CBT_MARKETPLACE)) { + return param_2 != Commands::CBT_GRANARY; + } + } + else if ((((param_2 != Commands::CBT_MARKETPLACE) && (param_2 != Commands::CBT_MERCENARYPOST)) && (param_2 != Commands::CBT_BARRACKS)) && (param_2 != Commands::CBT_ARMORY)) { + return param_2 != Commands::CBT_GRANARY; + } + return FALSE; + } +} +} From 3c1a7c4b08c8b4fc68b5c32f6aa91d98030c83eb Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 20 Jul 2026 15:34:56 +0200 Subject: [PATCH 005/242] batch 4 unpolished --- .../AI/AICState/Constructor_AICState.cpp | 14 +++ src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp | 26 +++++ .../addUnitToSmallestBehaviourTypeTribe.cpp | 88 +++++++++++++++ .../AICState/addUnitToSmallestPatrolTribe.cpp | 25 +++++ .../AI/AICState/addUnitsToTribe166.cpp | 35 ++++++ .../AICState/aiAddUnitToMoatDiggerTribe.cpp | 30 ++++++ .../AI/AICState/aiAssignMoatDiggers.cpp | 48 +++++++++ .../AICState/aiAssignUnitToDefensiveTribe.cpp | 26 +++++ .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 80 ++++++++++++++ .../AICState/aiReassignTunnelersToTribe.cpp | 35 ++++++ .../AICState/aiRecruitEngineerForOilDuty.cpp | 61 +++++++++++ .../AI/AICState/aiRecruitEngineers.cpp | 32 ++++++ .../assignRequiredIdleEngineersToNewTribe.cpp | 45 ++++++++ .../AI/AICState/assignUnitToATribe.cpp | 49 +++++++++ .../canNavigateUnitsFromTileToTargetTile.cpp | 24 +++++ .../AI/AICState/createTribeForUnitType.cpp | 26 +++++ .../AICState/destroyAnyBuildingInCategory.cpp | 102 ++++++++++++++++++ .../AI/AICState/destroyBuildingIfNoWorker.cpp | 40 +++++++ src/OpenSHC/AI/AICState/digNearestMoat.cpp | 44 ++++++++ .../AI/AICState/getDefensiveTribeForUnit.cpp | 80 ++++++++++++++ ...qualThanMinimumGoodsRequiredAfterTrade.cpp | 24 +++++ .../AI/AICState/playAnger1BikFromPlayer.cpp | 32 ++++++ .../playAnger2BikFromPlayerToPlayer.cpp | 29 +++++ .../playFriendlyVictoryBikFromPlayer.cpp | 22 ++++ .../playGoodsNotSentBikFromPlayer.cpp | 22 ++++ .../playGoodsRequestBikFromPlayerToPlayer.cpp | 23 ++++ .../playGoodsSentBikFromPlayerToPlayer.cpp | 23 ++++ .../AI/AICState/playJokeBikFromAIToHuman.cpp | 21 ++++ .../AI/AICState/playNervous1BikFromPlayer.cpp | 23 ++++ .../AI/AICState/playNervous2BikFromPlayer.cpp | 28 +++++ .../AI/AICState/playNoHelpBikFromPlayer.cpp | 22 ++++ ...yerKilledBiksFromKilledAndKillerPlayer.cpp | 56 ++++++++++ .../AICState/playRequestHelpBikFromPlayer.cpp | 27 +++++ ...playTauntToAttackedPlayerBikFromPlayer.cpp | 33 ++++++ .../AICState/playTeamWinningBikFromPlayer.cpp | 22 ++++ .../playThanksBikFromPlayerToPlayer.cpp | 32 ++++++ .../playVictory2BikFromPlayerToPlayer.cpp | 31 ++++++ .../AI/AICState/recreateEngineersTribe.cpp | 22 ++++ .../AI/AICState/smallestTribeOfUnitType.cpp | 60 +++++++++++ .../AICState/syncBehaviourType7UnitTribes.cpp | 35 ++++++ .../AI/AICState/teamIsWeakRelativeToEnemy.cpp | 65 +++++++++++ src/OpenSHC/AI/AICState/wipeAICMemory.cpp | 22 ++++ 42 files changed, 1584 insertions(+) create mode 100644 src/OpenSHC/AI/AICState/Constructor_AICState.cpp create mode 100644 src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp create mode 100644 src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp create mode 100644 src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp create mode 100644 src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp create mode 100644 src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/assignUnitToATribe.cpp create mode 100644 src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp create mode 100644 src/OpenSHC/AI/AICState/createTribeForUnitType.cpp create mode 100644 src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp create mode 100644 src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp create mode 100644 src/OpenSHC/AI/AICState/digNearestMoat.cpp create mode 100644 src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp create mode 100644 src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp create mode 100644 src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp create mode 100644 src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp create mode 100644 src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp create mode 100644 src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp create mode 100644 src/OpenSHC/AI/AICState/wipeAICMemory.cpp diff --git a/src/OpenSHC/AI/AICState/Constructor_AICState.cpp b/src/OpenSHC/AI/AICState/Constructor_AICState.cpp new file mode 100644 index 000000000..104d8e012 --- /dev/null +++ b/src/OpenSHC/AI/AICState/Constructor_AICState.cpp @@ -0,0 +1,14 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3940 + AICState* AICState::Constructor_AICState() + { + MACRO_CALL_MEMBER(AICState_Func::setInitialAIC, this)(); + this->aiTauntResponseTimeWindow = 0; + return this; + } +} +} diff --git a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp new file mode 100644 index 000000000..2dcf5a1a0 --- /dev/null +++ b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D27E0 + void AICState::addUnitToItsTribe(int unitID, int aiUnitBehaviourType) + { + int iVar1 = (int)DAT_UnitsState::instance.units[unitID].owner; + if (DAT_GameState::instance.playerDataArray[iVar1].aiType != AITA_NULL) { + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = (short)aiUnitBehaviourType; + iVar1 = MACRO_CALL_MEMBER(AICState_Func::addUnitToSmallestBehaviourTypeTribe, this)(iVar1, unitID, aiUnitBehaviourType); + if (iVar1 != 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp new file mode 100644 index 000000000..9c0cb83fb --- /dev/null +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp @@ -0,0 +1,88 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CCD20 + int AICState::addUnitToSmallestBehaviourTypeTribe(undefined4 playerID, undefined4 param_2, undefined4 aiUnitBehaviourType) + { + int _playerID = (int)playerID; + int AVar1 = DAT_GameState::instance.playerDataArray[_playerID].aiType; + if (AVar1 == AITA_NULL) { + return 0; + } + int _tribeTypeOffset = DAT_SkirmishDefinedData::instance.DAT_AIUnitBehaviourTypeMapping[(int)aiUnitBehaviourType + -10]; + int _smallestTribe = 0; + int _smallestTribeOffset = 0; + short _smallestTribeSize = 1000; + dword _groupsCount; + switch (_tribeTypeOffset) { + case 0xf: + _groupsCount = this->aics[AVar1 - 1].AttUnitPatrolGroupsCount; + break; + default: + goto switchD_004ccd78_caseD_10; + case 0xba: + _groupsCount = this->aics[AVar1 - 1].AttUnitBackupGroupsCount; + break; + case 0xbe: + _groupsCount = this->aics[AVar1 - 1].AttUnitSiegeDefGroupsCount; + break; + case 0xc0: + _groupsCount = this->aics[AVar1 - 1].AttMainGroupsCount; + } + int _selectedTribe; + int _selectedSlot; + if (((int)_groupsCount < 1) || (_groupsCount == 1)) { +switchD_004ccd78_caseD_10: + int _tribeID_groupsCount1 = (int)DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_tribeTypeOffset]; + if ((_tribeID_groupsCount1 != 0) && + (DAT_TribesState::instance.tribes[_tribeID_groupsCount1].uid == DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { + return _tribeID_groupsCount1; + } + _selectedTribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); + _selectedSlot = _tribeTypeOffset; + } + else { + int _maxOffset = _groupsCount + _tribeTypeOffset; + _selectedTribe = 0; + _selectedSlot = 0; + short* _pTribeIDs = DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs + _tribeTypeOffset; + if (_tribeTypeOffset < _maxOffset) { + do { + int _tribeID_2 = (int)*_pTribeIDs; + if ((_tribeID_2 == 0) || + (DAT_TribesState::instance.tribes[_tribeID_2].uid != DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { + _selectedTribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); + _selectedSlot = _tribeTypeOffset; + break; + } + short _tribeSize = DAT_TribesState::instance.tribes[_tribeID_2].size; + if (_tribeSize < _smallestTribeSize) { + _smallestTribeOffset = _tribeTypeOffset; + _smallestTribe = _tribeID_2; + _smallestTribeSize = _tribeSize; + } + _pTribeIDs = _pTribeIDs + 1; + _tribeTypeOffset = _tribeTypeOffset + 1; + _selectedTribe = _smallestTribe; + _selectedSlot = _smallestTribeOffset; + } while (_tribeTypeOffset < _maxOffset); + } + } + if (0 < _selectedTribe) { + DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_selectedSlot] = (short)_selectedTribe; + DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_selectedSlot] = DAT_TribesState::instance.tribes[_selectedTribe].uid; + return _selectedTribe; + } + return 0; + } +} +} diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp new file mode 100644 index 000000000..ef1b52ec1 --- /dev/null +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp @@ -0,0 +1,25 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2730 + void AICState::addUnitToSmallestPatrolTribe(int unitID) + { + int iVar1 = (int)DAT_UnitsState::instance.units[unitID].owner; + int _aiType = DAT_GameState::instance.playerDataArray[iVar1].aiType; + if (_aiType != AITA_NULL) { + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 4; + iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::getSmallestPatrolTribe, DAT_TribesState::ptr)(iVar1, (int)this->aics[_aiType - 1].OuterPatrolGroupsCount); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp b/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp new file mode 100644 index 000000000..7eedbe481 --- /dev/null +++ b/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp @@ -0,0 +1,35 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC720 + void AICState::addUnitsToTribe166(int playerID) + { + int tribeID; + uint unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + Map::Units::Unit* pUVar1 = &DAT_UnitsState::instance.units[1]; + do { + if ((((pUVar1->owner == playerID) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) && + (pUVar1->dying == 0)) && (pUVar1->aiUnitBehaviourType == 6)) { + tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; + if (pUVar1->tribeID != tribeID) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)pUVar1->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + } + } + unitID = unitID + 1; + pUVar1 = pUVar1 + 1; + } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp new file mode 100644 index 000000000..857e55933 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp @@ -0,0 +1,30 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC840 + void AICState::aiAddUnitToMoatDiggerTribe(int unitID) + { + int _owner = (int)DAT_UnitsState::instance.units[unitID].owner; + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 5; + int _tribe = (int)DAT_GameState::instance.playerDataArray[_owner].aiTribeIDs[10]; + if ((_tribe == 0) || + (DAT_TribesState::instance.tribes[_tribe].uid != DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10])) { + _tribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_owner); + int _uid = DAT_TribesState::instance.tribes[_tribe].uid; + DAT_GameState::instance.playerDataArray[_owner].aiTribeIDs[10] = (short)_tribe; + DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10] = _uid; + } + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribe); + DAT_TribesState::instance.tribes[_tribe].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp new file mode 100644 index 000000000..037a2f2fe --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp @@ -0,0 +1,48 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3F70 + void AICState::aiAssignMoatDiggers(int playerID) + { + int _unitID; + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + Map::Units::UnitTypeShort _unitType; + if (((_aiType != AITA_NULL) && (0 < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType0)) && + (_unitID = 1, 1 < (int)DAT_UnitsState::instance.maxUnitCount)) { + Map::Units::Unit* _ptrUnit = &DAT_UnitsState::instance.units[1]; + do { + if ((((((_ptrUnit->logicalState != Map::Units::ULS_INVISIBLE) && (_ptrUnit->owner == playerID)) && + ((_ptrUnit->isSelectable_OR_matchTime != 0 && + ((_ptrUnit->aiUnitBehaviourType == 0 && (_ptrUnit->dying == 0)))))) && + (_unitType = _ptrUnit->unitType, _unitType != Map::Units::UT_LORD)) && + ((((_unitType != Map::Units::UT_E_ENGINEER && (_unitType != Map::Units::UT_TUNNELER)) && + (_unitType != Map::Units::UT_S_CATAPULT)) && + ((_unitType != Map::Units::UT_S_TREBUCHET && (_unitType != Map::Units::UT_S_MANGONEL)))))) && + (((_unitType != Map::Units::UT_S_TOWER && + ((_unitType != Map::Units::UT_S_BATTERINGRAM && (_unitType != Map::Units::UT_S_SHIELD)))) && + ((_unitType != Map::Units::UT_S_BALLISTA && (_unitType != Map::Units::UT_S_FBALLISTA)))))) { + if (((((int)this->aics[_aiType - 1].DefDiggingUnitMax == 0) || + (_unitType == Map::Units::UT_E_ARCHER)) || (_unitType == Map::Units::UT_E_XBOW)) || + (_ptrUnit->someUnitStat4 == 0)) { + MACRO_CALL_MEMBER(AICState_Func::assignUnitToATribe, this)(_unitID); + } + else { + MACRO_CALL_MEMBER(AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); + } + } + _unitID = _unitID + 1; + _ptrUnit = _ptrUnit + 1; + } while (_unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp new file mode 100644 index 000000000..22cda9ad7 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2790 + void AICState::aiAssignUnitToDefensiveTribe(int unitID) + { + int _playerID = (int)DAT_UnitsState::instance.units[unitID].owner; + if (DAT_GameState::instance.playerDataArray[_playerID].aiType != AITA_NULL) { + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 2; + int _tribeID = MACRO_CALL_MEMBER(AICState_Func::getDefensiveTribeForUnit, this)(_playerID, unitID); + if (_tribeID != 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp new file mode 100644 index 000000000..75dc1e348 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -0,0 +1,80 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D28B0 + void AICState::aiGiveOuterPatrolCommand(int playerID) + { + int* piVar1; + short sVar2; + int iVar3; + short* psVar4; + int _buildingID; + int _buildingID2; + int _tile; + BOOLEnum _canNavigate; + int _aicOffset; + int _tribeID; + int _index; + int _count; + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType != 0) { + _aicOffset = (_aiType + -1) * 0x2a4; + _count = (int)this->aics[_aiType - 1].OuterPatrolGroupsCount; + _index = 0; + if (((0 < _count) && + (piVar1 = &DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker, + *piVar1 = *piVar1 + 1, + (int)this->aics[_aiType - 1].OuterPatrolRallyDelay <= DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker)) && + (DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker = 0, 0 < _count)) { + psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; + do { + _tribeID = (int)*psVar4; + DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + if (((_tribeID != 0) && + (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0xaa])) && + ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0xb && + ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk < 0xb && + (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk < 0xb)))))) { + if (((int)this->aics[_aiType - 1].OuterPatrolGroupsMove == 0) || + (_buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)(playerID, _index), + _buildingID == 0)) { + _buildingID2 = MACRO_CALL_MEMBER(AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + if (_buildingID2 == 0) goto LAB_004d2a44; + _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryX + + DAT_ViewportRenderState::instance.translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryY].addXgetTile; + } + else { + _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + + DAT_ViewportRenderState::instance.translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryY].addXgetTile; + } + if (_tile != 0) { + sVar2 = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; + _canNavigate = MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(_tribeID, _tile); + if (_canNavigate == FALSE) { + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); + } + else { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(_tribeID, _tile - iVar3, (int)sVar2, 0); + } + } + } +LAB_004d2a44: + _index = _index + 1; + psVar4 = psVar4 + 1; + } while (_index < _count); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp new file mode 100644 index 000000000..640f619e3 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp @@ -0,0 +1,35 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D40B0 + void AICState::aiReassignTunnelersToTribe(int param_1) + { + uint unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + Map::Units::Unit* psVar1 = &DAT_UnitsState::instance.units[1]; + do { + if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == param_1)) && + (psVar1->dying == 0)) && + ((psVar1->unitType == Map::Units::UT_TUNNELER && (psVar1->aiUnitBehaviourType == 0xf)))) { + if (psVar1->tribeID != 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)psVar1->tribeID); + } + MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 0xf); + } + unitID = unitID + 1; + psVar1 = psVar1 + 1; + } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp new file mode 100644 index 000000000..7379a3ed6 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp @@ -0,0 +1,61 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/AI/Tribes/AITribeType.hpp" + +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2610 + void AICState::aiRecruitEngineerForOilDuty(int playerID) + { + BOOLEnum _hasTribes; + int _newTribe; + int _unitID; + int _amount; + int _oilSmelter; + int _buildingUID; + if (((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (_newTribe = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, + DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) && + (29 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf])) && + ((0 < _newTribe && (DAT_BuildingsState::instance.buildings[_newTribe].buildingType == Map::Buildings::BT_ENGINEERSGUILD)))) && + ((_oilSmelter = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id, 0 < _oilSmelter && + ((DAT_BuildingsState::instance.buildings[_oilSmelter].buildingType == Map::Buildings::BT_OILSMELTER && + (_amount = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1] + 1, 1 < _amount)))))) { + if ((DAT_BuildingsState::instance.buildings[_oilSmelter].resourcePitch < 1) && + (DAT_GameState::instance.playerDataArray[playerID].currentResources[7] < 1)) { + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[7] = 4; + return; + } + _hasTribes = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)(playerID, _amount, TRUE); + if (_hasTribes != FALSE) { + _newTribe = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)(playerID, _amount, FALSE); + _unitID = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)(Map::Units::UT_E_ENGINEER, DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, playerID, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(_unitID, _newTribe); + if (_unitID != 0) { + DAT_UnitsState::instance.units[_unitID].engineerRelatedUnk = 1; + DAT_TribesState::instance.tribes[_newTribe].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + _buildingUID = DAT_BuildingsState::instance.buildings[_oilSmelter].uid; + DAT_TribesState::instance.tribes[_newTribe].tribeType = Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_newTribe].tribeBehaviorType = Map::Units::STBT_0x41d; + MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(_newTribe, Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _oilSmelter, _buildingUID, 0); + } + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp b/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp new file mode 100644 index 000000000..7af062fb0 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp @@ -0,0 +1,32 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC520 + void AICState::aiRecruitEngineers(int playerID) + { + int recruitmentBuilding; + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if ((((_aiType != AITA_NULL) && + (DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired != FALSE)) && + (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) && + (((0x1d < (int)this->aics[_aiType - 1].recruitGoldThreshold + DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] && + (recruitmentBuilding = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, + 0 < recruitmentBuilding)) && + (DAT_BuildingsState::instance.buildings[recruitmentBuilding].buildingType == Map::Buildings::BT_ENGINEERSGUILD)))) { + MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)(Map::Units::UT_E_ENGINEER, recruitmentBuilding, playerID, 0); + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = FALSE; + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp new file mode 100644 index 000000000..aeb6e8986 --- /dev/null +++ b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp @@ -0,0 +1,45 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC5A0 + int AICState::assignRequiredIdleEngineersToNewTribe(int playerID, int count) + { + Map::Units::States::UnitStateShort UVar1; + int tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + uint unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + Map::Units::Unit* psVar2 = &DAT_UnitsState::instance.units[1]; + do { + if (count < 1) { + return tribeID; + } + if (((((psVar2->logicalState == Map::Units::ULS_NORMAL) && (psVar2->owner == playerID)) && + (psVar2->dying == 0)) && + ((psVar2->unitType == Map::Units::UT_E_ENGINEER && (psVar2->aiUnitBehaviourType != 0x16)))) && + ((psVar2->aiUnitBehaviourType != 10 && (psVar2->engineerRelatedUnk == 0))) && + (((UVar1 = (psVar2->state).generic, UVar1 == 0x69 || (UVar1 == 2)) || (UVar1 == Map::Units::States::US_IDLEUnk)))) { + if (psVar2->tribeID != 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)psVar2->tribeID); + } + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + count = count + -1; + } + unitID = unitID + 1; + psVar2 = psVar2 + 1; + } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + return tribeID; + } +} +} diff --git a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp new file mode 100644 index 000000000..383a4e51c --- /dev/null +++ b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp @@ -0,0 +1,49 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2660 + void AICState::assignUnitToATribe(int unitID) + { + short* _unitTypeIndex; + int _isOfType; + int _tribeID; + int _playerID = (int)DAT_UnitsState::instance.units[unitID].owner; + if (DAT_GameState::instance.playerDataArray[_playerID].aiType != AITA_NULL) { + int iVar1; + if ((DAT_GameState::instance.playerDataArray[_playerID].aivCurrentPauseIndex == 1) && + (0 < DAT_GameState::instance.playerDataArray[_playerID].aivPauses[1])) { + iVar1 = 1; + } + else { + iVar1 = 0; + } + _unitTypeIndex = (short*)MACRO_CALL(Global_Func::GetUnitTypeIndexForUnitID)(unitID, iVar1); + int _tribeSize = DAT_GameState::instance.playerDataArray[_playerID].aivUnitLocationSlotLocationCount[(int)_unitTypeIndex]; + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 1; + if (_tribeSize < 1) { + _isOfType = MACRO_CALL_MEMBER(AICState_Func::unitIDIsRangedOrArmored, this)(unitID); + if (_isOfType != 0) { + _tribeID = MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(_playerID, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + return; + } + _tribeID = MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(_playerID, 1); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + return; + } + _tribeID = MACRO_CALL_MEMBER(AICState_Func::smallestTribeOfUnitType, this)(_playerID, _unitTypeIndex); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp new file mode 100644 index 000000000..8b18080b6 --- /dev/null +++ b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD250 + BOOLEnum AICState::canNavigateUnitsFromTileToTargetTile(int tribeID, int tile) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)( + DAT_TribesState::instance.tribes[tribeID].owner, + (int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID].tile], + (int)(short)DAT_TileMapState::instance.PathConnectionLayer[tile], + 0); + return (uint)(iVar1 != 0); + } +} +} diff --git a/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp b/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp new file mode 100644 index 000000000..11260ee9e --- /dev/null +++ b/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC960 + int AICState::createTribeForUnitType(int playerID, int unitSelectionTypeIndex) + { + short* psVar1 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + unitSelectionTypeIndex; + int _tribeID = (int)*psVar1; + if ((_tribeID == 0) || + (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex])) { + _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; + *psVar1 = (short)_tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex] = _tribeUID; + } + return _tribeID; + } +} +} diff --git a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp new file mode 100644 index 000000000..88bab103f --- /dev/null +++ b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp @@ -0,0 +1,102 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0280 + void AICState::destroyAnyBuildingInCategory(int playerID, AINervousDestroyBuildingCategory buildingCategory) + { + Map::Buildings::BuildingTypeShort BVar1; + int _buildingID; + bool bVar2; + + _buildingID = 1; + if (1 < DAT_BuildingsState::instance.maxBuildingsCount) { + Map::Buildings::Building* pBVar2 = &DAT_BuildingsState::instance.buildings[1]; + do { + if (((pBVar2->logicalState != 0) && (pBVar2->logicalState != Map::Buildings::BLS_REMOVE)) && + (pBVar2->owner == playerID)) { + if (buildingCategory == AINDBC_FEAR_FACTOR_BUILDINGS) { + BVar1 = pBVar2->buildingType; + if (((BVar1 != Map::Buildings::BT_CESSPIT) && (BVar1 != Map::Buildings::BT_BURNINGSTAKE)) && + (((BVar1 != Map::Buildings::BT_GIBBET && + (((BVar1 != Map::Buildings::BT_DUNGEON && (BVar1 != Map::Buildings::BT_STRETCHINGRACK)) && (BVar1 != Map::Buildings::BT_RACKFLOGGING)))) && + (((BVar1 != Map::Buildings::BT_CHOPPINGBLOCK && (BVar1 != Map::Buildings::BT_DUNKINGSTOOL)) && + ((BVar1 != Map::Buildings::BT_DOGCAGE && + (((BVar1 != Map::Buildings::BT_STATUE && (BVar1 != Map::Buildings::BT_SHRINE)) && + ((BVar1 != Map::Buildings::BT_DANCINGBEAR && + ((((BVar1 != Map::Buildings::BT_POND && (BVar1 != Map::Buildings::BT_GALLOWS)) && (BVar1 != Map::Buildings::BT_STOCKS)) && + ((BVar1 != Map::Buildings::BT_WITCHHOIST && (BVar1 != Map::Buildings::BT_MAYPOLE)))))))))))))))) { + bVar2 = BVar1 == Map::Buildings::BT_GARDEN; + goto LAB_004d04de; + } + } + else if (buildingCategory == AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS) { + BVar1 = pBVar2->buildingType; + if (((BVar1 != Map::Buildings::BT_FLETCHER) && (BVar1 != Map::Buildings::BT_BLACKSMITH)) && + (((BVar1 != Map::Buildings::BT_POLETURNER && + (((BVar1 != Map::Buildings::BT_ARMOURER && (BVar1 != Map::Buildings::BT_TANNER)) && (BVar1 != Map::Buildings::BT_INN)))) && + (((BVar1 != Map::Buildings::BT_APOTHECARY && (BVar1 != Map::Buildings::BT_CHAPEL)) && (BVar1 != Map::Buildings::BT_CHURCH)))))) { + bVar2 = BVar1 == Map::Buildings::BT_CATHEDRAL; + goto LAB_004d04de; + } + } + else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) { + BVar1 = pBVar2->buildingType; + if (((((BVar1 != Map::Buildings::BT_GATEHOUSELARGE) && (BVar1 != Map::Buildings::BT_GATEHOUSESMALL)) && + ((BVar1 != Map::Buildings::BT_DRAWBRIDGE && + ((((BVar1 != Map::Buildings::BT_TOWER1 && (BVar1 != Map::Buildings::BT_TOWER2)) && (BVar1 != Map::Buildings::BT_TOWER3)) && + ((BVar1 != Map::Buildings::BT_TOWER4 && (BVar1 != Map::Buildings::BT_TOWER5)))))))) && (BVar1 != Map::Buildings::BT_ENGINEERSGUILD)) && + (BVar1 != Map::Buildings::BT_TUNNELERSGUILD)) { + bVar2 = BVar1 == Map::Buildings::BT_OILSMELTER; + goto LAB_004d04de; + } + } + else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) { + BVar1 = pBVar2->buildingType; + if ((BVar1 != Map::Buildings::BT_MERCENARYPOST) && (BVar1 != Map::Buildings::BT_BARRACKS)) { + bVar2 = BVar1 == Map::Buildings::BT_STABLES; + goto LAB_004d04de; + } + } + else if (buildingCategory == AINDBC_WATER_BUILDINGS) { + if (pBVar2->buildingType != Map::Buildings::BT_WELL) { + bVar2 = pBVar2->buildingType == Map::Buildings::BT_WATERPOT; + goto LAB_004d04de; + } + } + else if (buildingCategory == AINDBC_RESOURCE_BUILDINGS) { + BVar1 = pBVar2->buildingType; + if (((BVar1 != Map::Buildings::BT_OXTETHER) && (BVar1 != Map::Buildings::BT_IRONMINE)) && + ((BVar1 != Map::Buildings::BT_PITCHRIG && + (((BVar1 != Map::Buildings::BT_BAKERY && (BVar1 != Map::Buildings::BT_BREWERY)) && (BVar1 != Map::Buildings::BT_QUARRY)))))) { + bVar2 = BVar1 == Map::Buildings::BT_MILL; +LAB_004d04de: + if (!bVar2) goto LAB_004d04f9; + } + } + else { + if (((buildingCategory == AINDBC_FARMS) && + (BVar1 = pBVar2->buildingType, BVar1 != Map::Buildings::BT_WHEATFARM)) && + ((BVar1 != Map::Buildings::BT_HOPFARM && (BVar1 != Map::Buildings::BT_APPLEFARM)))) { + bVar2 = BVar1 == Map::Buildings::BT_DAIRYFARM; + goto LAB_004d04de; + } + } + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_buildingID); + } +LAB_004d04f9: + _buildingID = _buildingID + 1; + pBVar2 = pBVar2 + 1; + } while (_buildingID < DAT_BuildingsState::instance.maxBuildingsCount); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp new file mode 100644 index 000000000..97c182d7a --- /dev/null +++ b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/AI/AIVState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_AIVState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB940 + undefined4 AICState::destroyBuildingIfNoWorker(int buildingID) + { + short _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; + int _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; + if ((((0 < _value) && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1)) && + (DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0)) && + (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY)) { + if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] == 0) { + if (0x13 < _value) { + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(buildingID); + return 1; + } + } + else if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { + DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = _value + -1; + } + } + return 0; + } +} +} diff --git a/src/OpenSHC/AI/AICState/digNearestMoat.cpp b/src/OpenSHC/AI/AICState/digNearestMoat.cpp new file mode 100644 index 000000000..c734a3ff9 --- /dev/null +++ b/src/OpenSHC/AI/AICState/digNearestMoat.cpp @@ -0,0 +1,44 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD160 + void AICState::digNearestMoat(int playerID) + { + int iVar1; + BOOLEnum tile; + int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10]; + if ((((tribeID != 0) && + (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10])) && + (0 < DAT_TribesState::instance.tribes[tribeID].size)) && + (DAT_TribesState::instance.tribes[tribeID].percentageSomething < 0x51)) { + iVar1 = MACRO_CALL_MEMBER(Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)(playerID); + if (iVar1 < 1) { + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); + return; + } + iVar1 = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + tile = MACRO_CALL_MEMBER(Map::TileMapState_Func::findNearestFriendlyMoatTileForDigging, DAT_TileMapState::ptr)(playerID, iVar1, 1); + if (-1 < (int)tile) { + MACRO_CALL_MEMBER(Map::TileMapState_Func::setXYBasedOnMoatID, DAT_TileMapState::ptr)(tile, 1, (int)DAT_UnitsState::instance.units[iVar1].x, (int)DAT_UnitsState::instance.units[iVar1].y); + iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::updateTribeRallyFlags, DAT_TribesState::ptr)(tribeID); + if (iVar1 == 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(tribeID, Map::Units::UIT_DIG_MOAT, DAT_TileMapState::instance.ALG_MoatXResult, DAT_TileMapState::instance.ALG_MoatYResult, 0); + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_STAND_GROUND; + } + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp new file mode 100644 index 000000000..7aaa535d8 --- /dev/null +++ b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp @@ -0,0 +1,80 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CCBF0 + int AICState::getDefensiveTribeForUnit(int playerID, int unitID) + { + int _index = 0; + int _unitType = (int)(short)DAT_UnitsState::instance.units[unitID].unitType; + int _unitType2; + do { + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index]) || + (_unitType2 = (int)(short)DAT_UnitsState::instance.units[unitID].unitTypeToChangeInto, + _unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index])) break; + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1]) || + (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1])) { + _index = _index + 1; + break; + } + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2]) || + (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2])) { + _index = _index + 2; + break; + } + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3]) || + (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3])) { + _index = _index + 3; + break; + } + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4]) || + (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4])) { + _index = _index + 4; + break; + } + _index = _index + 5; + } while (_index < 0x14); + int _tribeIndex; + if (_index < 1) { + _tribeIndex = 0xb4; + } + else if (_index < 2) { + _tribeIndex = 0xb5; + } + else if (_index < 7) { + _tribeIndex = 0xb6; + } + else if (_index < 0xc) { + _tribeIndex = 0xb7; + } + else if (_index < 0xf) { + _tribeIndex = 0xb8; + } + else { + if (19 < _index) { + return 0; + } + _tribeIndex = 0xb9; + } + short* _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeIndex; + int _tribeID = (int)*_pTribeID; + if ((_tribeID == 0) || + (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex])) { + _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; + *_pTribeID = (short)_tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex] = _tribeUID; + } + return _tribeID; + } +} +} diff --git a/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp b/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp new file mode 100644 index 000000000..6dd67d991 --- /dev/null +++ b/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Game/Resources/ResourceType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0520 + BOOLEnum AICState::isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade(int playerID, ResourceType resourceType, int buffer) + { + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == AITA_NULL) { + return TRUE; + } + if (resourceType == Game::Resources::RT_GOLD) { + return FALSE; + } + return (int)this->aics[_aiType - 1].minimumGoodsRequiredAfterTrade + buffer <= DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType]; + } +} +} diff --git a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp new file mode 100644 index 000000000..4f4662e1d --- /dev/null +++ b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp @@ -0,0 +1,32 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" +#include "OpenSHC/Globals/INT_ARRAY_00eb0af0.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0830 + void AICState::playAnger1BikFromPlayer(int playerID) + { + int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar2 != 0) { + int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] != DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) && + (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { + DWORD DVar3 = timeGetTime(); + if ((INT_ARRAY_00eb0af0::instance[playerID] == 0) || (599999 < DVar3 - INT_ARRAY_00eb0af0::instance[playerID])) { + INT_ARRAY_00eb0af0::instance[playerID] = DVar3; + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 5); + } + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp new file mode 100644 index 000000000..b235964f5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0C00 + void AICState::playAnger2BikFromPlayerToPlayer(int playerID, int targetPlayerID) + { + if (DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + bool bVar2; + if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 == 0)) && + (bVar2 = targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, + DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 = 0x60, bVar2)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 6); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp new file mode 100644 index 000000000..2d99ef4d8 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0FC0 + void AICState::playFriendlyVictoryBikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 10); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp new file mode 100644 index 000000000..d3d56f13d --- /dev/null +++ b/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0B70 + void AICState::playGoodsNotSentBikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1c); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp new file mode 100644 index 000000000..8aec4a1c2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0A20 + void AICState::playGoodsRequestBikFromPlayerToPlayer(int playerID, int targetPlayerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) && (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID].lordKilledByPlayerID == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0xe); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp new file mode 100644 index 000000000..fbab88edc --- /dev/null +++ b/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0BB0 + void AICState::playGoodsSentBikFromPlayerToPlayer(int playerID, int targetPlayerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if ((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1d); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp b/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp new file mode 100644 index 000000000..b976cc78c --- /dev/null +++ b/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0F90 + void AICState::playJokeBikFromAIToHuman(int playerID, int aiType) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, aiType, 0x14); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp new file mode 100644 index 000000000..28e61efb1 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0CF0 + void AICState::playNervous1BikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if ((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 == 0)) { + DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 = 0x30; + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 8); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp new file mode 100644 index 000000000..4d3b6da36 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0B10 + void AICState::playNervous2BikFromPlayer(int playerID) + { + int iVar3 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar2 = DAT_GameSynchronyState::instance.currentPlayerSlotID; + if ((iVar3 != 0) && (DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown == 0)) { + int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown = 48; + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] != DAT_GameState::instance.mapAndTime.playerTeams[iVar2]) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 9); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp new file mode 100644 index 000000000..d8ca73671 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1050 + void AICState::playNoHelpBikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1f); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp new file mode 100644 index 000000000..b9bf203fe --- /dev/null +++ b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp @@ -0,0 +1,56 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D08B0 + void AICState::playPlayerKilledBiksFromKilledAndKillerPlayer(int killerPlayerID, int killedPlayerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(killerPlayerID); + if (iVar1 != 0) { + if (killedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + iVar1 = 0xc; + } + else { + if (killerPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + int i = 1; + do { + if ((DAT_GameState::instance.playerDataArray[i].aiType != AITA_NULL) && + (DAT_GameState::instance.mapAndTime.playerTeams[i] == DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i); + if (iVar2 != 0) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(i, (int)DAT_GameState::instance.playerDataArray[i].aiType - 1, 0x11); + } + } + i = i + 1; + } while (i < 9); + return; + } + iVar1 = DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]; + if (iVar1 == DAT_GameState::instance.mapAndTime.playerTeams[killedPlayerID]) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 0x10); + return; + } + if (DAT_GameState::instance.mapAndTime.playerTeams[killerPlayerID] == iVar1) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 0x12); + return; + } + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + iVar1 = 0xd; + } + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, iVar1); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp new file mode 100644 index 000000000..1dc39d4bf --- /dev/null +++ b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp @@ -0,0 +1,27 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0D40 + void AICState::playRequestHelpBikFromPlayer(int playerID) + { + int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 = DAT_GameSynchronyState::instance.currentPlayerSlotID; + if ((iVar2 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 == 0)) { + DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 = 0x30; + if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[iVar1]) && (DAT_GameState::instance.playerDataArray[iVar1].lordKilledByPlayerID == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x13); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp new file mode 100644 index 000000000..89cacc944 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp @@ -0,0 +1,33 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D07C0 + void AICState::playTauntToAttackedPlayerBikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + iVar1 = 0; + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { + iVar1 = 0x17; + } + if (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (iVar1 == 0) { + iVar1 = ((byte)SEC_RNG::instance.currentNumber2 & 3) + 1; + } + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, iVar1); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp new file mode 100644 index 000000000..e27c7b599 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1000 + void AICState::playTeamWinningBikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker == 0)) && (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1e); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp new file mode 100644 index 000000000..e216c8c1f --- /dev/null +++ b/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp @@ -0,0 +1,32 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" +#include "OpenSHC/Globals/DWORD_00eb0b18.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0A80 + void AICState::playThanksBikFromPlayerToPlayer(int playerID, int targetPlayerID) + { + DWORD DVar2; + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + iVar1 = (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + DAT_GameState::instance.playerDataArray[playerID].aiRequestDelay = this->aics[iVar1].aiRequestDelay; + if (((targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) && + (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID].lordKilledByPlayerID == 0)) && + ((DVar2 = timeGetTime(), DWORD_00eb0b18::instance == 0 || (1199999 < DVar2 - DWORD_00eb0b18::instance)))) { + DWORD_00eb0b18::instance = DVar2; + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, iVar1, 0xf); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp new file mode 100644 index 000000000..5fb4e29cf --- /dev/null +++ b/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0C70 + void AICState::playVictory2BikFromPlayerToPlayer(int playerID, int targetPlayerID) + { + int iVar1; + bool bVar2; + if ((((DAT_GameState::instance.playerDataArray[targetPlayerID].aiType != AITA_NULL) && + (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] != -1)) && + (iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(targetPlayerID), iVar1 != 0)) && + (((iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID), iVar1 != 0 && + (DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 == 0)) && + (bVar2 = playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, + DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 = 0x30, bVar2)))) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(targetPlayerID, (int)DAT_GameState::instance.playerDataArray[targetPlayerID].aiType - 1, 0xb); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp new file mode 100644 index 000000000..ad2cf43b2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4630 + void AICState::recreateEngineersTribe(int playerID) + { + if (0 < DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops) { + int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; + if ((_tribeID != 0) && + (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12] = 0; + } + MACRO_CALL_MEMBER(AICState_Func::addEngineersToTribe, this)(playerID); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp new file mode 100644 index 000000000..b1b870c29 --- /dev/null +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -0,0 +1,60 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC9B0 + int AICState::smallestTribeOfUnitType(int playerID, short* unitType) + { + int iVar7 = 0; + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == AITA_NULL) { + return 0; + } + int iVar3 = (int)this->aics[_aiType - 1].defWallPatrolGroups; + int iVar6 = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[(int)unitType]; + int _tribeID = 0; + int local_c = 0; + short sVar4 = 1000; + if ((iVar3 < iVar6) && + (((unitType == (short*)0x8 || (unitType == (short*)0xa)) || (unitType == (short*)0x11)))) { + iVar6 = iVar3; + } + iVar3 = DAT_SkirmishDefinedData::instance.DAT_AiTribeIDOffsetForUnitType[(int)unitType]; + if (0 < iVar6) { + unitType = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar3; + do { + int iVar5 = (int)*unitType; + if ((iVar5 == 0) || + (DAT_TribesState::instance.tribes[iVar5].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7])) { + _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + goto LAB_004ccaae; + } + short sVar1 = DAT_TribesState::instance.tribes[iVar5].size; + if (sVar1 < sVar4) { + _tribeID = iVar5; + local_c = iVar7; + sVar4 = sVar1; + } + unitType = unitType + 1; + iVar7 = iVar7 + 1; + } while (iVar7 < iVar6); + iVar7 = local_c; + if (_tribeID != 0) { +LAB_004ccaae: + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[iVar3 + iVar7] = (short)_tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] = DAT_TribesState::instance.tribes[_tribeID].uid; + return _tribeID; + } + } + return 0; + } +} +} diff --git a/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp b/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp new file mode 100644 index 000000000..45d773b2c --- /dev/null +++ b/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp @@ -0,0 +1,35 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC7B0 + void AICState::syncBehaviourType7UnitTribes(int param_1) + { + int tribeID; + uint unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + Map::Units::Unit* pUVar1 = &DAT_UnitsState::instance.units[1]; + do { + if ((((pUVar1->owner == param_1) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) && + (pUVar1->dying == 0)) && (pUVar1->aiUnitBehaviourType == 7)) { + tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xa7]; + if (pUVar1->tribeID != tribeID) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)pUVar1->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + } + } + unitID = unitID + 1; + pUVar1 = pUVar1 + 1; + } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp new file mode 100644 index 000000000..fb055692e --- /dev/null +++ b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp @@ -0,0 +1,65 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Game/GameStateStructures.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0190 + BOOLEnum AICState::teamIsWeakRelativeToEnemy(int playerID, BOOLEnum param_2) + { + short _relativeStrength; + int _totalEnemyTroopValue = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; + if (_totalEnemyTroopValue == 0) { + _relativeStrength = 100; + } + else { + _relativeStrength = (short)((DAT_GameState::instance.playerDataArray[playerID].totalTeamTroopValue * 100) / _totalEnemyTroopValue); + } + DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy = _relativeStrength; + if (param_2 == FALSE) { + if (DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue < 100) { + return FALSE; + } + BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + if (BVar2 != FALSE) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 50) { + return TRUE; + } + return FALSE; + } + if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 250) { + return TRUE; + } + return FALSE; + } + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 75) { + return TRUE; + } + } + else { + BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + if (BVar2 != FALSE) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 0x46) { + return TRUE; + } + return FALSE; + } + if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 300) { + return TRUE; + } + return FALSE; + } + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 100) { + return TRUE; + } + } + return FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp new file mode 100644 index 000000000..414009e9a --- /dev/null +++ b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004C6D30 + void AICState::wipeAICMemory() + { + AICSpecification* destination = this->aics; + int iVar1 = 20; + do { + MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)(676, '\0', destination); + destination = destination + 1; + iVar1 = iVar1 + -1; + } while (iVar1 != 0); + } +} +} From c946f8c631de3883dd47de07e961527489929911 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 20 Jul 2026 16:28:18 +0200 Subject: [PATCH 006/242] batch 5 unpolished --- .../AI/AICState/setAICParameters_01.cpp | 150 ++++++++++++++++++ .../AI/AICState/setAICParameters_02.cpp | 148 +++++++++++++++++ .../AI/AICState/setAICParameters_03.cpp | 148 +++++++++++++++++ .../AI/AICState/setAICParameters_04.cpp | 149 +++++++++++++++++ .../AI/AICState/setAICParameters_05.cpp | 148 +++++++++++++++++ 5 files changed, 743 insertions(+) create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_01.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_02.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_03.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_04.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_05.cpp diff --git a/src/OpenSHC/AI/AICState/setAICParameters_01.cpp b/src/OpenSHC/AI/AICState/setAICParameters_01.cpp new file mode 100644 index 000000000..3cb13057a --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_01.cpp @@ -0,0 +1,150 @@ +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AICState.hpp" + +namespace OpenSHC { +namespace AI { + + using AIC::AITC_ANY; + using AIC::AITC_BALANCED; + using AIC::AITC_CLOSEST; + using AIC::AITC_GOLD; + using AIC::AITC_PLAYER; + + // FUNCTION: STRONGHOLDCRUSADER 0x004C6D60 + void AICState::setAICParameters_01(int aicID) + { + this->aics[aicID].populationPerFarm = 6; + this->aics[aicID].minimumCheese = 0xffffffff; + this->aics[aicID].minimumBread = 0xffffffff; + this->aics[aicID].minimumWheat = 0xffffffff; + this->aics[aicID].minimumHop = 0xffffffff; + this->aics[aicID].aiRequestDelay = 0x12; + this->aics[aicID].populationPerQuarry = 0x12; + this->aics[aicID].maxWoodcutters = 6; + this->aics[aicID].maxFarms = 6; + this->aics[aicID].sellResource09 = 0x12; + this->aics[aicID].flagType = 0xc; + this->aics[aicID].unknown002 = 0; + this->aics[aicID].unknown001 = 0; + this->aics[aicID].unknown003 = 0; + this->aics[aicID].unknown004 = 0; + this->aics[aicID].unknown005 = 0; + this->aics[aicID].criticalPopularity = 4000; + this->aics[aicID].lowestPopularity = 0x157c; + this->aics[aicID].highestPopularity = 0x1d4c; + this->aics[aicID].taxesMin = 3; + this->aics[aicID].taxesMax = 10; + this->aics[aicID].farm1 = 0x20; + this->aics[aicID].unknown011 = 0x14; + this->aics[aicID].maxFood = 100; + this->aics[aicID].minimumApples = 10; + this->aics[aicID].tradeAmountFood = 10; + this->aics[aicID].tradeAmountEquipment = 2; + this->aics[aicID].minimumGoodsRequiredAfterTrade = 0; + this->aics[aicID].doubleRationsFoodThreshold = 0; + this->aics[aicID].maxWood = 0x1e; + this->aics[aicID].maxStone = 0x28; + this->aics[aicID].maxResourceOther = 0x14; + this->aics[aicID].maxEquipment = 0x14; + this->aics[aicID].maxBeer = 0x14; + this->aics[aicID].maxResourceVariance = 5; + this->aics[aicID].recruitGoldThreshold = 200; + this->aics[aicID].populationPerWoodcutter = 8; + this->aics[aicID].populationPerIronmine = 0; + this->aics[aicID].populationPerPitchrig = 0; + this->aics[aicID].maxQuarries = 1; + this->aics[aicID].maxIronmines = 1; + this->aics[aicID].maxPitchrigs = 1; + this->aics[aicID].buildInterval = 1; + this->aics[aicID].resourceRebuildDelay = 10; + this->aics[aicID].blacksmithSetting = 0x16; + this->aics[aicID].fletcherSetting = 0x11; + this->aics[aicID].poleturnerSetting = 0x13; + this->aics[aicID].sellResource02 = 3; + this->aics[aicID].sellResource03 = 6; + this->aics[aicID].sellResource04 = 7; + this->aics[aicID].sellResource05 = 9; + this->aics[aicID].sellResource06 = 0xe; + this->aics[aicID].sellResource07 = 0x10; + this->aics[aicID].sellResource11 = 0x14; + this->aics[aicID].sellResource12 = 0x15; + this->aics[aicID].sellResource13 = 0x16; + this->aics[aicID].sellResource14 = 0x17; + this->aics[aicID].sellResource15 = 0x18; + this->aics[aicID].defWallPatrolRallyTime = 0x14; + this->aics[aicID].defWallPatrolGroups = 1; + this->aics[aicID].defSiegeEngineGoldThreshold = 200; + this->aics[aicID].defSiegeEngineBuildDelay = 0x14; + this->aics[aicID].unknown072 = 800; + this->aics[aicID].unknown073 = 0x50; + this->aics[aicID].recruitProbDefWeak = 0x32; + this->aics[aicID].RecruitIntervalWeak = 1; + this->aics[aicID].RecruitInterval = 1; + this->aics[aicID].RecruitIntervalStrong = 1; + this->aics[aicID].SortieUnitRanged = 0x16; + this->aics[aicID].SortieUnitMelee = 0x18; + this->aics[aicID].DefDiggingUnit = 0x18; + this->aics[aicID].OuterPatrolGroupsCount = 1; + this->aics[aicID].OuterPatrolRallyDelay = 10; + this->aics[aicID].DefUnit1 = 0x18; + this->aics[aicID].DefUnit2 = 0x18; + this->aics[aicID].DefUnit3 = 0x16; + this->aics[aicID].DefUnit4 = 0x16; + this->aics[aicID].RaidUnitsBase = 10; + this->aics[aicID].RaidUnit1 = 0x18; + this->aics[aicID].RaidUnit2 = 0x18; + this->aics[aicID].RaidUnit3 = 0x16; + this->aics[aicID].recruitProbDefDefault = 0; + this->aics[aicID].recruitProbDefStrong = 0; + this->aics[aicID].recruitProbRaidWeak = 0x32; + this->aics[aicID].recruitProbRaidDefault = 0x32; + this->aics[aicID].recruitProbRaidStrong = 0; + this->aics[aicID].recruitProbAttackWeak = 0; + this->aics[aicID].recruitProbAttackDefault = 0x32; + this->aics[aicID].recruitProbAttackStrong = 100; + this->aics[aicID].SortieUnitRangedMin = 5; + this->aics[aicID].SortieUnitMeleeMin = 6; + this->aics[aicID].DefDiggingUnitMax = 0; + this->aics[aicID].DefWalls = 0x14; + this->aics[aicID].DefTotal = 0x1e; + this->aics[aicID].OuterPatrolGroupsMove = 0; + this->aics[aicID].RaidUnitsRandom = 0xf; + this->aics[aicID].HarassingSiegeEnginesMax = 0; + this->aics[aicID].HarassingSiegeEngine1 = 0xbe; + this->aics[aicID].RaidRetargetDelay = 3; + this->aics[aicID].AttForceBase = 0x14; + this->aics[aicID].AttForceRandom = 10; + this->aics[aicID].AttForceSupportAllyThreshold = 0xf; + this->aics[aicID].AttForceRallyPercentage = 0x32; + this->aics[aicID].AttMovingTribesThreshold = 100; + this->aics[aicID].AttAssaultDelay = 0; + this->aics[aicID].AttUnitPatrolRecommandDelay = 0x19; + this->aics[aicID].AttCoordinationPreference = 0x14; + this->aics[aicID].SiegeEngine1 = 0; + this->aics[aicID].CowThrowInterval = 1000; + this->aics[aicID].AttMaxEngineers = 0; + this->aics[aicID].AttDiggingUnit = 0x18; + this->aics[aicID].AttDiggingUnitMax = 0x14; + this->aics[aicID].AttMaxAssassins = 0; + this->aics[aicID].AttUnit2 = 0x16; + this->aics[aicID].AttUnit2Max = 0; + this->aics[aicID].AttMaxLaddermen = 0; + this->aics[aicID].AttMaxTunnelers = 0; + this->aics[aicID].AttUnitPatrol = 0x16; + this->aics[aicID].AttUnitPatrolMax = 0; + this->aics[aicID].AttUnitPatrolGroupsCount = 0; + this->aics[aicID].AttUnitBackup = 0x16; + this->aics[aicID].AttUnitBackupMax = 0x10; + this->aics[aicID].AttUnitBackupGroupsCount = 0; + this->aics[aicID].AttUnitEngageMax = 0; + this->aics[aicID].AttUnitEngage = 0; + this->aics[aicID].AttUnitSiegeDef = 0x18; + this->aics[aicID].AttUnitSiegeDefMax = 0; + this->aics[aicID].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicID].AttUnitMain1 = 0x18; + this->aics[aicID].AttMaxDefault = 200; + this->aics[aicID].AttMainGroupsCount = 1; + this->aics[aicID].TargetChoice = AITC_PLAYER; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_02.cpp b/src/OpenSHC/AI/AICState/setAICParameters_02.cpp new file mode 100644 index 000000000..c3e0c0b69 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_02.cpp @@ -0,0 +1,148 @@ +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AICState.hpp" + +namespace OpenSHC { +namespace AI { + + using AIC::AITC_ANY; + using AIC::AITC_BALANCED; + using AIC::AITC_CLOSEST; + using AIC::AITC_GOLD; + using AIC::AITC_PLAYER; + + // FUNCTION: STRONGHOLDCRUSADER 0x004C7120 + void AICState::setAICParameters_02(int param_1) + { + this->aics[param_1].minimumBread = 0xffffffff; + this->aics[param_1].minimumWheat = 0xffffffff; + this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].populationPerFarm = 5; + this->aics[param_1].unknown011 = 0xf; + this->aics[param_1].tradeAmountFood = 5; + this->aics[param_1].aiRequestDelay = 0xc; + this->aics[param_1].maxResourceOther = 0xf; + this->aics[param_1].maxEquipment = 0xc; + this->aics[param_1].maxBeer = 5; + this->aics[param_1].maxResourceVariance = 5; + this->aics[param_1].populationPerWoodcutter = 5; + this->aics[param_1].populationPerQuarry = 0xf; + this->aics[param_1].resourceRebuildDelay = 0xc; + this->aics[param_1].flagType = 0xc; + this->aics[param_1].unknown002 = 0; + this->aics[param_1].unknown001 = 0; + this->aics[param_1].unknown003 = 0; + this->aics[param_1].unknown004 = 0; + this->aics[param_1].unknown005 = 0; + this->aics[param_1].criticalPopularity = 4000; + this->aics[param_1].lowestPopularity = 5000; + this->aics[param_1].highestPopularity = 8000; + this->aics[param_1].taxesMin = 3; + this->aics[param_1].taxesMax = 0xb; + this->aics[param_1].farm1 = 0x20; + this->aics[param_1].maxFood = 0x96; + this->aics[param_1].minimumApples = 10; + this->aics[param_1].minimumCheese = 0x14; + this->aics[param_1].tradeAmountEquipment = 6; + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + this->aics[param_1].doubleRationsFoodThreshold = 0x50; + this->aics[param_1].maxWood = 0x30; + this->aics[param_1].maxStone = 0x28; + this->aics[param_1].recruitGoldThreshold = 200; + this->aics[param_1].populationPerIronmine = 0; + this->aics[param_1].populationPerPitchrig = 0; + this->aics[param_1].maxQuarries = 2; + this->aics[param_1].maxIronmines = 1; + this->aics[param_1].maxWoodcutters = 10; + this->aics[param_1].maxPitchrigs = 1; + this->aics[param_1].maxFarms = 10; + this->aics[param_1].buildInterval = 2; + this->aics[param_1].blacksmithSetting = 0x16; + this->aics[param_1].fletcherSetting = 0x11; + this->aics[param_1].poleturnerSetting = 0x13; + this->aics[param_1].sellResource02 = 3; + this->aics[param_1].sellResource03 = 6; + this->aics[param_1].sellResource04 = 7; + this->aics[param_1].sellResource05 = 9; + this->aics[param_1].sellResource06 = 0xe; + this->aics[param_1].sellResource07 = 0x10; + this->aics[param_1].sellResource09 = 0x12; + this->aics[param_1].sellResource11 = 0x14; + this->aics[param_1].sellResource12 = 0x15; + this->aics[param_1].sellResource13 = 0x16; + this->aics[param_1].sellResource14 = 0x17; + this->aics[param_1].sellResource15 = 0x18; + this->aics[param_1].defWallPatrolRallyTime = 2; + this->aics[param_1].defWallPatrolGroups = 4; + this->aics[param_1].defSiegeEngineGoldThreshold = 500; + this->aics[param_1].defSiegeEngineBuildDelay = 0x14; + this->aics[param_1].unknown072 = 400; + this->aics[param_1].unknown073 = 0x3c; + this->aics[param_1].recruitProbDefStrong = 0x14; + this->aics[param_1].SortieUnitRanged = 0x16; + this->aics[param_1].DefDiggingUnitMax = 0x14; + this->aics[param_1].DefUnit1 = 0x16; + this->aics[param_1].RaidUnitsRandom = 10; + this->aics[param_1].recruitProbDefWeak = 0x46; + this->aics[param_1].recruitProbRaidDefault = 0x28; + this->aics[param_1].recruitProbRaidStrong = 0x28; + this->aics[param_1].recruitProbAttackWeak = 0; + this->aics[param_1].recruitProbAttackStrong = 0x28; + this->aics[param_1].RecruitIntervalWeak = 0; + this->aics[param_1].RecruitInterval = 1; + this->aics[param_1].RecruitIntervalStrong = 1; + this->aics[param_1].SortieUnitRangedMin = 2; + this->aics[param_1].SortieUnitMeleeMin = 8; + this->aics[param_1].SortieUnitMelee = 0x18; + this->aics[param_1].DefDiggingUnit = 0x18; + this->aics[param_1].DefWalls = 0x32; + this->aics[param_1].DefTotal = 0x50; + this->aics[param_1].OuterPatrolGroupsCount = 3; + this->aics[param_1].OuterPatrolGroupsMove = 1; + this->aics[param_1].OuterPatrolRallyDelay = 2; + this->aics[param_1].RaidUnit1 = 0x47; + this->aics[param_1].RaidUnit2 = 0x47; + this->aics[param_1].RaidUnit3 = 0x47; + this->aics[param_1].RaidUnit4 = 0x48; + this->aics[param_1].HarassingSiegeEnginesMax = 1; + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + this->aics[param_1].recruitProbDefDefault = 0x1e; + this->aics[param_1].recruitProbRaidWeak = 0x1e; + this->aics[param_1].recruitProbAttackDefault = 0x1e; + this->aics[param_1].RaidUnitsBase = 0x1e; + this->aics[param_1].RaidRetargetDelay = 3; + this->aics[param_1].AttForceBase = 0x1e; + this->aics[param_1].AttForceRandom = 10; + this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; + this->aics[param_1].AttForceRallyPercentage = 0x32; + this->aics[param_1].AttMovingTribesThreshold = 100; + this->aics[param_1].AttAssaultDelay = 0; + this->aics[param_1].AttUnitPatrolRecommandDelay = 0x19; + this->aics[param_1].AttCoordinationPreference = 0x28; + this->aics[param_1].SiegeEngine1 = 0x27; + this->aics[param_1].CowThrowInterval = 1000; + this->aics[param_1].AttMaxEngineers = 2; + this->aics[param_1].AttDiggingUnit = 0x18; + this->aics[param_1].AttDiggingUnitMax = 0x14; + this->aics[param_1].AttMaxAssassins = 0; + this->aics[param_1].AttUnit2 = 0x16; + this->aics[param_1].AttUnit2Max = 0x14; + this->aics[param_1].AttMaxLaddermen = 10; + this->aics[param_1].AttMaxTunnelers = 0; + this->aics[param_1].AttUnitPatrol = 0x48; + this->aics[param_1].AttUnitPatrolMax = 0; + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + this->aics[param_1].AttUnitBackup = 0x46; + this->aics[param_1].AttUnitBackupMax = 0x32; + this->aics[param_1].AttUnitBackupGroupsCount = 1; + this->aics[param_1].AttUnitEngageMax = 0; + this->aics[param_1].AttUnitEngage = 0; + this->aics[param_1].AttUnitSiegeDef = 0x16; + this->aics[param_1].AttUnitSiegeDefMax = 0x1e; + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + this->aics[param_1].AttUnitMain1 = 0x18; + this->aics[param_1].AttMaxDefault = 200; + this->aics[param_1].AttMainGroupsCount = 1; + this->aics[param_1].TargetChoice = AITC_BALANCED; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_03.cpp b/src/OpenSHC/AI/AICState/setAICParameters_03.cpp new file mode 100644 index 000000000..2305891ed --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_03.cpp @@ -0,0 +1,148 @@ +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AICState.hpp" + +namespace OpenSHC { +namespace AI { + + using AIC::AITC_ANY; + using AIC::AITC_BALANCED; + using AIC::AITC_CLOSEST; + using AIC::AITC_GOLD; + using AIC::AITC_PLAYER; + + // FUNCTION: STRONGHOLDCRUSADER 0x004C7520 + void AICState::setAICParameters_03(int param_1) + { + this->aics[param_1].minimumWheat = 0xffffffff; + this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].flagType = 0xc; + this->aics[param_1].unknown002 = 0; + this->aics[param_1].unknown001 = 0; + this->aics[param_1].unknown003 = 0; + this->aics[param_1].unknown004 = 0; + this->aics[param_1].unknown005 = 0; + this->aics[param_1].criticalPopularity = 5000; + this->aics[param_1].lowestPopularity = 7000; + this->aics[param_1].highestPopularity = 0x2134; + this->aics[param_1].taxesMin = 3; + this->aics[param_1].taxesMax = 0xb; + this->aics[param_1].farm1 = 0x21; + this->aics[param_1].populationPerFarm = 4; + this->aics[param_1].unknown011 = 0x14; + this->aics[param_1].maxFood = 400; + this->aics[param_1].minimumApples = 10; + this->aics[param_1].minimumCheese = 10; + this->aics[param_1].minimumBread = 10; + this->aics[param_1].tradeAmountFood = 5; + this->aics[param_1].tradeAmountEquipment = 4; + this->aics[param_1].aiRequestDelay = 0xc; + this->aics[param_1].minimumGoodsRequiredAfterTrade = 100; + this->aics[param_1].doubleRationsFoodThreshold = 0x3c; + this->aics[param_1].maxWood = 0x46; + this->aics[param_1].maxStone = 0x28; + this->aics[param_1].maxResourceOther = 10; + this->aics[param_1].maxEquipment = 10; + this->aics[param_1].maxBeer = 5; + this->aics[param_1].maxResourceVariance = 5; + this->aics[param_1].recruitGoldThreshold = 200; + this->aics[param_1].populationPerWoodcutter = 6; + this->aics[param_1].populationPerQuarry = 0x19; + this->aics[param_1].populationPerIronmine = 10; + this->aics[param_1].populationPerPitchrig = 0x14; + this->aics[param_1].maxQuarries = 2; + this->aics[param_1].maxIronmines = 4; + this->aics[param_1].maxWoodcutters = 8; + this->aics[param_1].maxPitchrigs = 1; + this->aics[param_1].maxFarms = 0xc; + this->aics[param_1].buildInterval = 3; + this->aics[param_1].resourceRebuildDelay = 0x32; + this->aics[param_1].blacksmithSetting = 0x15; + this->aics[param_1].fletcherSetting = 0x12; + this->aics[param_1].poleturnerSetting = 0x13; + this->aics[param_1].sellResource02 = 3; + this->aics[param_1].sellResource04 = 7; + this->aics[param_1].sellResource05 = 9; + this->aics[param_1].sellResource06 = 0xe; + this->aics[param_1].sellResource07 = 0x10; + this->aics[param_1].sellResource08 = 0x11; + this->aics[param_1].sellResource10 = 0x13; + this->aics[param_1].sellResource11 = 0x14; + this->aics[param_1].sellResource13 = 0x16; + this->aics[param_1].sellResource15 = 0x18; + this->aics[param_1].defWallPatrolRallyTime = 10; + this->aics[param_1].defWallPatrolGroups = 4; + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + this->aics[param_1].defSiegeEngineBuildDelay = 0x14; + this->aics[param_1].unknown072 = 200; + this->aics[param_1].unknown073 = 0x28; + this->aics[param_1].recruitProbDefWeak = 100; + this->aics[param_1].recruitProbDefDefault = 0x3c; + this->aics[param_1].recruitProbDefStrong = 0x1e; + this->aics[param_1].recruitProbRaidWeak = 0; + this->aics[param_1].recruitProbRaidDefault = 0; + this->aics[param_1].RecruitIntervalWeak = 1; + this->aics[param_1].RecruitInterval = 1; + this->aics[param_1].RecruitIntervalStrong = 4; + this->aics[param_1].SortieUnitRangedMin = 4; + this->aics[param_1].OuterPatrolRallyDelay = 0x14; + this->aics[param_1].SortieUnitMeleeMin = 5; + this->aics[param_1].RaidUnitsRandom = 5; + this->aics[param_1].recruitProbRaidStrong = 0; + this->aics[param_1].recruitProbAttackWeak = 0; + this->aics[param_1].recruitProbAttackDefault = 0x28; + this->aics[param_1].recruitProbAttackStrong = 0x46; + this->aics[param_1].DefDiggingUnitMax = 0; + this->aics[param_1].DefDiggingUnit = 0x18; + this->aics[param_1].DefWalls = 0x1e; + this->aics[param_1].DefTotal = 0x28; + this->aics[param_1].OuterPatrolGroupsCount = 2; + this->aics[param_1].OuterPatrolGroupsMove = 1; + this->aics[param_1].RaidUnitsBase = 10; + this->aics[param_1].HarassingSiegeEnginesMax = 2; + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + this->aics[param_1].RaidRetargetDelay = 3; + this->aics[param_1].AttForceBase = 10; + this->aics[param_1].AttForceRandom = 10; + this->aics[param_1].SortieUnitRanged = 0x17; + this->aics[param_1].DefUnit1 = 0x17; + this->aics[param_1].DefUnit2 = 0x17; + this->aics[param_1].DefUnit3 = 0x17; + this->aics[param_1].SortieUnitMelee = 0x1a; + this->aics[param_1].RaidUnit1 = 0x1a; + this->aics[param_1].AttForceSupportAllyThreshold = 10; + this->aics[param_1].AttForceRallyPercentage = 0x3c; + this->aics[param_1].AttMovingTribesThreshold = 100; + this->aics[param_1].AttAssaultDelay = 5; + this->aics[param_1].AttUnitPatrolRecommandDelay = 0xf; + this->aics[param_1].AttCoordinationPreference = 0x14; + this->aics[param_1].CowThrowInterval = 0x1e; + this->aics[param_1].SiegeEngine1 = 0x27; + this->aics[param_1].SiegeEngine2 = 0x27; + this->aics[param_1].SiegeEngine3 = 0x27; + this->aics[param_1].SiegeEngine4 = 0x3b; + this->aics[param_1].AttMaxEngineers = 10; + this->aics[param_1].AttDiggingUnit = 0x1a; + this->aics[param_1].AttDiggingUnitMax = 10; + this->aics[param_1].AttMaxAssassins = 0; + this->aics[param_1].AttUnit2 = 0; + this->aics[param_1].AttUnit2Max = 0; + this->aics[param_1].AttMaxLaddermen = 0; + this->aics[param_1].AttMaxTunnelers = 0; + this->aics[param_1].AttUnitPatrol = 0; + this->aics[param_1].AttUnitPatrolMax = 0; + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + this->aics[param_1].AttUnitBackup = 0x17; + this->aics[param_1].AttUnitBackupMax = 5; + this->aics[param_1].AttUnitBackupGroupsCount = 1; + this->aics[param_1].AttUnitEngageMax = 0; + this->aics[param_1].AttUnitEngage = 0; + this->aics[param_1].AttUnitSiegeDef = 0x1a; + this->aics[param_1].AttUnitSiegeDefMax = 0; + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + this->aics[param_1].AttUnitMain1 = 0x1a; + this->aics[param_1].AttMaxDefault = 200; + this->aics[param_1].AttMainGroupsCount = 2; + this->aics[param_1].TargetChoice = AITC_GOLD; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_04.cpp b/src/OpenSHC/AI/AICState/setAICParameters_04.cpp new file mode 100644 index 000000000..e81e060e1 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_04.cpp @@ -0,0 +1,149 @@ +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AICState.hpp" + +namespace OpenSHC { +namespace AI { + + using AIC::AITC_ANY; + using AIC::AITC_BALANCED; + using AIC::AITC_CLOSEST; + using AIC::AITC_GOLD; + using AIC::AITC_PLAYER; + + // FUNCTION: STRONGHOLDCRUSADER 0x004C7910 + void AICState::setAICParameters_04(int param_1) + { + this->aics[param_1].unknown004 = 1; + this->aics[param_1].unknown005 = 1; + this->aics[param_1].farm2 = 0x20; + this->aics[param_1].farm4 = 0x20; + this->aics[param_1].minimumWheat = 0xffffffff; + this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].flagType = 0xd; + this->aics[param_1].unknown002 = 0; + this->aics[param_1].unknown001 = 0; + this->aics[param_1].unknown003 = 0; + this->aics[param_1].criticalPopularity = 0x1194; + this->aics[param_1].lowestPopularity = 6000; + this->aics[param_1].highestPopularity = 9000; + this->aics[param_1].taxesMin = 3; + this->aics[param_1].taxesMax = 0xb; + this->aics[param_1].farm1 = 0x21; + this->aics[param_1].farm3 = 0x1f; + this->aics[param_1].populationPerFarm = 5; + this->aics[param_1].unknown011 = 0xc; + this->aics[param_1].maxFood = 200; + this->aics[param_1].minimumApples = 5; + this->aics[param_1].minimumCheese = 5; + this->aics[param_1].minimumBread = 5; + this->aics[param_1].tradeAmountFood = 10; + this->aics[param_1].tradeAmountEquipment = 4; + this->aics[param_1].aiRequestDelay = 0x14; + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x28; + this->aics[param_1].doubleRationsFoodThreshold = 0x1e; + this->aics[param_1].maxWood = 0x3c; + this->aics[param_1].maxStone = 0x32; + this->aics[param_1].maxResourceOther = 10; + this->aics[param_1].maxEquipment = 10; + this->aics[param_1].maxBeer = 0xf; + this->aics[param_1].maxResourceVariance = 5; + this->aics[param_1].recruitGoldThreshold = 200; + this->aics[param_1].populationPerWoodcutter = 4; + this->aics[param_1].populationPerQuarry = 9; + this->aics[param_1].populationPerIronmine = 0xd; + this->aics[param_1].populationPerPitchrig = 0xf; + this->aics[param_1].maxQuarries = 6; + this->aics[param_1].maxIronmines = 3; + this->aics[param_1].maxWoodcutters = 0xc; + this->aics[param_1].maxPitchrigs = 2; + this->aics[param_1].maxFarms = 10; + this->aics[param_1].buildInterval = 3; + this->aics[param_1].resourceRebuildDelay = 0x14; + this->aics[param_1].blacksmithSetting = 0x16; + this->aics[param_1].fletcherSetting = 0x12; + this->aics[param_1].poleturnerSetting = 0x14; + this->aics[param_1].sellResource05 = 9; + this->aics[param_1].sellResource07 = 0x10; + this->aics[param_1].sellResource10 = 0x13; + this->aics[param_1].sellResource12 = 0x15; + this->aics[param_1].defWallPatrolRallyTime = 4; + this->aics[param_1].defWallPatrolGroups = 3; + this->aics[param_1].defSiegeEngineGoldThreshold = 0xfa; + this->aics[param_1].defSiegeEngineBuildDelay = 2; + this->aics[param_1].unknown072 = 100; + this->aics[param_1].unknown073 = 0x14; + this->aics[param_1].recruitProbDefWeak = 0x5a; + this->aics[param_1].recruitProbDefDefault = 0x3c; + this->aics[param_1].recruitProbDefStrong = 0x1e; + this->aics[param_1].recruitProbRaidWeak = 10; + this->aics[param_1].recruitProbRaidDefault = 0x1e; + this->aics[param_1].recruitProbRaidStrong = 10; + this->aics[param_1].recruitProbAttackDefault = 10; + this->aics[param_1].RecruitInterval = 4; + this->aics[param_1].RecruitIntervalStrong = 4; + this->aics[param_1].OuterPatrolGroupsCount = 4; + this->aics[param_1].HarassingSiegeEnginesMax = 4; + this->aics[param_1].recruitProbAttackWeak = 0; + this->aics[param_1].OuterPatrolRallyDelay = 3; + this->aics[param_1].RaidUnitsRandom = 0x14; + this->aics[param_1].recruitProbAttackStrong = 0x3c; + this->aics[param_1].RecruitIntervalWeak = 1; + this->aics[param_1].SortieUnitRangedMin = 8; + this->aics[param_1].SortieUnitRanged = 0x46; + this->aics[param_1].SortieUnitMeleeMin = 6; + this->aics[param_1].DefDiggingUnitMax = 8; + this->aics[param_1].DefWalls = 0x50; + this->aics[param_1].DefTotal = 100; + this->aics[param_1].OuterPatrolGroupsMove = 1; + this->aics[param_1].DefUnit1 = 0x17; + this->aics[param_1].DefUnit2 = 0x17; + this->aics[param_1].DefUnit3 = 0x16; + this->aics[param_1].DefUnit4 = 0x16; + this->aics[param_1].RaidUnitsBase = 5; + this->aics[param_1].RaidUnit1 = 0x4a; + this->aics[param_1].RaidUnit2 = 0x4a; + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + this->aics[param_1].RaidRetargetDelay = 5; + this->aics[param_1].AttForceRandom = 0xf; + this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; + this->aics[param_1].SortieUnitMelee = 0x19; + this->aics[param_1].DefDiggingUnit = 0x19; + this->aics[param_1].AttForceBase = 0x28; + this->aics[param_1].AttForceRallyPercentage = 0x50; + this->aics[param_1].AttMovingTribesThreshold = 100; + this->aics[param_1].AttAssaultDelay = 0xc; + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + this->aics[param_1].AttCoordinationPreference = 0x32; + this->aics[param_1].CowThrowInterval = 8; + this->aics[param_1].SiegeEngine1 = 0x27; + this->aics[param_1].SiegeEngine2 = 0x28; + this->aics[param_1].SiegeEngine3 = 0x4d; + this->aics[param_1].SiegeEngine4 = 0x28; + this->aics[param_1].AttMaxEngineers = 0xc; + this->aics[param_1].AttDiggingUnit = 0x19; + this->aics[param_1].AttDiggingUnitMax = 0x14; + this->aics[param_1].AttMaxAssassins = 0; + this->aics[param_1].AttUnit2 = 0; + this->aics[param_1].AttUnit2Max = 0; + this->aics[param_1].AttMaxLaddermen = 0; + this->aics[param_1].AttMaxTunnelers = 0; + this->aics[param_1].AttUnitPatrol = 0; + this->aics[param_1].AttUnitPatrolMax = 0; + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + this->aics[param_1].AttUnitBackup = 0x17; + this->aics[param_1].AttUnitBackupMax = 0x1e; + this->aics[param_1].AttUnitBackupGroupsCount = 3; + this->aics[param_1].AttUnitEngageMax = 0; + this->aics[param_1].AttUnitEngage = 0; + this->aics[param_1].AttUnitSiegeDef = 0x1b; + this->aics[param_1].AttUnitSiegeDefMax = 5; + this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; + this->aics[param_1].AttUnitMain1 = 0x1b; + this->aics[param_1].AttUnitMain2 = 0x19; + this->aics[param_1].AttUnitMain3 = 0x19; + this->aics[param_1].AttMaxDefault = 200; + this->aics[param_1].AttMainGroupsCount = 3; + this->aics[param_1].TargetChoice = AITC_CLOSEST; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_05.cpp b/src/OpenSHC/AI/AICState/setAICParameters_05.cpp new file mode 100644 index 000000000..b3958aa09 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_05.cpp @@ -0,0 +1,148 @@ +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AICState.hpp" + +namespace OpenSHC { +namespace AI { + + using AIC::AITC_ANY; + using AIC::AITC_BALANCED; + using AIC::AITC_CLOSEST; + using AIC::AITC_GOLD; + using AIC::AITC_PLAYER; + + // FUNCTION: STRONGHOLDCRUSADER 0x004C7D20 + void AICState::setAICParameters_05(int param_1) + { + this->aics[param_1].maxFood = 0x32; + this->aics[param_1].maxStone = 0x32; + this->aics[param_1].taxesMin = 3; + this->aics[param_1].taxesMax = 0xc; + this->aics[param_1].farm2 = 0x1e; + this->aics[param_1].farm3 = 0x1e; + this->aics[param_1].populationPerFarm = 3; + this->aics[param_1].populationPerIronmine = 0xc; + this->aics[param_1].maxQuarries = 4; + this->aics[param_1].maxIronmines = 4; + this->aics[param_1].defWallPatrolGroups = 4; + this->aics[param_1].flagType = 10; + this->aics[param_1].unknown002 = 0; + this->aics[param_1].unknown001 = 0; + this->aics[param_1].unknown003 = 0; + this->aics[param_1].unknown004 = 0; + this->aics[param_1].unknown005 = 0; + this->aics[param_1].criticalPopularity = 4000; + this->aics[param_1].lowestPopularity = 5000; + this->aics[param_1].highestPopularity = 8000; + this->aics[param_1].farm1 = 0x1f; + this->aics[param_1].farm4 = 0x20; + this->aics[param_1].unknown011 = 0x14; + this->aics[param_1].minimumApples = 5; + this->aics[param_1].minimumCheese = 5; + this->aics[param_1].minimumBread = 5; + this->aics[param_1].minimumWheat = 5; + this->aics[param_1].minimumHop = 5; + this->aics[param_1].tradeAmountFood = 10; + this->aics[param_1].tradeAmountEquipment = 0; + this->aics[param_1].aiRequestDelay = 0x28; + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x14; + this->aics[param_1].doubleRationsFoodThreshold = 0x14; + this->aics[param_1].maxWood = 0x3c; + this->aics[param_1].maxResourceOther = 10; + this->aics[param_1].maxEquipment = 5; + this->aics[param_1].maxBeer = 10; + this->aics[param_1].maxResourceVariance = 2; + this->aics[param_1].recruitGoldThreshold = 200; + this->aics[param_1].populationPerWoodcutter = 6; + this->aics[param_1].populationPerQuarry = 10; + this->aics[param_1].populationPerPitchrig = 0x14; + this->aics[param_1].maxWoodcutters = 0xe; + this->aics[param_1].maxPitchrigs = 1; + this->aics[param_1].maxFarms = 0xf; + this->aics[param_1].buildInterval = 2; + this->aics[param_1].resourceRebuildDelay = 0x28; + this->aics[param_1].blacksmithSetting = 0x16; + this->aics[param_1].fletcherSetting = 0x12; + this->aics[param_1].poleturnerSetting = 0x14; + this->aics[param_1].defWallPatrolRallyTime = 3; + this->aics[param_1].defSiegeEngineGoldThreshold = 0x14; + this->aics[param_1].defSiegeEngineBuildDelay = 8; + this->aics[param_1].sellResource08 = 0x11; + this->aics[param_1].sellResource09 = 0x12; + this->aics[param_1].sellResource11 = 0x14; + this->aics[param_1].sellResource12 = 0x15; + this->aics[param_1].sellResource14 = 0x17; + this->aics[param_1].unknown072 = 100; + this->aics[param_1].unknown073 = 0x14; + this->aics[param_1].recruitProbDefWeak = 100; + this->aics[param_1].recruitProbDefDefault = 0x22; + this->aics[param_1].recruitProbDefStrong = 0x19; + this->aics[param_1].RaidUnitsRandom = 5; + this->aics[param_1].HarassingSiegeEnginesMax = 5; + this->aics[param_1].RecruitIntervalWeak = 1; + this->aics[param_1].RecruitInterval = 1; + this->aics[param_1].RecruitIntervalStrong = 1; + this->aics[param_1].SortieUnitRangedMin = 10; + this->aics[param_1].OuterPatrolGroupsMove = 1; + this->aics[param_1].OuterPatrolRallyDelay = 10; + this->aics[param_1].RaidUnitsBase = 10; + this->aics[param_1].AttForceRandom = 10; + this->aics[param_1].recruitProbRaidWeak = 0; + this->aics[param_1].recruitProbRaidStrong = 0x19; + this->aics[param_1].recruitProbAttackWeak = 0; + this->aics[param_1].recruitProbAttackStrong = 0x32; + this->aics[param_1].SortieUnitMeleeMin = 7; + this->aics[param_1].SortieUnitMelee = 0x4b; + this->aics[param_1].DefDiggingUnitMax = 4; + this->aics[param_1].DefDiggingUnit = 0x47; + this->aics[param_1].DefWalls = 0x32; + this->aics[param_1].OuterPatrolGroupsCount = 2; + this->aics[param_1].DefUnit1 = 0x4b; + this->aics[param_1].DefUnit5 = 0x4c; + this->aics[param_1].RaidUnit1 = 0x4a; + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + this->aics[param_1].RaidRetargetDelay = 3; + this->aics[param_1].AttForceBase = 0x32; + this->aics[param_1].recruitProbRaidDefault = 0x21; + this->aics[param_1].recruitProbAttackDefault = 0x21; + this->aics[param_1].SortieUnitRanged = 0x46; + this->aics[param_1].DefTotal = 0x46; + this->aics[param_1].DefUnit2 = 0x46; + this->aics[param_1].DefUnit3 = 0x46; + this->aics[param_1].DefUnit4 = 0x46; + this->aics[param_1].AttForceSupportAllyThreshold = 8; + this->aics[param_1].AttForceRallyPercentage = 0x50; + this->aics[param_1].AttMovingTribesThreshold = 100; + this->aics[param_1].AttAssaultDelay = 4; + this->aics[param_1].AttUnitPatrolRecommandDelay = 1; + this->aics[param_1].AttCoordinationPreference = 0x3c; + this->aics[param_1].CowThrowInterval = 2000; + this->aics[param_1].SiegeEngine1 = 0x4d; + this->aics[param_1].SiegeEngine2 = 0x4d; + this->aics[param_1].SiegeEngine3 = 0x27; + this->aics[param_1].SiegeEngine4 = 0x27; + this->aics[param_1].AttMaxEngineers = 10; + this->aics[param_1].AttDiggingUnit = 0x47; + this->aics[param_1].AttDiggingUnitMax = 0x14; + this->aics[param_1].AttMaxAssassins = 5; + this->aics[param_1].AttUnit2 = 0x4a; + this->aics[param_1].AttUnit2Max = 0x14; + this->aics[param_1].AttMaxLaddermen = 0; + this->aics[param_1].AttMaxTunnelers = 0; + this->aics[param_1].AttUnitPatrol = 0x4a; + this->aics[param_1].AttUnitPatrolMax = 0x14; + this->aics[param_1].AttUnitPatrolGroupsCount = 1; + this->aics[param_1].AttUnitBackup = 0x46; + this->aics[param_1].AttUnitBackupMax = 0x14; + this->aics[param_1].AttUnitBackupGroupsCount = 3; + this->aics[param_1].AttUnitEngageMax = 0; + this->aics[param_1].AttUnitEngage = 0x4c; + this->aics[param_1].AttUnitSiegeDef = 0x4c; + this->aics[param_1].AttUnitSiegeDefMax = 6; + this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; + this->aics[param_1].AttUnitMain1 = 0x4b; + this->aics[param_1].AttMaxDefault = 200; + this->aics[param_1].AttMainGroupsCount = 3; + this->aics[param_1].TargetChoice = AITC_GOLD; + } +} +} From d9d9fd6713def55c7800dfec7357fe26401b6290 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 20 Jul 2026 16:50:53 +0200 Subject: [PATCH 007/242] clang-formatting --- src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp | 8 +- .../addUnitToSmallestBehaviourTypeTribe.cpp | 38 ++++--- .../AICState/addUnitToSmallestPatrolTribe.cpp | 8 +- .../AI/AICState/addUnitsToTribe166.cpp | 16 +-- .../AICState/aiAddUnitToMoatDiggerTribe.cpp | 13 +-- .../AI/AICState/aiAssignMoatDiggers.cpp | 39 +++---- .../AICState/aiAssignUnitToDefensiveTribe.cpp | 5 +- .../aiCommandTribe11StandGroundToGate.cpp | 18 ++-- .../aiCommandTribe13DefensiveWave.cpp | 17 +-- .../AICState/aiCommandWallAssaultTribes.cpp | 15 +-- .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 66 +++++++----- .../AICState/aiReassignTunnelersToTribe.cpp | 12 +-- .../AICState/aiRecruitEngineerForOilDuty.cpp | 62 ++++++----- .../AI/AICState/aiRecruitEngineers.cpp | 25 ++--- .../assignRequiredIdleEngineersToNewTribe.cpp | 27 ++--- .../AI/AICState/assignUnitToATribe.cpp | 18 ++-- src/OpenSHC/AI/AICState/buyGoods.cpp | 14 +-- .../canNavigateUnitsFromTileToTargetTile.cpp | 16 +-- .../AI/AICState/createTribeForUnitType.cpp | 11 +- .../AICState/destroyAnyBuildingInCategory.cpp | 102 ++++++++++-------- .../AI/AICState/destroyBuildingIfNoWorker.cpp | 22 ++-- src/OpenSHC/AI/AICState/digNearestMoat.cpp | 32 +++--- .../AI/AICState/getDefensiveTribeForUnit.cpp | 51 +++++---- .../AICState/hasNoTroopsOrAllAreDiggers.cpp | 32 +++--- .../AI/AICState/hasNotEnoughSupplies.cpp | 22 ++-- .../AICState/ifHasTribe0SendUnitsToKeep.cpp | 5 +- ...qualThanMinimumGoodsRequiredAfterTrade.cpp | 7 +- .../AI/AICState/playAnger1BikFromPlayer.cpp | 19 ++-- .../playAnger2BikFromPlayerToPlayer.cpp | 17 +-- .../playFriendlyVictoryBikFromPlayer.cpp | 9 +- .../playGoodsNotSentBikFromPlayer.cpp | 9 +- .../playGoodsRequestBikFromPlayerToPlayer.cpp | 14 ++- .../playGoodsSentBikFromPlayerToPlayer.cpp | 9 +- .../AI/AICState/playJokeBikFromAIToHuman.cpp | 9 +- .../AI/AICState/playNervous1BikFromPlayer.cpp | 9 +- .../AI/AICState/playNervous2BikFromPlayer.cpp | 12 ++- .../AI/AICState/playNoHelpBikFromPlayer.cpp | 9 +- ...yerKilledBiksFromKilledAndKillerPlayer.cpp | 49 ++++++--- .../AICState/playRequestHelpBikFromPlayer.cpp | 13 ++- ...playTauntToAttackedPlayerBikFromPlayer.cpp | 16 +-- .../AICState/playTeamWinningBikFromPlayer.cpp | 12 ++- .../playThanksBikFromPlayerToPlayer.cpp | 18 ++-- .../playVictory2BikFromPlayerToPlayer.cpp | 25 +++-- .../AI/AICState/recreateEngineersTribe.cpp | 5 +- .../sendAITribe_0xf_toAttackPatrol.cpp | 15 +-- .../AICState/sendTribeAtOffset1ToCampfire.cpp | 5 +- src/OpenSHC/AI/AICState/sendTribeToAttack.cpp | 17 +-- .../AI/AICState/sendUnitsToCampfire.cpp | 7 +- src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp | 9 +- .../AI/AICState/setAttackPrimeInfo.cpp | 15 ++- ...htTribe0xc0TribesToAggressiveAndAttack.cpp | 15 +-- ...x11ToAggressiveAndAttackIfConditionMet.cpp | 19 ++-- .../setTribe0xCtoAggressiveAndAttack.cpp | 17 +-- .../setTribe0xbToAggressiveAndAttack.cpp | 17 +-- .../AICState/shouldDestroyWoodCutterUnk.cpp | 22 ++-- ...rketArmoryGranaryBarracksMercenarypost.cpp | 12 ++- .../AI/AICState/smallestTribeOfUnitType.cpp | 22 ++-- .../AICState/syncBehaviourType7UnitTribes.cpp | 16 +-- .../AI/AICState/teamIsWeakRelativeToEnemy.cpp | 20 ++-- src/OpenSHC/AI/AICState/wipeAICMemory.cpp | 6 +- 60 files changed, 658 insertions(+), 531 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp index 2dcf5a1a0..216be457c 100644 --- a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp @@ -1,11 +1,10 @@ #include "OpenSHC/AI/AICState.func.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -16,7 +15,8 @@ namespace AI { int iVar1 = (int)DAT_UnitsState::instance.units[unitID].owner; if (DAT_GameState::instance.playerDataArray[iVar1].aiType != AITA_NULL) { DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = (short)aiUnitBehaviourType; - iVar1 = MACRO_CALL_MEMBER(AICState_Func::addUnitToSmallestBehaviourTypeTribe, this)(iVar1, unitID, aiUnitBehaviourType); + iVar1 = MACRO_CALL_MEMBER(AICState_Func::addUnitToSmallestBehaviourTypeTribe, this)( + iVar1, unitID, aiUnitBehaviourType); if (iVar1 != 0) { MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); } diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp index 9c0cb83fb..fb1ce9974 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp @@ -1,24 +1,25 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" -#include "OpenSHC/Map/Units/TribesState.func.hpp" - #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CCD20 - int AICState::addUnitToSmallestBehaviourTypeTribe(undefined4 playerID, undefined4 param_2, undefined4 aiUnitBehaviourType) + int AICState::addUnitToSmallestBehaviourTypeTribe( + undefined4 playerID, undefined4 param_2, undefined4 aiUnitBehaviourType) { int _playerID = (int)playerID; int AVar1 = DAT_GameState::instance.playerDataArray[_playerID].aiType; if (AVar1 == AITA_NULL) { return 0; } - int _tribeTypeOffset = DAT_SkirmishDefinedData::instance.DAT_AIUnitBehaviourTypeMapping[(int)aiUnitBehaviourType + -10]; + int _tribeTypeOffset + = DAT_SkirmishDefinedData::instance.DAT_AIUnitBehaviourTypeMapping[(int)aiUnitBehaviourType + -10]; int _smallestTribe = 0; int _smallestTribeOffset = 0; short _smallestTribeSize = 1000; @@ -41,16 +42,18 @@ namespace AI { int _selectedTribe; int _selectedSlot; if (((int)_groupsCount < 1) || (_groupsCount == 1)) { -switchD_004ccd78_caseD_10: - int _tribeID_groupsCount1 = (int)DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_tribeTypeOffset]; - if ((_tribeID_groupsCount1 != 0) && - (DAT_TribesState::instance.tribes[_tribeID_groupsCount1].uid == DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { + switchD_004ccd78_caseD_10: + int _tribeID_groupsCount1 + = (int)DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_tribeTypeOffset]; + if ((_tribeID_groupsCount1 != 0) + && (DAT_TribesState::instance.tribes[_tribeID_groupsCount1].uid + == DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { return _tribeID_groupsCount1; } - _selectedTribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); + _selectedTribe = MACRO_CALL_MEMBER( + Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); _selectedSlot = _tribeTypeOffset; - } - else { + } else { int _maxOffset = _groupsCount + _tribeTypeOffset; _selectedTribe = 0; _selectedSlot = 0; @@ -58,9 +61,11 @@ namespace AI { if (_tribeTypeOffset < _maxOffset) { do { int _tribeID_2 = (int)*_pTribeIDs; - if ((_tribeID_2 == 0) || - (DAT_TribesState::instance.tribes[_tribeID_2].uid != DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { - _selectedTribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); + if ((_tribeID_2 == 0) + || (DAT_TribesState::instance.tribes[_tribeID_2].uid + != DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { + _selectedTribe = MACRO_CALL_MEMBER( + Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); _selectedSlot = _tribeTypeOffset; break; } @@ -79,7 +84,8 @@ namespace AI { } if (0 < _selectedTribe) { DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_selectedSlot] = (short)_selectedTribe; - DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_selectedSlot] = DAT_TribesState::instance.tribes[_selectedTribe].uid; + DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_selectedSlot] + = DAT_TribesState::instance.tribes[_selectedTribe].uid; return _selectedTribe; } return 0; diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp index ef1b52ec1..9a2d04fed 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp @@ -1,11 +1,10 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" -#include "OpenSHC/Map/Units/TribesState.func.hpp" - #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -17,7 +16,8 @@ namespace AI { int _aiType = DAT_GameState::instance.playerDataArray[iVar1].aiType; if (_aiType != AITA_NULL) { DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 4; - iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::getSmallestPatrolTribe, DAT_TribesState::ptr)(iVar1, (int)this->aics[_aiType - 1].OuterPatrolGroupsCount); + iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::getSmallestPatrolTribe, DAT_TribesState::ptr)( + iVar1, (int)this->aics[_aiType - 1].OuterPatrolGroupsCount); MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); } } diff --git a/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp b/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp index 7eedbe481..fa55cb886 100644 --- a/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp +++ b/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp @@ -1,11 +1,10 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -18,12 +17,15 @@ namespace AI { if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { Map::Units::Unit* pUVar1 = &DAT_UnitsState::instance.units[1]; do { - if ((((pUVar1->owner == playerID) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) && - (pUVar1->dying == 0)) && (pUVar1->aiUnitBehaviourType == 6)) { + if ((((pUVar1->owner == playerID) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) + && (pUVar1->dying == 0)) + && (pUVar1->aiUnitBehaviourType == 6)) { tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; if (pUVar1->tribeID != tribeID) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)pUVar1->tribeID); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, (int)pUVar1->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, tribeID); } } unitID = unitID + 1; diff --git a/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp index 857e55933..c9a91b8db 100644 --- a/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp @@ -1,11 +1,10 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -16,9 +15,11 @@ namespace AI { int _owner = (int)DAT_UnitsState::instance.units[unitID].owner; DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 5; int _tribe = (int)DAT_GameState::instance.playerDataArray[_owner].aiTribeIDs[10]; - if ((_tribe == 0) || - (DAT_TribesState::instance.tribes[_tribe].uid != DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10])) { - _tribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_owner); + if ((_tribe == 0) + || (DAT_TribesState::instance.tribes[_tribe].uid + != DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10])) { + _tribe + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_owner); int _uid = DAT_TribesState::instance.tribes[_tribe].uid; DAT_GameState::instance.playerDataArray[_owner].aiTribeIDs[10] = (short)_tribe; DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10] = _uid; diff --git a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp index 037a2f2fe..0cc811666 100644 --- a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp +++ b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp @@ -1,8 +1,7 @@ #include "OpenSHC/AI/AICState.func.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -16,26 +15,28 @@ namespace AI { int _unitID; int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; Map::Units::UnitTypeShort _unitType; - if (((_aiType != AITA_NULL) && (0 < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType0)) && - (_unitID = 1, 1 < (int)DAT_UnitsState::instance.maxUnitCount)) { + if (((_aiType != AITA_NULL) && (0 < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType0)) + && (_unitID = 1, 1 < (int)DAT_UnitsState::instance.maxUnitCount)) { Map::Units::Unit* _ptrUnit = &DAT_UnitsState::instance.units[1]; do { - if ((((((_ptrUnit->logicalState != Map::Units::ULS_INVISIBLE) && (_ptrUnit->owner == playerID)) && - ((_ptrUnit->isSelectable_OR_matchTime != 0 && - ((_ptrUnit->aiUnitBehaviourType == 0 && (_ptrUnit->dying == 0)))))) && - (_unitType = _ptrUnit->unitType, _unitType != Map::Units::UT_LORD)) && - ((((_unitType != Map::Units::UT_E_ENGINEER && (_unitType != Map::Units::UT_TUNNELER)) && - (_unitType != Map::Units::UT_S_CATAPULT)) && - ((_unitType != Map::Units::UT_S_TREBUCHET && (_unitType != Map::Units::UT_S_MANGONEL)))))) && - (((_unitType != Map::Units::UT_S_TOWER && - ((_unitType != Map::Units::UT_S_BATTERINGRAM && (_unitType != Map::Units::UT_S_SHIELD)))) && - ((_unitType != Map::Units::UT_S_BALLISTA && (_unitType != Map::Units::UT_S_FBALLISTA)))))) { - if (((((int)this->aics[_aiType - 1].DefDiggingUnitMax == 0) || - (_unitType == Map::Units::UT_E_ARCHER)) || (_unitType == Map::Units::UT_E_XBOW)) || - (_ptrUnit->someUnitStat4 == 0)) { + if ((((((_ptrUnit->logicalState != Map::Units::ULS_INVISIBLE) && (_ptrUnit->owner == playerID)) + && ((_ptrUnit->isSelectable_OR_matchTime != 0 + && ((_ptrUnit->aiUnitBehaviourType == 0 && (_ptrUnit->dying == 0)))))) + && (_unitType = _ptrUnit->unitType, _unitType != Map::Units::UT_LORD)) + && ((((_unitType != Map::Units::UT_E_ENGINEER && (_unitType != Map::Units::UT_TUNNELER)) + && (_unitType != Map::Units::UT_S_CATAPULT)) + && (( + _unitType != Map::Units::UT_S_TREBUCHET && (_unitType != Map::Units::UT_S_MANGONEL)))))) + && (( + (_unitType != Map::Units::UT_S_TOWER + && ((_unitType != Map::Units::UT_S_BATTERINGRAM && (_unitType != Map::Units::UT_S_SHIELD)))) + && ((_unitType != Map::Units::UT_S_BALLISTA && (_unitType != Map::Units::UT_S_FBALLISTA)))))) { + if (((((int)this->aics[_aiType - 1].DefDiggingUnitMax == 0) + || (_unitType == Map::Units::UT_E_ARCHER)) + || (_unitType == Map::Units::UT_E_XBOW)) + || (_ptrUnit->someUnitStat4 == 0)) { MACRO_CALL_MEMBER(AICState_Func::assignUnitToATribe, this)(_unitID); - } - else { + } else { MACRO_CALL_MEMBER(AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); } } diff --git a/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp index 22cda9ad7..cd5bb7b90 100644 --- a/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp @@ -1,11 +1,10 @@ #include "OpenSHC/AI/AICState.func.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp index 6057d9080..7001fe9cf 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp @@ -1,7 +1,6 @@ +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TroopValueState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -16,14 +15,17 @@ namespace AI { { int iVar1; int iVar2; - if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], iVar2 != 0)) && - (DAT_TribesState::instance.tribes[iVar2].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb])) && - (DAT_TribesState::instance.tribes[iVar2].selectionTargetUnitID != 0)) { + if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], iVar2 != 0)) + && (DAT_TribesState::instance.tribes[iVar2].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb])) + && (DAT_TribesState::instance.tribes[iVar2].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[iVar2].unitStance = Map::Units::Behavior::USE_STAND_GROUND; - iVar1 = MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)(iVar2); + iVar1 = MACRO_CALL_MEMBER( + Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)(iVar2); if (iVar1 == 0) { - MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)(iVar2); + MACRO_CALL_MEMBER( + Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)(iVar2); } } } diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp index 5f9524b07..c28d2776b 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -15,12 +14,14 @@ namespace AI { void AICState::aiCommandTribe13DefensiveWave(int param_1) { int tribeID; - if ((DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) && - (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xd], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xd]) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if ((DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xd], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xd]) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f4); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f4); } } } diff --git a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp index 55c81532f..fe11b9a93 100644 --- a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -22,11 +21,13 @@ namespace AI { psVar2 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + 0xbe; do { tribeID = (int)*psVar2; - if (((tribeID != 0) && - (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar1 + 0xbe])) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if (((tribeID != 0) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar1 + 0xbe])) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f2); } iVar1 = iVar1 + 1; psVar2 = psVar2 + 1; diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp index 75dc1e348..20b5496f0 100644 --- a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -1,11 +1,10 @@ #include "OpenSHC/AI/AICState.func.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" -#include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" namespace OpenSHC { @@ -31,45 +30,56 @@ namespace AI { _aicOffset = (_aiType + -1) * 0x2a4; _count = (int)this->aics[_aiType - 1].OuterPatrolGroupsCount; _index = 0; - if (((0 < _count) && - (piVar1 = &DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker, - *piVar1 = *piVar1 + 1, - (int)this->aics[_aiType - 1].OuterPatrolRallyDelay <= DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker)) && - (DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker = 0, 0 < _count)) { + if (((0 < _count) + && (piVar1 = &DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker, + *piVar1 = *piVar1 + 1, + (int)this->aics[_aiType - 1].OuterPatrolRallyDelay + <= DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker)) + && (DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker = 0, 0 < _count)) { psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; do { _tribeID = (int)*psVar4; DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - if (((_tribeID != 0) && - (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0xaa])) && - ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0xb && - ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk < 0xb && - (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk < 0xb)))))) { - if (((int)this->aics[_aiType - 1].OuterPatrolGroupsMove == 0) || - (_buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)(playerID, _index), - _buildingID == 0)) { - _buildingID2 = MACRO_CALL_MEMBER(AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); - if (_buildingID2 == 0) goto LAB_004d2a44; - _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryX + - DAT_ViewportRenderState::instance.translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryY].addXgetTile; - } - else { - _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + - DAT_ViewportRenderState::instance.translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryY].addXgetTile; + if (((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0xaa])) + && ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0xb + && ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk < 0xb + && (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk < 0xb)))))) { + if (((int)this->aics[_aiType - 1].OuterPatrolGroupsMove == 0) + || (_buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)( + playerID, _index), + _buildingID == 0)) { + _buildingID2 = MACRO_CALL_MEMBER( + AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + if (_buildingID2 == 0) + goto LAB_004d2a44; + _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID2] + .buildingEntryY] + .addXgetTile; + } else { + _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] + .buildingEntryY] + .addXgetTile; } if (_tile != 0) { sVar2 = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; iVar3 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; - _canNavigate = MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(_tribeID, _tile); + _canNavigate = MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( + _tribeID, _tile); if (_canNavigate == FALSE) { MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); - } - else { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(_tribeID, _tile - iVar3, (int)sVar2, 0); + } else { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, + DAT_TribesState::ptr)(_tribeID, _tile - iVar3, (int)sVar2, 0); } } } -LAB_004d2a44: + LAB_004d2a44: _index = _index + 1; psVar4 = psVar4 + 1; } while (_index < _count); diff --git a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp index 640f619e3..3c745352a 100644 --- a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp @@ -1,12 +1,11 @@ #include "OpenSHC/AI/AICState.func.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -18,11 +17,12 @@ namespace AI { if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { Map::Units::Unit* psVar1 = &DAT_UnitsState::instance.units[1]; do { - if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == param_1)) && - (psVar1->dying == 0)) && - ((psVar1->unitType == Map::Units::UT_TUNNELER && (psVar1->aiUnitBehaviourType == 0xf)))) { + if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == param_1)) + && (psVar1->dying == 0)) + && ((psVar1->unitType == Map::Units::UT_TUNNELER && (psVar1->aiUnitBehaviourType == 0xf)))) { if (psVar1->tribeID != 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)psVar1->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, (int)psVar1->tribeID); } MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 0xf); } diff --git a/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp index 7379a3ed6..c96ca96b9 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp @@ -1,20 +1,19 @@ +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" - -#include "OpenSHC/Global.func.hpp" -#include "OpenSHC/Map/Units/UnitsState.func.hpp" -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Map/Units/UnitInstructionType.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" -#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -28,31 +27,44 @@ namespace AI { int _amount; int _oilSmelter; int _buildingUID; - if (((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (_newTribe = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, - DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) && - (29 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf])) && - ((0 < _newTribe && (DAT_BuildingsState::instance.buildings[_newTribe].buildingType == Map::Buildings::BT_ENGINEERSGUILD)))) && - ((_oilSmelter = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id, 0 < _oilSmelter && - ((DAT_BuildingsState::instance.buildings[_oilSmelter].buildingType == Map::Buildings::BT_OILSMELTER && - (_amount = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1] + 1, 1 < _amount)))))) { - if ((DAT_BuildingsState::instance.buildings[_oilSmelter].resourcePitch < 1) && - (DAT_GameState::instance.playerDataArray[playerID].currentResources[7] < 1)) { + if (((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (_newTribe = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, + DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) + && (29 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf])) + && ((0 < _newTribe + && (DAT_BuildingsState::instance.buildings[_newTribe].buildingType + == Map::Buildings::BT_ENGINEERSGUILD)))) + && ((_oilSmelter = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id, + 0 < _oilSmelter + && ((DAT_BuildingsState::instance.buildings[_oilSmelter].buildingType + == Map::Buildings::BT_OILSMELTER + && (_amount + = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1] + 1, + 1 < _amount)))))) { + if ((DAT_BuildingsState::instance.buildings[_oilSmelter].resourcePitch < 1) + && (DAT_GameState::instance.playerDataArray[playerID].currentResources[7] < 1)) { DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[7] = 4; return; } - _hasTribes = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)(playerID, _amount, TRUE); + _hasTribes + = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)(playerID, _amount, TRUE); if (_hasTribes != FALSE) { - _newTribe = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)(playerID, _amount, FALSE); - _unitID = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)(Map::Units::UT_E_ENGINEER, DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, playerID, 0); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(_unitID, _newTribe); + _newTribe = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)( + playerID, _amount, FALSE); + _unitID = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + Map::Units::UT_E_ENGINEER, DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, + playerID, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + _unitID, _newTribe); if (_unitID != 0) { DAT_UnitsState::instance.units[_unitID].engineerRelatedUnk = 1; DAT_TribesState::instance.tribes[_newTribe].unitStance = Map::Units::Behavior::USE_DEFENSIVE; _buildingUID = DAT_BuildingsState::instance.buildings[_oilSmelter].uid; DAT_TribesState::instance.tribes[_newTribe].tribeType = Tribes::AITT_ENGINEERS; DAT_TribesState::instance.tribes[_newTribe].tribeBehaviorType = Map::Units::STBT_0x41d; - MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(_newTribe, Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _oilSmelter, _buildingUID, 0); + MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + _newTribe, Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _oilSmelter, + _buildingUID, 0); } } } diff --git a/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp b/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp index 7af062fb0..c42651eeb 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp @@ -1,12 +1,11 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/UnitsState.func.hpp" -#include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { @@ -17,14 +16,16 @@ namespace AI { { int recruitmentBuilding; int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if ((((_aiType != AITA_NULL) && - (DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired != FALSE)) && - (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) && - (((0x1d < (int)this->aics[_aiType - 1].recruitGoldThreshold + DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] && - (recruitmentBuilding = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, - 0 < recruitmentBuilding)) && - (DAT_BuildingsState::instance.buildings[recruitmentBuilding].buildingType == Map::Buildings::BT_ENGINEERSGUILD)))) { - MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)(Map::Units::UT_E_ENGINEER, recruitmentBuilding, playerID, 0); + if ((((_aiType != AITA_NULL) && (DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired != FALSE)) + && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) + && (((0x1d < (int)this->aics[_aiType - 1].recruitGoldThreshold + + DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] + && (recruitmentBuilding = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, + 0 < recruitmentBuilding)) + && (DAT_BuildingsState::instance.buildings[recruitmentBuilding].buildingType + == Map::Buildings::BT_ENGINEERSGUILD)))) { + MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + Map::Units::UT_E_ENGINEER, recruitmentBuilding, playerID, 0); DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = FALSE; } } diff --git a/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp index aeb6e8986..d1f3f4888 100644 --- a/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp +++ b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp @@ -1,13 +1,12 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Map/Units/States/UnitState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -16,7 +15,8 @@ namespace AI { int AICState::assignRequiredIdleEngineersToNewTribe(int playerID, int count) { Map::Units::States::UnitStateShort UVar1; - int tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + int tribeID + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); uint unitID = 1; if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { Map::Units::Unit* psVar2 = &DAT_UnitsState::instance.units[1]; @@ -24,15 +24,18 @@ namespace AI { if (count < 1) { return tribeID; } - if (((((psVar2->logicalState == Map::Units::ULS_NORMAL) && (psVar2->owner == playerID)) && - (psVar2->dying == 0)) && - ((psVar2->unitType == Map::Units::UT_E_ENGINEER && (psVar2->aiUnitBehaviourType != 0x16)))) && - ((psVar2->aiUnitBehaviourType != 10 && (psVar2->engineerRelatedUnk == 0))) && - (((UVar1 = (psVar2->state).generic, UVar1 == 0x69 || (UVar1 == 2)) || (UVar1 == Map::Units::States::US_IDLEUnk)))) { + if (((((psVar2->logicalState == Map::Units::ULS_NORMAL) && (psVar2->owner == playerID)) + && (psVar2->dying == 0)) + && ((psVar2->unitType == Map::Units::UT_E_ENGINEER && (psVar2->aiUnitBehaviourType != 0x16)))) + && ((psVar2->aiUnitBehaviourType != 10 && (psVar2->engineerRelatedUnk == 0))) + && (((UVar1 = (psVar2->state).generic, UVar1 == 0x69 || (UVar1 == 2)) + || (UVar1 == Map::Units::States::US_IDLEUnk)))) { if (psVar2->tribeID != 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)psVar2->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, (int)psVar2->tribeID); } - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, tribeID); count = count + -1; } unitID = unitID + 1; diff --git a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp index 383a4e51c..5cbcef48a 100644 --- a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp +++ b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp @@ -1,12 +1,11 @@ #include "OpenSHC/AI/AICState.func.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Global.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -20,21 +19,22 @@ namespace AI { int _playerID = (int)DAT_UnitsState::instance.units[unitID].owner; if (DAT_GameState::instance.playerDataArray[_playerID].aiType != AITA_NULL) { int iVar1; - if ((DAT_GameState::instance.playerDataArray[_playerID].aivCurrentPauseIndex == 1) && - (0 < DAT_GameState::instance.playerDataArray[_playerID].aivPauses[1])) { + if ((DAT_GameState::instance.playerDataArray[_playerID].aivCurrentPauseIndex == 1) + && (0 < DAT_GameState::instance.playerDataArray[_playerID].aivPauses[1])) { iVar1 = 1; - } - else { + } else { iVar1 = 0; } _unitTypeIndex = (short*)MACRO_CALL(Global_Func::GetUnitTypeIndexForUnitID)(unitID, iVar1); - int _tribeSize = DAT_GameState::instance.playerDataArray[_playerID].aivUnitLocationSlotLocationCount[(int)_unitTypeIndex]; + int _tribeSize = DAT_GameState::instance.playerDataArray[_playerID] + .aivUnitLocationSlotLocationCount[(int)_unitTypeIndex]; DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 1; if (_tribeSize < 1) { _isOfType = MACRO_CALL_MEMBER(AICState_Func::unitIDIsRangedOrArmored, this)(unitID); if (_isOfType != 0) { _tribeID = MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(_playerID, 0); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, _tribeID); return; } _tribeID = MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(_playerID, 1); diff --git a/src/OpenSHC/AI/AICState/buyGoods.cpp b/src/OpenSHC/AI/AICState/buyGoods.cpp index d27a0501e..404228645 100644 --- a/src/OpenSHC/AI/AICState/buyGoods.cpp +++ b/src/OpenSHC/AI/AICState/buyGoods.cpp @@ -1,10 +1,9 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { @@ -12,14 +11,17 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC000 BOOLEnum AICState::buyGoods(int playerID, ResourceType resourceType, int amount) { - int _cost = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::getBuyPrice, DAT_GameState::ptr)(playerID, resourceType, amount); - BOOLEnum _gain = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::processResourceGain, DAT_BuildingsState::ptr)(playerID, resourceType, amount); + int _cost = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::getBuyPrice, DAT_GameState::ptr)( + playerID, resourceType, amount); + BOOLEnum _gain = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::processResourceGain, + DAT_BuildingsState::ptr)(playerID, resourceType, amount); if (_gain != FALSE) { int* piVar1 = DAT_GameState::instance.playerDataArray[playerID].currentResources + 0xf; *piVar1 = *piVar1 - _cost; piVar1 = &DAT_GameState::instance.playerDataArray[playerID].marketGold; *piVar1 = *piVar1 - _cost; - MACRO_CALL_MEMBER(Game::GameStateStructures_Func::displayPlayerTradeVisualEffect, DAT_GameState::ptr)(playerID, 0, amount, resourceType); + MACRO_CALL_MEMBER(Game::GameStateStructures_Func::displayPlayerTradeVisualEffect, DAT_GameState::ptr)( + playerID, 0, amount, resourceType); return TRUE; } return FALSE; diff --git a/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp index 8b18080b6..b68d96055 100644 --- a/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp +++ b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp @@ -1,10 +1,9 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_PathFindingState.hpp" -#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { @@ -13,11 +12,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CD250 BOOLEnum AICState::canNavigateUnitsFromTileToTargetTile(int tribeID, int tile) { - int iVar1 = MACRO_CALL_MEMBER(Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)( - DAT_TribesState::instance.tribes[tribeID].owner, - (int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID].tile], - (int)(short)DAT_TileMapState::instance.PathConnectionLayer[tile], - 0); + int iVar1 = MACRO_CALL_MEMBER( + Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[tribeID].owner, + (int)(short)DAT_TileMapState::instance.PathConnectionLayer + [DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID].tile], + (int)(short)DAT_TileMapState::instance.PathConnectionLayer[tile], 0); return (uint)(iVar1 != 0); } } diff --git a/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp b/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp index 11260ee9e..f161e8f1d 100644 --- a/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp +++ b/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp @@ -1,6 +1,5 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -13,9 +12,11 @@ namespace AI { { short* psVar1 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + unitSelectionTypeIndex; int _tribeID = (int)*psVar1; - if ((_tribeID == 0) || - (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex])) { - _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + if ((_tribeID == 0) + || (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex])) { + _tribeID + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; *psVar1 = (short)_tribeID; DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex] = _tribeUID; diff --git a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp index 88bab103f..55622a561 100644 --- a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp +++ b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp @@ -1,8 +1,7 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" -#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" @@ -20,79 +19,90 @@ namespace AI { if (1 < DAT_BuildingsState::instance.maxBuildingsCount) { Map::Buildings::Building* pBVar2 = &DAT_BuildingsState::instance.buildings[1]; do { - if (((pBVar2->logicalState != 0) && (pBVar2->logicalState != Map::Buildings::BLS_REMOVE)) && - (pBVar2->owner == playerID)) { + if (((pBVar2->logicalState != 0) && (pBVar2->logicalState != Map::Buildings::BLS_REMOVE)) + && (pBVar2->owner == playerID)) { if (buildingCategory == AINDBC_FEAR_FACTOR_BUILDINGS) { BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_CESSPIT) && (BVar1 != Map::Buildings::BT_BURNINGSTAKE)) && - (((BVar1 != Map::Buildings::BT_GIBBET && - (((BVar1 != Map::Buildings::BT_DUNGEON && (BVar1 != Map::Buildings::BT_STRETCHINGRACK)) && (BVar1 != Map::Buildings::BT_RACKFLOGGING)))) && - (((BVar1 != Map::Buildings::BT_CHOPPINGBLOCK && (BVar1 != Map::Buildings::BT_DUNKINGSTOOL)) && - ((BVar1 != Map::Buildings::BT_DOGCAGE && - (((BVar1 != Map::Buildings::BT_STATUE && (BVar1 != Map::Buildings::BT_SHRINE)) && - ((BVar1 != Map::Buildings::BT_DANCINGBEAR && - ((((BVar1 != Map::Buildings::BT_POND && (BVar1 != Map::Buildings::BT_GALLOWS)) && (BVar1 != Map::Buildings::BT_STOCKS)) && - ((BVar1 != Map::Buildings::BT_WITCHHOIST && (BVar1 != Map::Buildings::BT_MAYPOLE)))))))))))))))) { + if (((BVar1 != Map::Buildings::BT_CESSPIT) && (BVar1 != Map::Buildings::BT_BURNINGSTAKE)) + && (((BVar1 != Map::Buildings::BT_GIBBET + && (((BVar1 != Map::Buildings::BT_DUNGEON + && (BVar1 != Map::Buildings::BT_STRETCHINGRACK)) + && (BVar1 != Map::Buildings::BT_RACKFLOGGING)))) + && (((BVar1 != Map::Buildings::BT_CHOPPINGBLOCK + && (BVar1 != Map::Buildings::BT_DUNKINGSTOOL)) + && ((BVar1 != Map::Buildings::BT_DOGCAGE + && (( + (BVar1 != Map::Buildings::BT_STATUE && (BVar1 != Map::Buildings::BT_SHRINE)) + && ((BVar1 != Map::Buildings::BT_DANCINGBEAR + && ((((BVar1 != Map::Buildings::BT_POND + && (BVar1 != Map::Buildings::BT_GALLOWS)) + && (BVar1 != Map::Buildings::BT_STOCKS)) + && ((BVar1 != Map::Buildings::BT_WITCHHOIST + && (BVar1 != Map::Buildings::BT_MAYPOLE)))))))))))))))) { bVar2 = BVar1 == Map::Buildings::BT_GARDEN; goto LAB_004d04de; } - } - else if (buildingCategory == AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS) { + } else if (buildingCategory == AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS) { BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_FLETCHER) && (BVar1 != Map::Buildings::BT_BLACKSMITH)) && - (((BVar1 != Map::Buildings::BT_POLETURNER && - (((BVar1 != Map::Buildings::BT_ARMOURER && (BVar1 != Map::Buildings::BT_TANNER)) && (BVar1 != Map::Buildings::BT_INN)))) && - (((BVar1 != Map::Buildings::BT_APOTHECARY && (BVar1 != Map::Buildings::BT_CHAPEL)) && (BVar1 != Map::Buildings::BT_CHURCH)))))) { + if (((BVar1 != Map::Buildings::BT_FLETCHER) && (BVar1 != Map::Buildings::BT_BLACKSMITH)) + && (((BVar1 != Map::Buildings::BT_POLETURNER + && (((BVar1 != Map::Buildings::BT_ARMOURER && (BVar1 != Map::Buildings::BT_TANNER)) + && (BVar1 != Map::Buildings::BT_INN)))) + && (((BVar1 != Map::Buildings::BT_APOTHECARY && (BVar1 != Map::Buildings::BT_CHAPEL)) + && (BVar1 != Map::Buildings::BT_CHURCH)))))) { bVar2 = BVar1 == Map::Buildings::BT_CATHEDRAL; goto LAB_004d04de; } - } - else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) { + } else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) { BVar1 = pBVar2->buildingType; - if (((((BVar1 != Map::Buildings::BT_GATEHOUSELARGE) && (BVar1 != Map::Buildings::BT_GATEHOUSESMALL)) && - ((BVar1 != Map::Buildings::BT_DRAWBRIDGE && - ((((BVar1 != Map::Buildings::BT_TOWER1 && (BVar1 != Map::Buildings::BT_TOWER2)) && (BVar1 != Map::Buildings::BT_TOWER3)) && - ((BVar1 != Map::Buildings::BT_TOWER4 && (BVar1 != Map::Buildings::BT_TOWER5)))))))) && (BVar1 != Map::Buildings::BT_ENGINEERSGUILD)) && - (BVar1 != Map::Buildings::BT_TUNNELERSGUILD)) { + if (((((BVar1 != Map::Buildings::BT_GATEHOUSELARGE) + && (BVar1 != Map::Buildings::BT_GATEHOUSESMALL)) + && ((BVar1 != Map::Buildings::BT_DRAWBRIDGE + && ((((BVar1 != Map::Buildings::BT_TOWER1 && (BVar1 != Map::Buildings::BT_TOWER2)) + && (BVar1 != Map::Buildings::BT_TOWER3)) + && ((BVar1 != Map::Buildings::BT_TOWER4 + && (BVar1 != Map::Buildings::BT_TOWER5)))))))) + && (BVar1 != Map::Buildings::BT_ENGINEERSGUILD)) + && (BVar1 != Map::Buildings::BT_TUNNELERSGUILD)) { bVar2 = BVar1 == Map::Buildings::BT_OILSMELTER; goto LAB_004d04de; } - } - else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) { + } else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) { BVar1 = pBVar2->buildingType; if ((BVar1 != Map::Buildings::BT_MERCENARYPOST) && (BVar1 != Map::Buildings::BT_BARRACKS)) { bVar2 = BVar1 == Map::Buildings::BT_STABLES; goto LAB_004d04de; } - } - else if (buildingCategory == AINDBC_WATER_BUILDINGS) { + } else if (buildingCategory == AINDBC_WATER_BUILDINGS) { if (pBVar2->buildingType != Map::Buildings::BT_WELL) { bVar2 = pBVar2->buildingType == Map::Buildings::BT_WATERPOT; goto LAB_004d04de; } - } - else if (buildingCategory == AINDBC_RESOURCE_BUILDINGS) { + } else if (buildingCategory == AINDBC_RESOURCE_BUILDINGS) { BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_OXTETHER) && (BVar1 != Map::Buildings::BT_IRONMINE)) && - ((BVar1 != Map::Buildings::BT_PITCHRIG && - (((BVar1 != Map::Buildings::BT_BAKERY && (BVar1 != Map::Buildings::BT_BREWERY)) && (BVar1 != Map::Buildings::BT_QUARRY)))))) { + if (((BVar1 != Map::Buildings::BT_OXTETHER) && (BVar1 != Map::Buildings::BT_IRONMINE)) + && ((BVar1 != Map::Buildings::BT_PITCHRIG + && (((BVar1 != Map::Buildings::BT_BAKERY && (BVar1 != Map::Buildings::BT_BREWERY)) + && (BVar1 != Map::Buildings::BT_QUARRY)))))) { bVar2 = BVar1 == Map::Buildings::BT_MILL; -LAB_004d04de: - if (!bVar2) goto LAB_004d04f9; + LAB_004d04de: + if (!bVar2) + goto LAB_004d04f9; } - } - else { - if (((buildingCategory == AINDBC_FARMS) && - (BVar1 = pBVar2->buildingType, BVar1 != Map::Buildings::BT_WHEATFARM)) && - ((BVar1 != Map::Buildings::BT_HOPFARM && (BVar1 != Map::Buildings::BT_APPLEFARM)))) { + } else { + if (((buildingCategory == AINDBC_FARMS) + && (BVar1 = pBVar2->buildingType, BVar1 != Map::Buildings::BT_WHEATFARM)) + && ((BVar1 != Map::Buildings::BT_HOPFARM && (BVar1 != Map::Buildings::BT_APPLEFARM)))) { bVar2 = BVar1 == Map::Buildings::BT_DAIRYFARM; goto LAB_004d04de; } } - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_buildingID); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( + _buildingID); } -LAB_004d04f9: + LAB_004d04f9: _buildingID = _buildingID + 1; pBVar2 = pBVar2 + 1; } while (_buildingID < DAT_BuildingsState::instance.maxBuildingsCount); diff --git a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp index 97c182d7a..85d25c03d 100644 --- a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp +++ b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp @@ -1,13 +1,12 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/AI/AIVState.func.hpp" #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Globals/DAT_AIVState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" -#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" namespace OpenSHC { namespace AI { @@ -17,20 +16,21 @@ namespace AI { { short _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; int _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; - if ((((0 < _value) && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1)) && - (DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0)) && - (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY)) { + if ((((0 < _value) && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1)) + && (DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0)) + && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY)) { if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] == 0) { if (0x13 < _value) { MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(buildingID); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( + buildingID); return 1; } - } - else if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { + } else if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = _value + -1; } } diff --git a/src/OpenSHC/AI/AICState/digNearestMoat.cpp b/src/OpenSHC/AI/AICState/digNearestMoat.cpp index c734a3ff9..9187b70c5 100644 --- a/src/OpenSHC/AI/AICState/digNearestMoat.cpp +++ b/src/OpenSHC/AI/AICState/digNearestMoat.cpp @@ -1,13 +1,12 @@ #include "OpenSHC/AI/AICState.func.hpp" - +#include "OpenSHC/Map/TileMapState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/UnitInstructionType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" -#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { @@ -19,22 +18,29 @@ namespace AI { int iVar1; BOOLEnum tile; int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10]; - if ((((tribeID != 0) && - (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10])) && - (0 < DAT_TribesState::instance.tribes[tribeID].size)) && - (DAT_TribesState::instance.tribes[tribeID].percentageSomething < 0x51)) { - iVar1 = MACRO_CALL_MEMBER(Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)(playerID); + if ((((tribeID != 0) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10])) + && (0 < DAT_TribesState::instance.tribes[tribeID].size)) + && (DAT_TribesState::instance.tribes[tribeID].percentageSomething < 0x51)) { + iVar1 = MACRO_CALL_MEMBER(Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)( + playerID); if (iVar1 < 1) { MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); return; } iVar1 = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; - tile = MACRO_CALL_MEMBER(Map::TileMapState_Func::findNearestFriendlyMoatTileForDigging, DAT_TileMapState::ptr)(playerID, iVar1, 1); + tile = MACRO_CALL_MEMBER(Map::TileMapState_Func::findNearestFriendlyMoatTileForDigging, + DAT_TileMapState::ptr)(playerID, iVar1, 1); if (-1 < (int)tile) { - MACRO_CALL_MEMBER(Map::TileMapState_Func::setXYBasedOnMoatID, DAT_TileMapState::ptr)(tile, 1, (int)DAT_UnitsState::instance.units[iVar1].x, (int)DAT_UnitsState::instance.units[iVar1].y); - iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::updateTribeRallyFlags, DAT_TribesState::ptr)(tribeID); + MACRO_CALL_MEMBER(Map::TileMapState_Func::setXYBasedOnMoatID, DAT_TileMapState::ptr)(tile, 1, + (int)DAT_UnitsState::instance.units[iVar1].x, (int)DAT_UnitsState::instance.units[iVar1].y); + iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::updateTribeRallyFlags, DAT_TribesState::ptr)( + tribeID); if (iVar1 == 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(tribeID, Map::Units::UIT_DIG_MOAT, DAT_TileMapState::instance.ALG_MoatXResult, DAT_TileMapState::instance.ALG_MoatYResult, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( + tribeID, Map::Units::UIT_DIG_MOAT, DAT_TileMapState::instance.ALG_MoatXResult, + DAT_TileMapState::instance.ALG_MoatYResult, 0); DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_STAND_GROUND; } } diff --git a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp index 7aaa535d8..0007cf995 100644 --- a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp +++ b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp @@ -1,12 +1,11 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" -#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" namespace OpenSHC { namespace AI { @@ -18,26 +17,27 @@ namespace AI { int _unitType = (int)(short)DAT_UnitsState::instance.units[unitID].unitType; int _unitType2; do { - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index]) || - (_unitType2 = (int)(short)DAT_UnitsState::instance.units[unitID].unitTypeToChangeInto, - _unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index])) break; - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1]) || - (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1])) { + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index]) + || (_unitType2 = (int)(short)DAT_UnitsState::instance.units[unitID].unitTypeToChangeInto, + _unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index])) + break; + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1]) + || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1])) { _index = _index + 1; break; } - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2]) || - (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2])) { + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2]) + || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2])) { _index = _index + 2; break; } - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3]) || - (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3])) { + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3]) + || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3])) { _index = _index + 3; break; } - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4]) || - (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4])) { + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4]) + || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4])) { _index = _index + 4; break; } @@ -46,20 +46,15 @@ namespace AI { int _tribeIndex; if (_index < 1) { _tribeIndex = 0xb4; - } - else if (_index < 2) { + } else if (_index < 2) { _tribeIndex = 0xb5; - } - else if (_index < 7) { + } else if (_index < 7) { _tribeIndex = 0xb6; - } - else if (_index < 0xc) { + } else if (_index < 0xc) { _tribeIndex = 0xb7; - } - else if (_index < 0xf) { + } else if (_index < 0xf) { _tribeIndex = 0xb8; - } - else { + } else { if (19 < _index) { return 0; } @@ -67,9 +62,11 @@ namespace AI { } short* _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeIndex; int _tribeID = (int)*_pTribeID; - if ((_tribeID == 0) || - (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex])) { - _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + if ((_tribeID == 0) + || (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex])) { + _tribeID + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; *_pTribeID = (short)_tribeID; DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex] = _tribeUID; diff --git a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp index b4f0895ac..32fca0836 100644 --- a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp +++ b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp @@ -16,37 +16,33 @@ namespace AI { int _totalBackupLate; int _totalBackupLate2; - _total1 = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + - DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + - DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops; + _total1 = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + + DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops; _halfOfDiggingTroops = 0; if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState == 6) { if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 17) { _totalBackup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - } - else { + } else { _totalBackupLate = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; _totalBackup = (int)(_totalBackupLate + (_totalBackupLate >> 0x1f & 7U)) >> 3; } - _totalTroops = _total1 + DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops + - _totalBackup + - DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + - DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + - DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; - } - else { + _totalTroops = _total1 + DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops + + _totalBackup + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + } else { _halfOfDiggingTroops = DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops / 2; if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 13) { _totalBackup2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - } - else { + } else { _totalBackupLate2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; _totalBackup2 = (int)(_totalBackupLate2 + (_totalBackupLate2 >> 0x1f & 7U)) >> 3; } - _totalTroops = _total1 + _totalBackup2 + - DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + - DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + - DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + _totalTroops = _total1 + _totalBackup2 + + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; } if ((1 < _totalTroops) && ((4 < _totalTroops || (_halfOfDiggingTroops <= _totalTroops * 2)))) { return FALSE; diff --git a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp index 0f772a912..8a56546ea 100644 --- a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp +++ b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp @@ -1,7 +1,7 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { @@ -10,15 +10,17 @@ namespace AI { BOOLEnum AICState::hasNotEnoughSupplies(int playerID) { BOOLEnum BVar1 = TRUE; - if (((((DAT_GameState::instance.playerDataArray[playerID].marketplace.id != 0) || - (DAT_BuildingsState::instance.buildingCosts[0x1a].requiredWood <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) || - (0 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)) && - (((DAT_GameState::instance.playerDataArray[playerID].granary.id != 0 || - (DAT_BuildingsState::instance.buildingCosts[0x13].requiredWood <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) || - (1 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)))) && - (((0 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] || - (25 < DAT_GameState::instance.playerDataArray[playerID].popularity)) || - (0 < DAT_GameState::instance.playerDataArray[playerID].totalFood)))) { + if (((((DAT_GameState::instance.playerDataArray[playerID].marketplace.id != 0) + || (DAT_BuildingsState::instance.buildingCosts[0x1a].requiredWood + <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) + || (0 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)) + && (((DAT_GameState::instance.playerDataArray[playerID].granary.id != 0 + || (DAT_BuildingsState::instance.buildingCosts[0x13].requiredWood + <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) + || (1 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)))) + && (((0 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] + || (25 < DAT_GameState::instance.playerDataArray[playerID].popularity)) + || (0 < DAT_GameState::instance.playerDataArray[playerID].totalFood)))) { BVar1 = FALSE; } return BVar1; diff --git a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp index fb68e2842..b118a2cce 100644 --- a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp +++ b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp @@ -10,8 +10,9 @@ namespace AI { void AICState::ifHasTribe0SendUnitsToKeep(int playerID) { int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0]; - if ((0 < tribeID) && - (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0])) { + if ((0 < tribeID) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0])) { MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); } } diff --git a/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp b/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp index 6dd67d991..9b2058928 100644 --- a/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp +++ b/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp @@ -1,6 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Game/Resources/ResourceType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -9,7 +8,8 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0520 - BOOLEnum AICState::isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade(int playerID, ResourceType resourceType, int buffer) + BOOLEnum AICState::isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade( + int playerID, ResourceType resourceType, int buffer) { int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (_aiType == AITA_NULL) { @@ -18,7 +18,8 @@ namespace AI { if (resourceType == Game::Resources::RT_GOLD) { return FALSE; } - return (int)this->aics[_aiType - 1].minimumGoodsRequiredAfterTrade + buffer <= DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType]; + return (int)this->aics[_aiType - 1].minimumGoodsRequiredAfterTrade + buffer + <= DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType]; } } } diff --git a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp index 4f4662e1d..d544ada7d 100644 --- a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -15,15 +14,21 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0830 void AICState::playAnger1BikFromPlayer(int playerID) { - int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar2 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar2 != 0) { int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] != DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) && - (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { + if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] + != DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) + && (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID + == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { DWORD DVar3 = timeGetTime(); - if ((INT_ARRAY_00eb0af0::instance[playerID] == 0) || (599999 < DVar3 - INT_ARRAY_00eb0af0::instance[playerID])) { + if ((INT_ARRAY_00eb0af0::instance[playerID] == 0) + || (599999 < DVar3 - INT_ARRAY_00eb0af0::instance[playerID])) { INT_ARRAY_00eb0af0::instance[playerID] = DVar3; - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 5); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, + DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 5); } } } diff --git a/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp index b235964f5..dbef793fc 100644 --- a/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp @@ -1,8 +1,7 @@ -#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -16,12 +15,14 @@ namespace AI { void AICState::playAnger2BikFromPlayerToPlayer(int playerID, int targetPlayerID) { if (DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); bool bVar2; - if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 == 0)) && - (bVar2 = targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, - DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 = 0x60, bVar2)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 6); + if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 == 0)) + && (bVar2 = targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, + DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 = 0x60, bVar2)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 6); } } } diff --git a/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp index 2d99ef4d8..ea8497a85 100644 --- a/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -13,9 +12,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0FC0 void AICState::playFriendlyVictoryBikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 10); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 10); } } } diff --git a/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp index d3d56f13d..62fd7fb60 100644 --- a/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -13,9 +12,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0B70 void AICState::playGoodsNotSentBikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1c); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1c); } } } diff --git a/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp index 8aec4a1c2..484a7fbbb 100644 --- a/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -14,9 +13,14 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0A20 void AICState::playGoodsRequestBikFromPlayerToPlayer(int playerID, int targetPlayerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) && (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID].lordKilledByPlayerID == 0)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0xe); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) + && (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .lordKilledByPlayerID + == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0xe); } } } diff --git a/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp index fbab88edc..b9afb8833 100644 --- a/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -14,9 +13,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0BB0 void AICState::playGoodsSentBikFromPlayerToPlayer(int playerID, int targetPlayerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if ((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1d); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1d); } } } diff --git a/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp b/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp index b976cc78c..e6528e25b 100644 --- a/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp +++ b/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" @@ -12,9 +11,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0F90 void AICState::playJokeBikFromAIToHuman(int playerID, int aiType) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, aiType, 0x14); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, aiType, 0x14); } } } diff --git a/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp index 28e61efb1..93c274c9b 100644 --- a/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -13,10 +12,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0CF0 void AICState::playNervous1BikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if ((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 == 0)) { DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 = 0x30; - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 8); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 8); } } } diff --git a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp index 4d3b6da36..a2b044f24 100644 --- a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -14,13 +13,16 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0B10 void AICState::playNervous2BikFromPlayer(int playerID) { - int iVar3 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar3 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); int iVar2 = DAT_GameSynchronyState::instance.currentPlayerSlotID; if ((iVar3 != 0) && (DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown == 0)) { int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown = 48; - if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] != DAT_GameState::instance.mapAndTime.playerTeams[iVar2]) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 9); + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] + != DAT_GameState::instance.mapAndTime.playerTeams[iVar2]) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, AVar1 - 1, 9); } } } diff --git a/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp index d8ca73671..2a4c11018 100644 --- a/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -13,9 +12,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D1050 void AICState::playNoHelpBikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1f); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1f); } } } diff --git a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp index b9bf203fe..a0679b77a 100644 --- a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp @@ -1,8 +1,7 @@ -#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -15,41 +14,57 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D08B0 void AICState::playPlayerKilledBiksFromKilledAndKillerPlayer(int killerPlayerID, int killedPlayerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(killerPlayerID); + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + killerPlayerID); if (iVar1 != 0) { if (killedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { iVar1 = 0xc; - } - else { + } else { if (killerPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER( + Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); int i = 1; do { - if ((DAT_GameState::instance.playerDataArray[i].aiType != AITA_NULL) && - (DAT_GameState::instance.mapAndTime.playerTeams[i] == DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { - int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i); + if ((DAT_GameState::instance.playerDataArray[i].aiType != AITA_NULL) + && (DAT_GameState::instance.mapAndTime.playerTeams[i] + == DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + int iVar2 = MACRO_CALL_MEMBER( + Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i); if (iVar2 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(i, (int)DAT_GameState::instance.playerDataArray[i].aiType - 1, 0x11); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, + DAT_VideoBikQueue::ptr)( + i, (int)DAT_GameState::instance.playerDataArray[i].aiType - 1, 0x11); } } i = i + 1; } while (i < 9); return; } - iVar1 = DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]; + iVar1 = DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]; if (iVar1 == DAT_GameState::instance.mapAndTime.playerTeams[killedPlayerID]) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 0x10); + MACRO_CALL_MEMBER( + Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 0x10); return; } if (DAT_GameState::instance.mapAndTime.playerTeams[killerPlayerID] == iVar1) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 0x12); + MACRO_CALL_MEMBER( + Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER( + Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 0x12); return; } - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); iVar1 = 0xd; } - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, iVar1); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, iVar1); } } } diff --git a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp index 1dc39d4bf..fc2a1bac2 100644 --- a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -14,12 +13,16 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0D40 void AICState::playRequestHelpBikFromPlayer(int playerID) { - int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar2 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); int iVar1 = DAT_GameSynchronyState::instance.currentPlayerSlotID; if ((iVar2 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 == 0)) { DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 = 0x30; - if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[iVar1]) && (DAT_GameState::instance.playerDataArray[iVar1].lordKilledByPlayerID == 0)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x13); + if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] + == DAT_GameState::instance.mapAndTime.playerTeams[iVar1]) + && (DAT_GameState::instance.playerDataArray[iVar1].lordKilledByPlayerID == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x13); } } } diff --git a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp index 89cacc944..e95658878 100644 --- a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -15,17 +14,22 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D07C0 void AICState::playTauntToAttackedPlayerBikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { iVar1 = 0; - if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] + == DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { iVar1 = 0x17; } - if (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { if (iVar1 == 0) { iVar1 = ((byte)SEC_RNG::instance.currentNumber2 & 3) + 1; } - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, iVar1); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, iVar1); } } } diff --git a/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp index e27c7b599..02745d879 100644 --- a/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -13,9 +12,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D1000 void AICState::playTeamWinningBikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker == 0)) && (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker == 0)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1e); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker == 0)) + && (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1e); } } } diff --git a/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp index e216c8c1f..110bb9381 100644 --- a/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -16,15 +15,20 @@ namespace AI { void AICState::playThanksBikFromPlayerToPlayer(int playerID, int targetPlayerID) { DWORD DVar2; - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { iVar1 = (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1; DAT_GameState::instance.playerDataArray[playerID].aiRequestDelay = this->aics[iVar1].aiRequestDelay; - if (((targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) && - (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID].lordKilledByPlayerID == 0)) && - ((DVar2 = timeGetTime(), DWORD_00eb0b18::instance == 0 || (1199999 < DVar2 - DWORD_00eb0b18::instance)))) { + if (((targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) + && (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .lordKilledByPlayerID + == 0)) + && ((DVar2 = timeGetTime(), + DWORD_00eb0b18::instance == 0 || (1199999 < DVar2 - DWORD_00eb0b18::instance)))) { DWORD_00eb0b18::instance = DVar2; - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, iVar1, 0xf); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, iVar1, 0xf); } } } diff --git a/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp index 5fb4e29cf..97437bc36 100644 --- a/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp @@ -1,8 +1,7 @@ -#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -17,14 +16,18 @@ namespace AI { { int iVar1; bool bVar2; - if ((((DAT_GameState::instance.playerDataArray[targetPlayerID].aiType != AITA_NULL) && - (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] != -1)) && - (iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(targetPlayerID), iVar1 != 0)) && - (((iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID), iVar1 != 0 && - (DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 == 0)) && - (bVar2 = playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, - DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 = 0x30, bVar2)))) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(targetPlayerID, (int)DAT_GameState::instance.playerDataArray[targetPlayerID].aiType - 1, 0xb); + if ((((DAT_GameState::instance.playerDataArray[targetPlayerID].aiType != AITA_NULL) + && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] != -1)) + && (iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + targetPlayerID), + iVar1 != 0)) + && (((iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + playerID), + iVar1 != 0 && (DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 == 0)) + && (bVar2 = playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, + DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 = 0x30, bVar2)))) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + targetPlayerID, (int)DAT_GameState::instance.playerDataArray[targetPlayerID].aiType - 1, 0xb); } } } diff --git a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp index ad2cf43b2..a733ce5f7 100644 --- a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp +++ b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp @@ -11,8 +11,9 @@ namespace AI { { if (0 < DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops) { int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; - if ((_tribeID != 0) && - (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12] = 0; } MACRO_CALL_MEMBER(AICState_Func::addEngineersToTribe, this)(playerID); diff --git a/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp b/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp index e39cd8bcd..791472b60 100644 --- a/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp +++ b/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp @@ -1,7 +1,6 @@ +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TroopValueState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -16,12 +15,14 @@ namespace AI { { int _tribeID; /* bug: only sends 0xf, while 0xf+1 could also be send if defined by 'AIC: AttUnitPatrolGroupsCount' */ - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (_tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xf], _tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xf]) && - (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (_tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xf], _tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xf]) + && (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; - MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::sendAttackingPatrolTribeToComputedDestination, DAT_TroopValueState::ptr)(_tribeID); + MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::sendAttackingPatrolTribeToComputedDestination, + DAT_TroopValueState::ptr)(_tribeID); return; } } diff --git a/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp index d54d90ecd..f595abbde 100644 --- a/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp @@ -10,8 +10,9 @@ namespace AI { void AICState::sendTribeAtOffset1ToCampfire(int playerID) { int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[1]; - if ((0 < _tribeID) && - (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[1])) { + if ((0 < _tribeID) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[1])) { MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); } } diff --git a/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp b/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp index 70816a822..86bc99714 100644 --- a/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -15,12 +14,14 @@ namespace AI { void AICState::sendTribeToAttack(int playerID) { int tribeID; - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbd], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbd]) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbd], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbd]) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3fb); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3fb); } } } diff --git a/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp b/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp index 3438b8701..b81436f3d 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp @@ -1,6 +1,5 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -13,7 +12,9 @@ namespace AI { void AICState::sendUnitsToCampfire(int tribeID, int playerID) { if (0 < DAT_GameState::instance.playerDataArray[playerID].campground.id) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, DAT_GameState::instance.playerDataArray[playerID].campground.xEntry, DAT_GameState::instance.playerDataArray[playerID].campground.yEntry, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, + DAT_GameState::instance.playerDataArray[playerID].campground.xEntry, + DAT_GameState::instance.playerDataArray[playerID].campground.yEntry, 0); DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; } } diff --git a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp index 79a4d2d29..8b0339efc 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp @@ -1,9 +1,8 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" namespace OpenSHC { @@ -14,7 +13,9 @@ namespace AI { { int iVar1 = DAT_GameState::instance.playerDataArray[playerID].keep.id; if (0 < iVar1) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, (int)(short)DAT_BuildingsState::instance.buildings[iVar1].x + 3, (int)(short)DAT_BuildingsState::instance.buildings[iVar1].y + 4, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, + (int)(short)DAT_BuildingsState::instance.buildings[iVar1].x + 3, + (int)(short)DAT_BuildingsState::instance.buildings[iVar1].y + 4, 0); } } } diff --git a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp index 172e3b81c..0689b2419 100644 --- a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp +++ b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp @@ -1,9 +1,9 @@ #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_TroopValueState.hpp" -#include "OpenSHC/Globals/DAT_TileMapState.hpp" #include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" namespace OpenSHC { namespace AI { @@ -12,11 +12,16 @@ namespace AI { void AICState::setAttackPrimeInfo(int playerID, int attackedPlayerID) { int _tile = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile; - DAT_TroopValueState::instance.attackInfo.startCon = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; + DAT_TroopValueState::instance.attackInfo.startCon + = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; DAT_TroopValueState::instance.attackInfo.startZone = (int)(char)DAT_TileMapState::instance.AIZoneLayer[_tile]; - DAT_TroopValueState::instance.attackInfo.zoneSize = DAT_PathFindingState::instance.zoneSizesArray[(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]]; + DAT_TroopValueState::instance.attackInfo.zoneSize + = DAT_PathFindingState::instance + .zoneSizesArray[(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]]; DAT_TroopValueState::instance.attackInfo.unknownOne_0x20f90 = 1; - DAT_TroopValueState::instance.attackInfo.keepCon = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry]; + DAT_TroopValueState::instance.attackInfo.keepCon + = (int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry]; } } } diff --git a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp index 16bce6ec3..772489730 100644 --- a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp +++ b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -22,11 +21,13 @@ namespace AI { psVar2 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xc0; do { _tribeID = (int)*psVar2; - if (((_tribeID != 0) && - (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar1 + 0xc0])) && - (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { + if (((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar1 + 0xc0])) + && (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(_tribeID, Map::Units::STBT_0x3f2); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + _tribeID, Map::Units::STBT_0x3f2); } iVar1 = iVar1 + 1; psVar2 = psVar2 + 1; diff --git a/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp b/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp index c92c7b451..b44d4a6c2 100644 --- a/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp +++ b/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -16,13 +15,15 @@ namespace AI { void AICState::setTribe0x11ToAggressiveAndAttackIfConditionMet(int param_1) { int tribeID; - if (((0 < *(int*)((int)DAT_TroopValueState::instance.attackInfo.moatValuesArray + param_1 * 0x177bc + -4)) && - (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL)) && - (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0x11], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0x11]) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if (((0 < *(int*)((int)DAT_TroopValueState::instance.attackInfo.moatValuesArray + param_1 * 0x177bc + -4)) + && (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL)) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0x11], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0x11]) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f7); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f7); } } } diff --git a/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp index 45520c9d5..2290c59f5 100644 --- a/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp +++ b/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -15,12 +14,14 @@ namespace AI { void AICState::setTribe0xCtoAggressiveAndAttack(int playerID) { int tribeID; - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xc], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xc]) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xc], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xc]) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f2); } } } diff --git a/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp index 259138f45..87e451e47 100644 --- a/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp +++ b/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -15,12 +14,14 @@ namespace AI { void AICState::setTribe0xbToAggressiveAndAttack(int playerID) { int tribeID; - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb]) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb]) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f2); } } } diff --git a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp index 68feb468c..d374436ea 100644 --- a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp +++ b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp @@ -1,13 +1,12 @@ -#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/AI/AIVState.func.hpp" #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { @@ -20,9 +19,9 @@ namespace AI { return FALSE; } if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 1) { - _hut = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT); - } - else { + _hut = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT); + } else { if (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] < 0x15) { return FALSE; } @@ -37,8 +36,11 @@ namespace AI { if (_hut == 0) { return FALSE; } - MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)((int)(short)DAT_BuildingsState::instance.buildings[_hut].x, (int)(short)DAT_BuildingsState::instance.buildings[_hut].y); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(_hut, playerID, 50); + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + (int)(short)DAT_BuildingsState::instance.buildings[_hut].x, + (int)(short)DAT_BuildingsState::instance.buildings[_hut].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(_hut, playerID, 50); MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hut); return TRUE; } diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp index 3a98835e1..52613f2ef 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp @@ -1,5 +1,4 @@ #include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Commands/CommandBuildingType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -8,14 +7,17 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB9F0 - BOOLEnum AICState::shouldNotBuildMarketArmoryGranaryBarracksMercenarypost(int playerID, Commands::CommandBuildingType param_2) + BOOLEnum AICState::shouldNotBuildMarketArmoryGranaryBarracksMercenarypost( + int playerID, Commands::CommandBuildingType param_2) { if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) { - if ((0 < DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker) && (param_2 != Commands::CBT_MARKETPLACE)) { + if ((0 < DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker) + && (param_2 != Commands::CBT_MARKETPLACE)) { return param_2 != Commands::CBT_GRANARY; } - } - else if ((((param_2 != Commands::CBT_MARKETPLACE) && (param_2 != Commands::CBT_MERCENARYPOST)) && (param_2 != Commands::CBT_BARRACKS)) && (param_2 != Commands::CBT_ARMORY)) { + } else if ((((param_2 != Commands::CBT_MARKETPLACE) && (param_2 != Commands::CBT_MERCENARYPOST)) + && (param_2 != Commands::CBT_BARRACKS)) + && (param_2 != Commands::CBT_ARMORY)) { return param_2 != Commands::CBT_GRANARY; } return FALSE; diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp index b1b870c29..a7b0d34e6 100644 --- a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -1,11 +1,10 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" -#include "OpenSHC/Map/Units/TribesState.func.hpp" - #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" namespace OpenSHC { namespace AI { @@ -23,8 +22,8 @@ namespace AI { int _tribeID = 0; int local_c = 0; short sVar4 = 1000; - if ((iVar3 < iVar6) && - (((unitType == (short*)0x8 || (unitType == (short*)0xa)) || (unitType == (short*)0x11)))) { + if ((iVar3 < iVar6) + && (((unitType == (short*)0x8 || (unitType == (short*)0xa)) || (unitType == (short*)0x11)))) { iVar6 = iVar3; } iVar3 = DAT_SkirmishDefinedData::instance.DAT_AiTribeIDOffsetForUnitType[(int)unitType]; @@ -32,9 +31,11 @@ namespace AI { unitType = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar3; do { int iVar5 = (int)*unitType; - if ((iVar5 == 0) || - (DAT_TribesState::instance.tribes[iVar5].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7])) { - _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + if ((iVar5 == 0) + || (DAT_TribesState::instance.tribes[iVar5].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7])) { + _tribeID = MACRO_CALL_MEMBER( + Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); goto LAB_004ccaae; } short sVar1 = DAT_TribesState::instance.tribes[iVar5].size; @@ -48,9 +49,10 @@ namespace AI { } while (iVar7 < iVar6); iVar7 = local_c; if (_tribeID != 0) { -LAB_004ccaae: + LAB_004ccaae: DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[iVar3 + iVar7] = (short)_tribeID; - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] = DAT_TribesState::instance.tribes[_tribeID].uid; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] + = DAT_TribesState::instance.tribes[_tribeID].uid; return _tribeID; } } diff --git a/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp b/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp index 45d773b2c..7cfb1dbdf 100644 --- a/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp +++ b/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp @@ -1,11 +1,10 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -18,12 +17,15 @@ namespace AI { if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { Map::Units::Unit* pUVar1 = &DAT_UnitsState::instance.units[1]; do { - if ((((pUVar1->owner == param_1) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) && - (pUVar1->dying == 0)) && (pUVar1->aiUnitBehaviourType == 7)) { + if ((((pUVar1->owner == param_1) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) + && (pUVar1->dying == 0)) + && (pUVar1->aiUnitBehaviourType == 7)) { tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xa7]; if (pUVar1->tribeID != tribeID) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)pUVar1->tribeID); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, (int)pUVar1->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, tribeID); } } unitID = unitID + 1; diff --git a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp index fb055692e..9633dd0c3 100644 --- a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp +++ b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp @@ -1,9 +1,8 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { @@ -15,16 +14,17 @@ namespace AI { int _totalEnemyTroopValue = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; if (_totalEnemyTroopValue == 0) { _relativeStrength = 100; - } - else { - _relativeStrength = (short)((DAT_GameState::instance.playerDataArray[playerID].totalTeamTroopValue * 100) / _totalEnemyTroopValue); + } else { + _relativeStrength = (short)((DAT_GameState::instance.playerDataArray[playerID].totalTeamTroopValue * 100) + / _totalEnemyTroopValue); } DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy = _relativeStrength; if (param_2 == FALSE) { if (DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue < 100) { return FALSE; } - BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + BOOLEnum BVar2 + = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); if (BVar2 != FALSE) { if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 50) { return TRUE; @@ -40,9 +40,9 @@ namespace AI { if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 75) { return TRUE; } - } - else { - BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + } else { + BOOLEnum BVar2 + = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); if (BVar2 != FALSE) { if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 0x46) { return TRUE; diff --git a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp index 414009e9a..20ee5094d 100644 --- a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp +++ b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp @@ -1,6 +1,5 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" @@ -13,7 +12,8 @@ namespace AI { AICSpecification* destination = this->aics; int iVar1 = 20; do { - MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)(676, '\0', destination); + MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 676, '\0', destination); destination = destination + 1; iVar1 = iVar1 + -1; } while (iVar1 != 0); From ccdcdb75fb5d7ec81ab7647127b25874b18cbd48 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sun, 26 Jul 2026 23:17:09 +0200 Subject: [PATCH 008/242] ghidra-cpp and claude fixes --- .../AI/AICState/addEngineersToTribe.cpp | 23 +- .../AI/AICState/addRallyPointForTribe.cpp | 101 +++ .../AICState/addUnitToSmallestPatrolTribe.cpp | 4 +- src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp | 53 ++ .../aiChoiceAttForceRallyPercentage.cpp | 93 +++ .../AICState/aiCommandSiegeEngineTribes.cpp | 207 +++++++ .../aiCommandTribe12AggressiveApproach.cpp | 81 +++ .../AICState/aiCommandWallAssaultTribes.cpp | 9 +- .../AI/AICState/aiCreateSiegeUnits.cpp | 514 +++++++++++++++ .../AI/AICState/aiGiveRaidInstructions.cpp | 306 +++++++++ .../AI/AICState/aiOfTypeInCurrentGame.cpp | 55 ++ .../AICState/aiReassignTunnelersToTribe.cpp | 25 +- .../AI/AICState/aiRecruitSortieMeleeUnits.cpp | 113 ++++ .../AICState/aiRecruitSortieRangedUnits.cpp | 117 ++++ src/OpenSHC/AI/AICState/aiRecruitUnits.cpp | 487 +++++++++++++++ .../aiRegisterTribeAndAssignTarget.cpp | 69 +++ .../AI/AICState/aiRequiresExtraOxtethers.cpp | 147 +++++ src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 123 ++++ ...iShouldAttackOrWaitForTeamCoordination.cpp | 112 ++++ .../AI/AICState/aiUpdateTaxesAndRations.cpp | 157 +++++ .../AI/AICState/assignUnitToATribe.cpp | 3 +- src/OpenSHC/AI/AICState/buyRequiredGoods.cpp | 129 ++++ ...mBuildingIDFromPlayersArrayOfBuildings.cpp | 105 ++++ .../AI/AICState/clearOutdatedAITribes.cpp | 67 ++ .../clearPlayerDataInformationChunk.cpp | 52 ++ .../clearRallyFlagOnAllAIAttackTribes.cpp | 89 +++ .../AI/AICState/commandFourTribesToMove.cpp | 68 ++ .../AICState/computeAttackPossibilities.cpp | 60 ++ .../AICState/computeEnemyKeepApproachTile.cpp | 173 ++++++ .../AI/AICState/computeNervousness.cpp | 86 +++ .../AI/AICState/countSiegeEngineUnits.cpp | 63 ++ .../AICState/decideOnTribeAttackLocation.cpp | 287 +++++++++ .../AI/AICState/destroyBuildingIfNoWorker.cpp | 34 +- ...determineAIPlayerAttackRequestResponse.cpp | 55 ++ .../AI/AICState/determineAIPlayerHelp.cpp | 53 ++ .../AI/AICState/disbandAIPlayerSiegeUnits.cpp | 72 +++ ...ndAttackTribePositionAndPathToDefenses.cpp | 117 ++++ .../generateSiegeCreationInformation.cpp | 106 ++++ .../AI/AICState/getSmallestPatrolTribe.cpp | 100 +++ .../getTargetableBuildingForPlayerID.cpp | 116 ++++ .../getUnitTypeForUnitBehaviourType.cpp | 118 ++++ .../giveMoveCommandToAttackTribes.cpp | 106 ++++ .../AICState/giveMoveCommandToSortieUnits.cpp | 105 ++++ .../AI/AICState/giveSomeRaidCommand.cpp | 70 +++ .../AICState/hasNoTroopsOrAllAreDiggers.cpp | 47 +- .../AI/AICState/instructTribe166ToMove.cpp | 116 ++++ .../AI/AICState/makeOutpostTribesAttack.cpp | 12 +- ...eUnitsGoDefensiveAndBackToSomeLocation.cpp | 100 +++ .../AICState/moveAttackTribesToLocations.cpp | 104 ++++ .../moveAttackingUnitsToNextRallyPoint.cpp | 151 +++++ ...rcentageNonMovingTribesGTEAICSpecified.cpp | 96 +++ ...BuyWhenLowOnResourceAndSnoozeBuildings.cpp | 333 ++++++++++ ...yerKilledBiksFromKilledAndKillerPlayer.cpp | 22 +- ...playTauntToAttackedPlayerBikFromPlayer.cpp | 23 +- .../processAttForceRallyPercentage.cpp | 111 ++++ .../randomlySelectAttackUnitTypeToRecruit.cpp | 233 +++++++ .../recomputeAIPathCostToAttackedKeep.cpp | 93 +++ .../AI/AICState/recomputeAIZonerLayer.cpp | 42 ++ .../AI/AICState/recomputeAttackAIZone.cpp | 71 +++ .../AI/AICState/recreateEngineersTribe.cpp | 2 +- .../recruitHarrassingSiegeEngines.cpp | 254 ++++++++ ...oveOrganismsAndSetMoveDestinationPairs.cpp | 66 ++ .../AI/AICState/renderDebugDataAiInfo.cpp | 248 ++++++++ src/OpenSHC/AI/AICState/requestGoods.cpp | 70 +++ .../AI/AICState/selectAttackTarget.cpp | 254 ++++++++ ...selectBuildingFromAListOfBuildingTypes.cpp | 75 +++ ...andomBuildingIDFromListOfBuildingTypes.cpp | 37 ++ src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 147 +++++ ...oAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp | 109 ++++ ...sendOilMenForOilPickupOrToAIVLocations.cpp | 104 ++++ ...gedUnitTribesToAIVSlotsOrKeepIfNervous.cpp | 76 +++ .../AICState/sendTribeToAIVLocationSlot.cpp | 90 +++ .../sendUnitsToAttackBreachedCastle.cpp | 181 ++++++ src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp | 2 +- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 165 +++++ ...sendWallPatrolUnitTribesToAIVLocations.cpp | 155 +++++ .../AI/AICState/setAICParameters_06.cpp | 289 +++++++++ .../AI/AICState/setAICParameters_07.cpp | 283 +++++++++ .../AI/AICState/setAICParameters_08.cpp | 289 +++++++++ .../AI/AICState/setAICParameters_09.cpp | 283 +++++++++ .../AI/AICState/setAICParameters_10.cpp | 283 +++++++++ .../AI/AICState/setAICParameters_11.cpp | 281 +++++++++ .../AI/AICState/setAICParameters_12.cpp | 281 +++++++++ .../AI/AICState/setAICParameters_13.cpp | 275 +++++++++ .../AI/AICState/setAICParameters_14.cpp | 289 +++++++++ .../AI/AICState/setAICParameters_15.cpp | 275 +++++++++ .../AI/AICState/setAICParameters_16.cpp | 277 +++++++++ .../AICState/setAttackCoordinationLevel.cpp | 6 +- ...htTribe0xc0TribesToAggressiveAndAttack.cpp | 9 +- src/OpenSHC/AI/AICState/setInitialAIC.cpp | 52 ++ .../AICState/setNextMoveLocationForUnits.cpp | 52 ++ ...TargetForTribeBasedOnTargetChoiceLogic.cpp | 196 ++++++ .../AICState/setupWorkshopProductionType.cpp | 152 +++++ .../AI/AICState/shareGoldAmongTeamMembers.cpp | 203 ++++++ .../AI/AICState/shouldNotBuildKillingPits.cpp | 5 +- ...uldWaitWithBuildingAPositiveFearFactor.cpp | 4 +- .../AI/AICState/smallestTribeOfUnitType.cpp | 11 +- .../AI/AICState/someChatMessageSelection.cpp | 210 +++++++ .../AI/AICState/teamIsWeakRelativeToEnemy.cpp | 20 +- .../AI/AICState/unitIDIsRangedOrArmored.cpp | 40 ++ src/OpenSHC/AI/AICState/updateAIBehaviour.cpp | 165 +++++ .../AI/AICState/updateAIPlayerState.cpp | 567 +++++++++++++++++ .../AI/AICState/updateAIStrengthState.cpp | 583 ++++++++++++++++++ .../AI/AICState/updateTribeLocations.cpp | 74 +++ ...12_toPlaceSiegeTentsAndAssignEngineers.cpp | 206 +++++++ .../useAITribe_0xe_toPlaceTunnels.cpp | 80 +++ src/OpenSHC/AI/AICState/wipeAICMemory.cpp | 10 +- .../woodCuttersHutWhileNoWoodAvailable.cpp | 7 +- 108 files changed, 14227 insertions(+), 149 deletions(-) create mode 100644 src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp create mode 100644 src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp create mode 100644 src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp create mode 100644 src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp create mode 100644 src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp create mode 100644 src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRecruitUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRetreatUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp create mode 100644 src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp create mode 100644 src/OpenSHC/AI/AICState/buyRequiredGoods.cpp create mode 100644 src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp create mode 100644 src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp create mode 100644 src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp create mode 100644 src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp create mode 100644 src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp create mode 100644 src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp create mode 100644 src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp create mode 100644 src/OpenSHC/AI/AICState/computeNervousness.cpp create mode 100644 src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp create mode 100644 src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp create mode 100644 src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp create mode 100644 src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp create mode 100644 src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp create mode 100644 src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp create mode 100644 src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp create mode 100644 src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp create mode 100644 src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp create mode 100644 src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp create mode 100644 src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp create mode 100644 src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp create mode 100644 src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp create mode 100644 src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp create mode 100644 src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp create mode 100644 src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp create mode 100644 src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp create mode 100644 src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp create mode 100644 src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp create mode 100644 src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp create mode 100644 src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp create mode 100644 src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp create mode 100644 src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp create mode 100644 src/OpenSHC/AI/AICState/requestGoods.cpp create mode 100644 src/OpenSHC/AI/AICState/selectAttackTarget.cpp create mode 100644 src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp create mode 100644 src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp create mode 100644 src/OpenSHC/AI/AICState/sellExcessGoods.cpp create mode 100644 src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp create mode 100644 src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp create mode 100644 src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp create mode 100644 src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp create mode 100644 src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp create mode 100644 src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp create mode 100644 src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_06.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_07.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_08.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_09.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_10.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_11.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_12.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_13.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_14.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_15.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_16.cpp create mode 100644 src/OpenSHC/AI/AICState/setInitialAIC.cpp create mode 100644 src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp create mode 100644 src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp create mode 100644 src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp create mode 100644 src/OpenSHC/AI/AICState/someChatMessageSelection.cpp create mode 100644 src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp create mode 100644 src/OpenSHC/AI/AICState/updateAIBehaviour.cpp create mode 100644 src/OpenSHC/AI/AICState/updateAIPlayerState.cpp create mode 100644 src/OpenSHC/AI/AICState/updateAIStrengthState.cpp create mode 100644 src/OpenSHC/AI/AICState/updateTribeLocations.cpp create mode 100644 src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp create mode 100644 src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp diff --git a/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp b/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp index e9c39df1a..2d3d8b873 100644 --- a/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp +++ b/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp @@ -10,24 +10,21 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D4040 void AICState::addEngineersToTribe(int playerID) { - int unitID; - - unitID = 1; + int _unitID = 1; if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { - /* Unit offset 150 */ - Map::Units::Unit* psVar1 = &DAT_UnitsState::instance.units[1]; + Map::Units::Unit* _pUnit = &DAT_UnitsState::instance.units[1]; do { /* if logicalState == normal && owner == playerID && unitType == 0x1e (engineer) && aiUnitBehaviourType == 10 */ - if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == playerID)) - && (psVar1->dying == 0)) - && (((psVar1->unitType == Map::Units::UT_E_ENGINEER) && (psVar1->aiUnitBehaviourType == 10)) - && (psVar1->tribeID == 0))) { - MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 10); + if ((((_pUnit->logicalState == Map::Units::ULS_NORMAL) && (_pUnit->owner == playerID)) + && (_pUnit->dying == 0)) + && (((_pUnit->unitType == Map::Units::UT_E_ENGINEER) && (_pUnit->aiUnitBehaviourType == 10)) + && (_pUnit->tribeID == 0))) { + MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(_unitID, 10); } - unitID = unitID + 1; - psVar1 = psVar1 + 1; - } while (unitID < (int)DAT_UnitsState::instance.maxUnitCount); + _unitID = _unitID + 1; + _pUnit = _pUnit + 1; + } while (_unitID < (int)DAT_UnitsState::instance.maxUnitCount); } } diff --git a/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp b/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp new file mode 100644 index 000000000..1ae3180da --- /dev/null +++ b/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp @@ -0,0 +1,101 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/Unit.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitTypeShort.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Unit; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::UnitTypeShort; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFA10 + void AICState ::addRallyPointForTribe(int tribeID) + + { + + short* psVar1; + + BOOLEnum _areInDifferentTeamsUnk; + + Unit* _ptrUnit; + + UnitTypeShort _unitType; + + DAT_TribesState::instance.tribes[tribeID].rallyPointCount = 0; + + _ptrUnit = &DAT_UnitsState::instance.units[1]; + + do { + + if (_ptrUnit->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) { + + _areInDifferentTeamsUnk = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::getTeamsDifferent, + DAT_GameState::ptr)(DAT_TribesState::instance.tribes[tribeID].owner, (int)((int)(_ptrUnit->owner))); + + if (_areInDifferentTeamsUnk == FALSE) { + + _unitType = _ptrUnit->unitType; + + if ((((_unitType == OpenSHC::Map::Units::UT_S_CATAPULT) + || (_unitType == OpenSHC::Map::Units::UT_S_TREBUCHET)) + || (_unitType == OpenSHC::Map::Units::UT_S_FBALLISTA)) + && (_ptrUnit->unknownSiegeTentRelated02 == 3)) { + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::computeNextRallyPointDestination, + DAT_PathFindingState::ptr)(-1, (int)((int)(_ptrUnit->x)), (int)((int)(_ptrUnit->y))); + + DAT_TribesState::instance.tribes[tribeID] + .rallyPointArray[DAT_TribesState::instance.tribes[tribeID].rallyPointCount][0] + = (short)DAT_PathFindingState::instance.ALG_ResultX; + + DAT_TribesState::instance.tribes[tribeID] + .rallyPointArray[DAT_TribesState::instance.tribes[tribeID].rallyPointCount][1] + = (short)DAT_PathFindingState::instance.ALG_ResultY; + + psVar1 = &DAT_TribesState::instance.tribes[tribeID].rallyPointCount; + + *psVar1 = *psVar1 + 1; + + if (8 < DAT_TribesState::instance.tribes[tribeID].rallyPointCount) + break; + } + } + } + + _ptrUnit = _ptrUnit + 0x248; + + } while ((int)_ptrUnit < 0x165141a); + + if (DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex < 0) { + + DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex = 0; + } + + if (DAT_TribesState::instance.tribes[tribeID].rallyPointCount + <= DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex) { + + DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex = 0; + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp index 9a2d04fed..2939e1589 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp @@ -1,7 +1,9 @@ +#include "OpenSHC/AI/AICState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Globals/DAT_AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -16,7 +18,7 @@ namespace AI { int _aiType = DAT_GameState::instance.playerDataArray[iVar1].aiType; if (_aiType != AITA_NULL) { DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 4; - iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::getSmallestPatrolTribe, DAT_TribesState::ptr)( + iVar1 = MACRO_CALL_MEMBER(AI::AICState_Func::getSmallestPatrolTribe, DAT_AICState::ptr)( iVar1, (int)this->aics[_aiType - 1].OuterPatrolGroupsCount); MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); } diff --git a/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp b/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp new file mode 100644 index 000000000..0181f8255 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp @@ -0,0 +1,53 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Game::Player::PlayerData; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x004D48F0 + void AICState ::aiBuyAndSellGoods(int playerID) + + { + + PlayerData* _pPlayerData; + + int _pMarketID; + + _pMarketID = DAT_GameState::instance.playerDataArray[playerID].marketplace.id; + + DAT_GameState::instance.playerDataArray[playerID].hasMarketUnk = 0; + + if (_pMarketID != 0) { + + DAT_GameState::instance.playerDataArray[playerID].hasMarketUnk = 1; + } + + if (DAT_GameState::instance.playerDataArray[playerID].hasMarketUnk != 0) { + + _pPlayerData = &DAT_GameState::instance.playerDataArray[playerID]; + + _pPlayerData->willBuy = _pPlayerData->willBuy ^ TRUE; + + if (_pPlayerData->willBuy == FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellExcessGoods, this)(playerID); + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::buyRequiredGoods, this)(playerID); + + return; + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp new file mode 100644 index 000000000..46b561d3c --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -0,0 +1,93 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CEC80 + uint AICState ::aiChoiceAttForceRallyPercentage(int param_1) + + { + + AITypeInt AVar1; + + int iVar2; + + int iVar3; + + short* psVar4; + + int local_14; + + int local_10; + + int* local_c; + + AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + + return 0; + } + + local_14 = 0; + + local_10 = 0; + + local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + iVar3 = 0; + + if (0 < *local_c) { + + psVar4 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + (*(int (*)[2])(local_c + -1))[0]; + + do { + + iVar2 = (int)*psVar4; + + if (((iVar2 != 0) + && (DAT_TribesState::instance.tribes[iVar2].uid + == DAT_GameState::instance.playerDataArray[param_1] + .aiTribeUIDs[iVar3 + (*(int (*)[2])(local_c + -1))[0]])) + && (local_14 = local_14 + 1, + DAT_TribesState::instance.tribes[iVar2].percentageMovingUnk < 0x14)) { + + local_10 = local_10 + 1; + } + + iVar3 = iVar3 + 1; + + psVar4 = psVar4 + 1; + + } while (iVar3 < *local_c); + } + + local_c = local_c + 2; + + } while ((int)local_c < 0xb42a2c); + + if (0 < local_14) { + + return (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x200) + <= (local_10 * 100) / local_14); + } + + return 0; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp new file mode 100644 index 000000000..f4a02fbcf --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp @@ -0,0 +1,207 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Unit.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitTypeShort.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::Unit; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::UnitTypeShort; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFCD0 + void AICState ::aiCommandSiegeEngineTribes(int playerID) + + { + + UnitTypeShort UVar1; + + int iVar2; + + uint x1; + + int _sectionID2; + + int iVar3; + + int iVar4; + + uint y1; + + Unit* local_14; + + int local_c[3]; + + int _tile; + + short _sectionID; + + short _targetUnitID; + + iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xba]; + + iVar4 = 0; + + iVar3 = 0; + + local_c[0] = 0; + + local_c[1] = 0; + + local_c[2] = 0; + + if ((iVar2 != 0) + && (DAT_TribesState::instance.tribes[iVar2].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xba])) { + + local_c[0] = iVar2; + + iVar3 = 1; + } + + iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbb]; + + if ((iVar2 != 0) + && (DAT_TribesState::instance.tribes[iVar2].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbb])) { + + local_c[iVar3] = iVar2; + + iVar3 = iVar3 + 1; + } + + iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbc]; + + if ((iVar2 != 0) + && (DAT_TribesState::instance.tribes[iVar2].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbc])) { + + local_c[iVar3] = iVar2; + } + + local_14 = &DAT_UnitsState::instance.units[1]; + + do { + + if ((local_14->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) + && ((((UVar1 = local_14->unitType, + UVar1 == OpenSHC::Map::Units::UT_S_TOWER || (UVar1 == OpenSHC::Map::Units::UT_S_BATTERINGRAM)) + || (UVar1 == OpenSHC::Map::Units::UT_S_SHIELD)) + && ((local_14->unknownSiegeTentRelated02 == 3 && (local_14->aiUnitBehaviourType != 0x15)))))) { + + if (UVar1 == OpenSHC::Map::Units::UT_S_TOWER) { + + if ((local_14->tribeID != 0) + && (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc + + -4) + != 0)) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, + DAT_TribesState::ptr)((int)local_14->tribeID, OpenSHC::Map::Units::STBT_0x414); + } + + } + + else if (UVar1 == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + + iVar3 = (int)local_14->tribeID; + + if (iVar3 != 0) { + + if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.gateValuesArray + playerID * 0x177bc + + -4) + == 0) { + + if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + + playerID * 0x177bc + -4) + != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, + DAT_TribesState::ptr)(iVar3, OpenSHC::Map::Units::STBT_0x413); + } + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, + DAT_TribesState::ptr)(iVar3, OpenSHC::Map::Units::STBT_0x3f6); + } + } + + } + + else if (UVar1 == OpenSHC::Map::Units::UT_S_SHIELD) { + + _sectionID = local_14->tribeID; + + _sectionID2 = (int)_sectionID; + + if ((_sectionID2 != 0) && (iVar4 < 3)) { + + iVar3 = local_c[iVar4]; + + DAT_TribesState::instance.tribes[_sectionID2].field56_0x1f2 = (short)iVar3; + + DAT_TribesState::instance.tribes[_sectionID2].uid2 + = DAT_TribesState::instance.tribes[iVar3].uid; + + _targetUnitID = DAT_TribesState::instance.tribes[iVar3].selectionTargetUnitID; + + DAT_TribesState::instance.tribes[iVar3].tribeID = _sectionID; + + _tile = DAT_UnitsState::instance.units[_targetUnitID].tile; + + iVar4 = iVar4 + 1; + + if (0 < _tile) { + + y1 = (uint)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + + x1 = _tile - DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + _sectionID2, x1, y1, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + calculatePreferredRelativeOrientation, + DAT_DirectionAlgorithmState::ptr)((int)DAT_UnitsState::instance.units[_targetUnitID].x, + (int)((int)(DAT_UnitsState::instance.units[_targetUnitID].y)), (int)((int)(x1)), + (int)((int)(y1))); + + DAT_TribesState::instance.tribes[_sectionID2].orientation + = (short)DAT_DirectionAlgorithmState::instance.orientation; + } + } + } + } + + local_14 = local_14 + 0x248; + + } while ((int)local_14 < 0x165141a); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp new file mode 100644 index 000000000..e4b5a1359 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp @@ -0,0 +1,81 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF2E0 + void AICState ::aiCommandTribe12AggressiveApproach(int param_1) + + { + + int iVar1; + + BOOLEnum BVar2; + + int tribeID; + + if ((((DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xc], tribeID != 0)) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xc])) + && (iVar1 = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID, iVar1 != 0)) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + DAT_PathFindingState::ptr)((int)DAT_UnitsState::instance.units[iVar1].x, + (uint)((int)((int)DAT_UnitsState::instance.units[iVar1].y)), -1, -1, 10000, FALSE); + + iVar1 = DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID; + + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + BVar2 = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)(iVar1, 200); + + if (((BVar2 != FALSE) + || (BVar2 = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, (int)((int)(150))), + BVar2 != FALSE)) + || ((BVar2 + = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, 100), + BVar2 != FALSE + || (BVar2 = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, (int)((int)(50))), + BVar2 != FALSE)))) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(tribeID, (uint)((int)(DAT_PathFindingState::instance.ALG_ResultX)), + (uint)((int)(DAT_PathFindingState::instance.ALG_ResultY)), 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp index fe11b9a93..3f1f25be3 100644 --- a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp @@ -13,14 +13,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF660 void AICState::aiCommandWallAssaultTribes(int param_1) { - int tribeID; - int iVar1; - short* psVar2; if (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) { - iVar1 = 0; - psVar2 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + 0xbe; + int iVar1 = 0; + short* psVar2 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + 0xbe; do { - tribeID = (int)*psVar2; + int tribeID = (int)*psVar2; if (((tribeID != 0) && (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar1 + 0xbe])) diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp new file mode 100644 index 000000000..ec0e19d76 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -0,0 +1,514 @@ +#include "OpenSHC/AI/AICState.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/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/Tribes/AITribeType.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Buildings/BuildingTypeShort.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.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_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::Tribes::AITribeType; + using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Buildings::BuildingTypeShort; + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2000 + void AICState ::aiCreateSiegeUnits(int playerID) + + { + + int _existingBuildingID; + + int _spawnedUnit; + + int _requiredEngineerCount; + + int _remainingRequiredEngineers; + + int _tribeID; + + int _targetUnitID; + + int _area; + + int _engineersTribe; + + int _aicOffset; + + int _y; + + int _slotIndex; + + int _nextSlotIndex; + + int _tile; + + int _mappingOffset; + + int _incrementsBy5; + + int _siegeInfoIndex; + + int _tribeSize; + + int _requiredGold; + + int _engineersGuildID; + + int _newUID; + + int _newBuildingID; + + int* _pGold; + + int _engineIndex; + + int _uid; + + int _unitID; + + int _location; + + AITypeInt _aiType; + + BuildingTypeShort _existingBuildingType; + + int* _pDelay; + + UnitType _unitType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType != OpenSHC::AI::AIT_NULL) { + + _engineersGuildID = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + + if (((0 < _engineersGuildID) + && (DAT_BuildingsState::instance.buildings[_engineersGuildID].buildingType + == OpenSHC::Map::Buildings::BT_ENGINEERSGUILD)) + && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) { + + _siegeInfoIndex = 0; + + _incrementsBy5 = 0; + + _mappingOffset = 0; + + do { + + _unitType + = *(UnitType*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].unitType + + _mappingOffset); + + _tribeSize = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*( + int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + + _mappingOffset)]; + + _slotIndex = 0; + + if (_tribeSize < 4) { + + if (0 < _tribeSize) + goto LAB_004d20c0; + + } + + else { + + _tribeSize = 3; + + LAB_004d20c0: + do { + + _nextSlotIndex = _slotIndex + 1; + + _location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[*( + int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + + _mappingOffset)][_slotIndex]; + + if (0 < _location) { + + _existingBuildingID = (int)(short)DAT_TileMapState::instance.BuildingLayer[_location]; + + _engineIndex = _incrementsBy5 + _slotIndex; + + _unitID = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID; + + _uid = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid; + + _tile = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID; + + if ((_unitID == 0) || (DAT_UnitsState::instance.units[_unitID].uid == _uid)) { + + if ((_tile == 0) || (DAT_BuildingsState::instance.buildings[_tile].uid == _uid)) { + + if (_unitID == 0) { + + if (_tile == 0) { + + if (_existingBuildingID == 0) { + + if (0x1f < _mappingOffset) + goto LAB_004d21d4; + + } + + else if ((_mappingOffset < 0x20) + && ((_existingBuildingType + = DAT_BuildingsState::instance.buildings[_existingBuildingID] + .buildingType, + _existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER4 + || (_existingBuildingType + == OpenSHC::Map::Buildings::BT_TOWER5)))) { + + LAB_004d21d4: + _requiredGold + = DAT_BuildingsState::instance + .buildingCosts[*( + int*)((int)&DAT_SkirmishDefinedData::instance + .DAT_SiegeEngineMetaInfoArray[0] + .buildingType + + _mappingOffset)] + .requiredGold; + + _aicOffset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + + /* + defSiegeEngineGoldThreshold */ + + /* + defSiegeEngineBuildDelay */ + + if ((_requiredGold + <= DAT_GameState::instance.playerDataArray[playerID] + .currentResources[0xf] + + *(int*)((int)this + _aicOffset + 0x118)) + && (_pDelay = &DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay, + *_pDelay = *_pDelay + 1, + *(int*)((int)this + _aicOffset + 0x11c) + <= DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay)) { + + _y = (int)DAT_ViewportRenderState::instance + .DAT_TileTranslationMatrix_YComponent[_location]; + + _tile = _location + - DAT_ViewportRenderState::instance.translationMatrix[_y] + .addXgetTile; + + if (_siegeInfoIndex < 2) { + + _spawnedUnit = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::spawnUnit, + DAT_UnitsState::ptr)(playerID, playerID, _tile * 8 + 4, + _y * 8 + 4, + (int)((int)(DAT_BuildingsState::instance + .buildings[_existingBuildingID] + .terrainHeightUnk)), + _unitType); + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .unitID = _spawnedUnit; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .uid = DAT_UnitsState::instance.units[_spawnedUnit].uid; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .buildingID = 0; + + MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func:: + processPlacementResourceLossForBuildingType, + DAT_BuildingsState::ptr)(playerID, + (BuildingType)((int)(DAT_SkirmishDefinedData::instance + .DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex] + .buildingType)), + 0); + + } + + else { + + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::placeBuilding, + DAT_TileMapState::ptr)(playerID, _tile, _y, + (CommandBuildingType)((int)((uint)(ushort)(short) + DAT_SkirmishDefinedData::instance + .DAT_SiegeEngineMetaInfoArray + [_siegeInfoIndex] + .commandBuildingType)), + 3, 0xf); + + if (DAT_TileMapState::instance.buildingPlacementFail + == FALSE) { + + _pGold + = DAT_GameState::instance.playerDataArray[playerID] + .currentResources + + 0xf; + + *_pGold = *_pGold - _requiredGold; + + _newBuildingID + = DAT_TileMapState::instance.DAT_PlacedBuildingID; + + _newUID = DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance + .DAT_PlacedBuildingID] + .uid; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex] + [_slotIndex] + .unitID = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex] + [_slotIndex] + .uid = _newUID; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex] + [_slotIndex] + .buildingID = _newBuildingID; + } + } + + /* + delay = 0 */ + + *(undefined4*)(playerID * 0x39f4 + 0x115f48c + _slotIndex * 20 + + _siegeInfoIndex * 100) = 0; + + return; + } + } + + } + + else { + + LAB_004d22d3: + _requiredEngineerCount + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: + getRequiredEngineerCountForSiegeBuilding, + DAT_BuildingsState::ptr)(_tile); + + if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount + != _requiredEngineerCount) { + + if (_requiredEngineerCount + <= DAT_GameState::instance.playerDataArray[playerID] + .engineerCountRelated) { + + _engineersTribe = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func:: + assignRequiredIdleEngineersToNewTribe, + this)(playerID, _requiredEngineerCount); + + DAT_TribesState::instance.tribes[_engineersTribe].tribeType + = OpenSHC::AI::Tribes::AITT_ENGINEERS; + + DAT_TribesState::instance.tribes[_engineersTribe] + .tribeBehaviorType = OpenSHC::Map::Units:: + STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func:: + giveTribeAnInstruction, + DAT_TribesState::ptr)(_engineersTribe, + OpenSHC::Map::Units:: + UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, + _tile, DAT_BuildingsState::instance.buildings[_tile].uid, + 0); + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired + = TRUE; + } + } + + } + + else { + + if (_tile != 0) + goto LAB_004d22d3; + + _remainingRequiredEngineers = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, + DAT_UnitsState::ptr)(_unitID); + + if (0 < _remainingRequiredEngineers) { + + if (DAT_GameState::instance.playerDataArray[playerID] + .engineerCountRelated + < _remainingRequiredEngineers) { + + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired + = TRUE; + + } + + else { + + _tribeID + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func:: + assignRequiredIdleEngineersToNewTribe, + this)(playerID, _remainingRequiredEngineers); + + _targetUnitID = (int)DAT_TribesState::instance.tribes[_tribeID] + .selectionTargetUnitID; + + if ((_targetUnitID != 0) + && (_area = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func:: + calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance + .units[_unitID] + .tile])), + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance + .units[_targetUnitID] + .tile])), + 0), + _area != 0)) { + + DAT_TribesState::instance.tribes[_tribeID].tribeType + = OpenSHC::AI::Tribes::AITT_ENGINEERS; + + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x41c; + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, + DAT_UnitsState::ptr)(_tribeID, + OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, _unitID, + DAT_UnitsState::instance.units[_unitID].uid, 0); + + return; + } + } + } + } + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unknown = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID = 0; + } + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unknown = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID = 0; + } + } + + _slotIndex = _nextSlotIndex; + + } while (_nextSlotIndex < _tribeSize); + } + + _siegeInfoIndex = _siegeInfoIndex + 1; + + _incrementsBy5 = _incrementsBy5 + 5; + + _mappingOffset = _mappingOffset + 16; + + if (64 < _mappingOffset) { + + return; + } + + } while (true); + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp new file mode 100644 index 000000000..3f67ced06 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -0,0 +1,306 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2A70 + void AICState ::aiGiveRaidInstructions(int playerID) + + { + + int* piVar1; + + short sVar2; + + int iVar3; + + int _isAlive; + + int _buildingID_2; + + int _buildingID; + + int iVar4; + + int _buildingTile; + + BOOLEnum BVar5; + + int _tribeID3; + + BOOLEnum _indexTo6; + + short* _ptrTribeID3; + + int _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType != 0) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter; + + *piVar1 = *piVar1 + 1; + + /* + AIC: RaidRetargetDelay */ + + _indexTo6 = FALSE; + + if (*(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x1f0) + <= DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter) { + + DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk == 0) { + + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; + + } + + else { + + iVar4 = DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown; + + if (0 < iVar4) { + + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + = iVar4 + -1; + } + } + + _ptrTribeID3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xb4; + + do { + + _tribeID3 = (int)*_ptrTribeID3; + + DAT_TribesState::instance.tribes[_tribeID3].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + if ((_tribeID3 != 0) + && (DAT_TribesState::instance.tribes[_tribeID3].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_indexTo6 + 0xb4])) { + + if ((DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2) + && (_isAlive = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), + _isAlive != 0)) { + + if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) { + + _buildingID_2 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk, + (undefined4)((int)(_indexTo6))); + + if (_buildingID_2 == 0) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + + LAB_004d2d6b: + if (_buildingID != 0) + goto LAB_004d2d6f; + + } + + else { + + LAB_004d2c00: + _buildingTile + = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] + .buildingEntryY] + .addXgetTile; + + LAB_004d2d8d: + if (_buildingTile != 0) { + + sVar2 = DAT_ViewportRenderState::instance + .DAT_TileTranslationMatrix_YComponent[_buildingTile]; + + iVar4 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; + + BVar5 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( + _tribeID3, _buildingTile); + + if (BVar5 == FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID3, playerID); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, + DAT_TribesState::ptr)(_tribeID3, (uint)((int)(_buildingTile - iVar4)), + (uint)((int)((int)sVar2)), 0); + } + } + } + } + + } + + else if ((DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + == 0) + && (iVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, + this)(_aiType + -1, playerID), + DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk < iVar4)) { + + if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) + && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, TRUE), + BVar5 == FALSE)) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + playerID, (undefined4)((int)(_indexTo6))); + + if (_buildingID != 0) { + + LAB_004d2d6f: + _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] + .buildingEntryY] + .addXgetTile; + + goto LAB_004d2d8d; + } + + _buildingID_2 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + + if (_buildingID_2 != 0) + goto LAB_004d2c00; + } + + } + + else if ((DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb6) + || (DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb5)) { + + if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) + && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, FALSE), + BVar5 == FALSE)) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk, + (undefined4)((int)(_indexTo6))); + + if (_buildingID == 0) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, + this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + + goto LAB_004d2d6b; + } + + goto LAB_004d2d6f; + } + + } + + else { + + BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, FALSE); + + if (BVar5 == FALSE) { + + iVar4 = (int)DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID; + + if ((((iVar4 == 0) + || (DAT_BuildingsState::instance.buildings[iVar4].uid + != DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID)) + || (DAT_BuildingsState::instance.buildings[iVar4].fireDuration != 0)) + || (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, TRUE), + BVar5 == FALSE)) { + + iVar4 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, + this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + + if (iVar4 == 0) { + + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .someTotalDefenseTroopsRelatedCountdown = 0; + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, + DAT_UnitsState::ptr)(_tribeID3, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, iVar4, + DAT_BuildingsState::instance.buildings[iVar4].uid, 0); + + iVar3 = DAT_BuildingsState::instance.buildings[iVar4].uid; + + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = (short)iVar4; + + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID = iVar3; + + DAT_GameState::instance.playerDataArray[playerID] + .someTotalDefenseTroopsRelatedCountdown = 100; + } + + } + + else { + + if (DAT_GameState::instance.mapAndTime.yearChanged != 0) { + + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; + } + + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + = 100; + } + } + } + } + + _ptrTribeID3 = _ptrTribeID3 + 1; + + _indexTo6 = _indexTo6 + TRUE; + + } while ((int)_indexTo6 < 6); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp b/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp new file mode 100644 index 000000000..0de10b080 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp @@ -0,0 +1,55 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Game::Player::PlayerData; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + 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 0x004D0580 + BOOLEnum AICState ::aiOfTypeInCurrentGame(int param_1) + + { + + int* _ptrCurrentAIArray; + + PlayerData* _playerData; + + _playerData = &DAT_GameState::instance.playerDataArray[1]; + + _ptrCurrentAIArray = DAT_GameSynchronyState::instance.currentAIArray + 1; + + while (((*_ptrCurrentAIArray == 0 || (_playerData->lordKilledByPlayerID != 0)) + || (param_1 != _playerData->aiType + ~OpenSHC::AI::AIT_NULL))) { + + _ptrCurrentAIArray = _ptrCurrentAIArray + 1; + + _playerData = _playerData + 0xe7d; + + if (0x191de9f < (int)_ptrCurrentAIArray) { + + return FALSE; + } + } + + return TRUE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp index 3c745352a..4b40f07e0 100644 --- a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp @@ -13,22 +13,17 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D40B0 void AICState::aiReassignTunnelersToTribe(int param_1) { - uint unitID = 1; - if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { - Map::Units::Unit* psVar1 = &DAT_UnitsState::instance.units[1]; - do { - if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == param_1)) - && (psVar1->dying == 0)) - && ((psVar1->unitType == Map::Units::UT_TUNNELER && (psVar1->aiUnitBehaviourType == 0xf)))) { - if (psVar1->tribeID != 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( - unitID, (int)psVar1->tribeID); - } - MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 0xf); + for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { + Map::Units::Unit* _pUnit = &DAT_UnitsState::instance.units[unitID]; + if ((((_pUnit->logicalState == Map::Units::ULS_NORMAL) && (_pUnit->owner == param_1)) + && (_pUnit->dying == 0)) + && ((_pUnit->unitType == Map::Units::UT_TUNNELER && (_pUnit->aiUnitBehaviourType == 0xf)))) { + if (_pUnit->tribeID != 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, (int)_pUnit->tribeID); } - unitID = unitID + 1; - psVar1 = psVar1 + 1; - } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 0xf); + } } } } diff --git a/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp new file mode 100644 index 000000000..3b011e85d --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp @@ -0,0 +1,113 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Map::Units::UnitType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD690 + void AICState ::aiRecruitSortieMeleeUnits(int playerID) + + { + + AITypeInt AVar1; + + int iVar2; + + int _unitID; + + int _section1016id; + + UnitType _unitType; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 != OpenSHC::AI::AIT_NULL) { + + iVar2 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + + _section1016id = *(int*)((int)this + iVar2 + 0x154); + + if (((((-1 < _section1016id) + && (DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 < _section1016id)) + && (0 < DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount)) + && ((DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0 + && (_unitType = *(UnitType*)((int)this + iVar2 + 0x158), + _unitType != OpenSHC::Map::Units::UT_E_ENGINEER)))) + && ((_unitType != OpenSHC::Map::Units::UT_E_LADDER + && (_unitType != OpenSHC::Map::Units::UT_TUNNELER)))) { + + if ((int)_unitType < 0x46) { + + _section1016id = DAT_GameState::instance.playerDataArray[playerID].barracks.id; + + } + + else { + + _section1016id = DAT_GameState::instance.playerDataArray[playerID].mercenaryPost.id; + } + + if (_section1016id != 0) { + + if ((int)_unitType < 0x46) { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_section1016id)), playerID, 0); + + } + + else { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_section1016id)), playerID, 0); + } + + if (_unitID == 0) { + + _section1016id = *(int*)((int)this + iVar2 + 0x9c); + + if ((0 < _section1016id) && (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason == 2)) { + + DAT_GameState::instance.playerDataArray[playerID] + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] + = _section1016id; + + return; + } + + } + + else { + + DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType = 7; + + _section1016id = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::createTribeForUnitType, this)( + playerID, (int)((int)(167))); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + _unitID, _section1016id); + } + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp new file mode 100644 index 000000000..b9e473e21 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp @@ -0,0 +1,117 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Map::Units::UnitType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD560 + void AICState ::aiRecruitSortieRangedUnits(int playerID) + + { + + UnitType unitType; + + int iVar1; + + uint _unitID; + + int iVar2; + + int _buildingID; + + AITypeInt _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType != OpenSHC::AI::AIT_NULL) { + + iVar1 = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + + iVar2 = *(int*)((int)this + iVar1 + 0x14c); + + /* + bug: missing != 0? */ + + if (((((-1 < iVar2) + && (DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 + < DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 / 2 + iVar2)) + && (0 < DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount)) + && ((DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0 + && (unitType = *(UnitType*)((int)this + iVar1 + 0x150), + unitType != OpenSHC::Map::Units::UT_E_ENGINEER)))) + && ((unitType != OpenSHC::Map::Units::UT_E_LADDER && (unitType != OpenSHC::Map::Units::UT_TUNNELER)))) { + + if ((int)unitType < 0x46) { + + _buildingID = DAT_GameState::instance.playerDataArray[playerID].barracks.id; + + } + + else { + + _buildingID = DAT_GameState::instance.playerDataArray[playerID].mercenaryPost.id; + } + + if (_buildingID != 0) { + + if ((int)unitType < 0x46) { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, + DAT_UnitsState::ptr)(unitType, (undefined4)((int)(_buildingID)), playerID, 0); + + } + + else { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, + DAT_UnitsState::ptr)(unitType, (undefined4)((int)(_buildingID)), playerID, 0); + } + + if (_unitID == 0) { + + iVar2 = *(int*)((int)this + iVar1 + 0x9c); + + if ((0 < iVar2) && (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason == 2)) { + + DAT_GameState::instance.playerDataArray[playerID] + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = iVar2; + + return; + } + + } + + else { + + DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType = 6; + + iVar2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::createTribeForUnitType, this)( + playerID, (int)((int)(166))); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + _unitID, iVar2); + } + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp new file mode 100644 index 000000000..50877b900 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp @@ -0,0 +1,487 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AIRecruitUnitChoice.hpp" +#include "OpenSHC/AI/AIRecruitUnitChoiceInt.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/AIUnitBehaviourType.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Game/TrailType.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/UnitType.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_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AICState; + using OpenSHC::AI::AIRecruitUnitChoice; + using OpenSHC::AI::AIRecruitUnitChoiceInt; + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIUnitBehaviourType; + using OpenSHC::Game::GameMode2; + using OpenSHC::Game::TrailType; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3AE0 + void AICState ::aiRecruitUnits(int playerID) + + { + + int* piVar1; + + AIRecruitUnitChoiceInt AVar2; + + bool bVar3; + + int iVar4; + + int iVar5; + + int _tribeID_defDiggingUnitMax; + + int _unitID; + + UnitType _unitType; + + int iVar6; + + AICState* _pAICState; + + int local_8; + + int _aicRecruitInterval; + + int _nervousActionTracker; + + int _buildingID; + + int _unitChoiceIndex; + + AIRecruitUnitChoiceInt _unitTypeChoice; + + int _defTotal; + + AITypeInt _aiType; + + int _playerID2; + + bool _recruitDefDiggingUnit; + + _playerID2 = playerID; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + _unitType = ((UnitType)0); + + _pAICState = this; + + if (_aiType != OpenSHC::AI::AIT_NULL) { + + bVar3 = false; + + _recruitDefDiggingUnit = false; + + iVar6 = _aiType + ~OpenSHC::AI::AIT_NULL; + + if (((DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) + && (DAT_GameCore::instance.isSkirmishTrail == TRUE)) + && (DAT_GameCore::instance.currentTrailType == OpenSHC::Game::TT_EXTREME)) { + + bVar3 = true; + } + + iVar4 = iVar6 * 0xa9; + + _aicRecruitInterval = *(int*)((int)this + + (DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + iVar4) * 4 + 0x164); + + local_8 = -(uint)(_aicRecruitInterval != 0) + 2; + + if (bVar3) { + + local_8 = -(uint)(_aicRecruitInterval != 0) + 3; + } + + _nervousActionTracker = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + if (_nervousActionTracker < 1) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker; + + *piVar1 = *piVar1 + 1; + + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker < _aicRecruitInterval) { + + return; + } + + } + + else { + + local_8 = 4; + } + + iVar5 = DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount; + + DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker = 0; + + if ((0 < iVar5) && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) { + + AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState; + + if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { + + _defTotal = *(int*)((int)this + iVar6 * 0x2a4 + 0x170); + + if (bVar3) { + + _defTotal = (_defTotal * 4) / 3; + } + + if (0 < _nervousActionTracker) { + + _defTotal = _defTotal * 4; + } + + if (_defTotal <= DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk) { + + return; + } + + } + + else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { + + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( + iVar6, playerID); + + if (iVar5 <= DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk) { + + return; + } + + } + + else if ((AVar2 == OpenSHC::AI::AIRUC_ATTACKING) + && (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState != 0)) { + + return; + } + + iVar6 = iVar6 * 0x2a4; + + /* + DefDiggingUnitMax */ + + /* + DefDiggingUnitMax */ + + if (((*(int*)((int)this + iVar6 + 0x15c) != 0) + && (iVar5 + = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, + DAT_TileMapState::ptr)(playerID), + iVar5 != 0)) + && ((_tribeID_defDiggingUnitMax + = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10], + _tribeID_defDiggingUnitMax == 0 + || ((DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10] + != DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].uid + || ((int)DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].size + < *(int*)((int)this + iVar6 + 0x15c))))))) { + + _recruitDefDiggingUnit = true; + } + + playerID = 0; + + if (0 < local_8) { + + do { + + if (_recruitDefDiggingUnit) { + + if (((byte)SEC_RNG::instance.currentNumber2 & 1) != 0) { + + _recruitDefDiggingUnit = false; + + goto LAB_004d3cc1; + } + + if (DAT_GameState::instance.playerDataArray[_playerID2].barracks.id == 0) { + + if (DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id == 0) { + + return; + } + + /* + DefDiggingUnit */ + + _unitType = *(UnitType*)((int)this + iVar6 + 0x160); + + } + + else { + + /* + DefDiggingUnit */ + + _unitType = *(UnitType*)((int)this + iVar6 + 0x160); + } + + } + + else { + + LAB_004d3cc1: + _unitTypeChoice + = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; + + if (_unitTypeChoice == OpenSHC::AI::AIRUC_DEFENSIVE) { + + if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex) { + + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; + } + + /* + DefUnit 1 up to 8 */ + + if (*(int*)((int)this + + (DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex + + iVar4) + * 4 + + 0x184) + == 0) { + + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; + } + + _unitChoiceIndex + = DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex; + + /* + DefUnit 1 up to 8 */ + + _unitType = *(UnitType*)((int)this + (iVar4 + _unitChoiceIndex) * 4 + 0x184); + + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex + = _unitChoiceIndex + 1; + + } + + else if (_unitTypeChoice == OpenSHC::AI::AIRUC_RAIDING) { + + if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex) { + + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; + } + + if (*(int*)((int)this + + (DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex + + iVar4) + * 4 + + 0x1ac) + == 0) { + + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; + } + + iVar5 = DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex; + + _unitType = *(UnitType*)((int)this + (iVar4 + iVar5) * 4 + 0x1ac); + + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = iVar5 + 1; + + } + + else if (_unitTypeChoice == OpenSHC::AI::AIRUC_ATTACKING) { + + _pAICState = (AICState*)MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::randomlySelectAttackUnitTypeToRecruit, this)( + _playerID2); + + _unitType + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getUnitTypeForUnitBehaviourType, + this)(_playerID2, (AIUnitBehaviourType)((int)(_pAICState))); + } + } + + if (_unitType == ((UnitType)0)) { + + return; + } + + if (_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) { + + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; + + } + + else if (_unitType == OpenSHC::Map::Units::UT_E_LADDER) { + + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; + + } + + else if (_unitType == OpenSHC::Map::Units::UT_TUNNELER) { + + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].tunnelersGuild.id; + + } + + else if (_unitType == OpenSHC::Map::Units::UT_E_MONK) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(_playerID2, OpenSHC::Map::Buildings::BT_CATHEDRAL); + + } + + else if ((int)_unitType < 0x46) { + + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].barracks.id; + + } + + else { + + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id; + } + + if (_buildingID == 0) { + + return; + } + + if ((((_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) + || (_unitType == OpenSHC::Map::Units::UT_E_LADDER)) + || (_unitType == OpenSHC::Map::Units::UT_TUNNELER)) + || ((_unitType == OpenSHC::Map::Units::UT_E_MONK || (0x45 < (int)_unitType)))) { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); + + } + + else { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); + } + + if (_unitID == 0) { + + /* + tradeAmountEquipment */ + + iVar6 = *(int*)((int)this + iVar6 + 0x9c); + + if (iVar6 < 1) { + + return; + } + + if (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason != 2) { + + return; + } + + if (DAT_GameState::instance.playerDataArray[_playerID2].aiNervousActionsTracker < 1) { + + DAT_GameState::instance.playerDataArray[_playerID2] + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] + = iVar6; + + return; + } + + DAT_GameState::instance.playerDataArray[_playerID2] + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = 5; + + return; + } + + if (_recruitDefDiggingUnit) { + + /* + digging units? */ + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); + + } + + else { + + AVar2 = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; + + /* + 0 = defensive, 1 = raid, 2 = army */ + + if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { + + if (DAT_GameState::instance.playerDataArray[_playerID2].totalDefensiveTroopsUnk + < *(int*)((int)this + iVar6 + 0x180)) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignUnitToATribe, this)(_unitID); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToSmallestPatrolTribe, this)( + _unitID); + } + + } + + else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignUnitToDefensiveTribe, this)( + _unitID); + + } + + else if (AVar2 == OpenSHC::AI::AIRUC_ATTACKING) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToItsTribe, this)( + _unitID, (int)((int)(_pAICState))); + } + } + + playerID = playerID + 1; + + if (local_8 <= playerID) { + + return; + } + + } while (true); + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp b/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp new file mode 100644 index 000000000..74dfe4fde --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp @@ -0,0 +1,69 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1950 + void AICState ::aiRegisterTribeAndAssignTarget(int tribeID, int tribeUID) + + { + + int _index; + + short* _tribe; + + int* _uid; + + if (DAT_TribesState::instance.tribes[tribeID].size < 1) { + + DAT_TribesState::instance.tribes[tribeID].tribeState = 3; + + return; + } + + if (DAT_GameState::instance.playerDataArray[DAT_TribesState::instance.tribes[tribeID].owner].aiType + != OpenSHC::AI::AIT_NULL) { + + _index = 0; + + _uid = this->tribeUIDArray; + + _tribe = this->tribeIDArray; + + do { + + if ((*_tribe == 0) || (DAT_TribesState::instance.tribes[*_tribe].uid != *_uid)) { + + this->tribeIDArray[_index] = (short)tribeID; + + this->tribeUIDArray[_index] = tribeUID; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTargetForTribeBasedOnTargetChoiceLogic, this)( + DAT_TribesState::instance.tribes[tribeID].owner, tribeID); + + return; + } + + _index = _index + 1; + + _tribe = _tribe + 1; + + _uid = _uid + 1; + + } while (_index < 1000); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp new file mode 100644 index 000000000..a1c8bb331 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp @@ -0,0 +1,147 @@ +#include "OpenSHC/AI/AICState.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_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Buildings::BuildingType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB3A0 + undefined4 AICState ::aiRequiresExtraOxtethers(int playerID) + + { + + int* piVar1; + + int _buildingID; + + int _oxTetherCount; + + int _linkedTetherID; + + short* _linkedTetherIDs; + + int _linkedTetherCount; + + int _oxTetherLoopIndex; + + int _quarryID; + + int _stoneWaiting; + + int _playerID; + + _playerID = playerID; + + _buildingID + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_QUARRY); + + _quarryID = 0; + + /* + reuse of playerID!! */ + + playerID = 0; + + _oxTetherCount = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(_playerID, OpenSHC::Map::Buildings::BT_OXTETHER, 1); + + if (9 < _oxTetherCount) { + + return (undefined4)(0); + } + + piVar1 = &DAT_GameState::instance.playerDataArray[_playerID].highestLoadedQuarryUnk; + + *piVar1 = 0; + + if (_buildingID != 0) { + + do { + + _stoneWaiting + = DAT_BuildingsState::instance + .buildings[(short)DAT_BuildingsState::instance.buildings[_buildingID].quarryStockpileID] + .resourceStone; + + _linkedTetherCount = 0; + + _linkedTetherIDs = DAT_BuildingsState::instance.buildings[_buildingID].quarryLinkedOxTethers; + + _oxTetherLoopIndex = 3; + + do { + + _linkedTetherID = (int)*_linkedTetherIDs; + + if (_linkedTetherID != 0) { + + if ((DAT_BuildingsState::instance.buildings[_linkedTetherID].buildingType + == OpenSHC::Map::Buildings::BT_OXTETHER) + && (DAT_BuildingsState::instance.buildings[_linkedTetherID].oxtetherLinkedQuarryID + == _buildingID)) { + + _linkedTetherCount = _linkedTetherCount + 1; + + } + + else { + + *_linkedTetherIDs = 0; + } + } + + _linkedTetherIDs = _linkedTetherIDs + 1; + + _oxTetherLoopIndex = _oxTetherLoopIndex + -1; + + } while (_oxTetherLoopIndex != 0); + + if (_linkedTetherCount < 1) { + + *piVar1 = _buildingID; + + return (undefined4)(1); + } + + /* + store the highest ratio of stone in quarry stockpile divided by linked ox + tethers */ + + if (playerID < _stoneWaiting / _linkedTetherCount) { + + playerID = _stoneWaiting / _linkedTetherCount; + + _quarryID = _buildingID; + } + + _buildingID + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findNextBuildingForPlayerAndType, + DAT_BuildingsState::ptr)(_playerID, OpenSHC::Map::Buildings::BT_QUARRY, _buildingID); + + } while (_buildingID != 0); + + /* + if the highest ratio is larger than 20, return true */ + + if (20 < playerID) { + + *piVar1 = _quarryID; + + return (undefined4)(1); + } + } + + return (undefined4)(0); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp new file mode 100644 index 000000000..d2308602d --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -0,0 +1,123 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + doc:| + Retreat units to campfire or keep + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE4D0 + void AICState ::aiRetreatUnits(short* playerID) + + { + + BOOLEnum BVar1; + + int _counter; + + int _tribeID; + + int* local_8; + + int _aiBehaviourType; + + int _groupCount; + + short* _playerID; + + _playerID = playerID; + + if (DAT_GameState::instance.playerDataArray[(int)playerID].aiType != OpenSHC::AI::AIT_NULL) { + + local_8 = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + _groupCount = *local_8; + + _aiBehaviourType = (*(int (*)[2])(local_8 + -1))[0]; + + _counter = 0; + + if (0 < _groupCount) { + + playerID = DAT_GameState::instance.playerDataArray[(int)_playerID].aiTribeIDs + _aiBehaviourType; + + do { + + _tribeID = (int)*playerID; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[(int)_playerID] + .aiTribeUIDs[_counter + _aiBehaviourType])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + if (_aiBehaviourType == 0xbe) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, (int)((int)(_playerID))); + + } + + else if (_aiBehaviourType == 0xd) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, (int)((int)(_playerID))); + + } + + else { + + BVar1 + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + + if (BVar1 == FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( + _tribeID, (int)((int)(_playerID))); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, (int)((int)(_playerID))); + } + } + } + + playerID = playerID + 1; + + _counter = _counter + 1; + + } while (_counter < _groupCount); + } + + local_8 = local_8 + 2; + + } while ((int)local_8 < 0xb42a2c); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp new file mode 100644 index 000000000..173aa0643 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp @@ -0,0 +1,112 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.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_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Game::GameMode2; + using OpenSHC::Game::Player::PlayerData; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDCF0 + BOOLEnum AICState ::aiShouldAttackOrWaitForTeamCoordination(int playerID) + + { + + AITypeInt _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) { + return FALSE; + } + + if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 1) { + return TRUE; + } + + int _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + if (DAT_GameState::instance.playerDataArray[_attackedPlayerID].totalTroopValue < 100) { + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 0; + } + + int _attForceBase = *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 500); + int _currentWaveStrength = DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; + int _totalAttack = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops; + + if (_totalAttack < _attForceBase + _currentWaveStrength) { + return FALSE; + } + + if (DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel == 0) { + return TRUE; + } + + int _readyTeamMembers = 0; + int _unreadyTeamMembers = 0; + int _iPlayer = 1; + PlayerData* _pPlayerData = &DAT_GameState::instance.playerDataArray[1]; + + do { + if (_iPlayer != playerID) { + int _isAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_iPlayer); + if (_isAlive != 0) { + BOOLEnum _isAI = MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, + DAT_GameSynchronyState::ptr)(_iPlayer); + if (_isAI != FALSE) { + if (DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + if (_pPlayerData->aiPlayerState != 0) { + return TRUE; + } + if (_pPlayerData->totalAttackTroops - _pPlayerData->totalAttackingEngineerTroops + < *(int*)((int)DAT_EntityState::instance.seagullArray + _pPlayerData->aiType * 0x2a4 + + 0x2664) + + _pPlayerData->currentWaveRandomAttackingStrength) { + _unreadyTeamMembers = _unreadyTeamMembers + 1; + } + else { + _readyTeamMembers = _readyTeamMembers + 1; + } + } + } + } + } + _iPlayer = _iPlayer + 1; + _pPlayerData = _pPlayerData + 1; + } while (_iPlayer < 9); + + if (_readyTeamMembers >= DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel) { + return TRUE; + } + if (_unreadyTeamMembers == 0) { + return TRUE; + } + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience = + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience + 1; + if (DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience <= 0x30 + || (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CAMPAIGN_MISSION)) { + return FALSE; + } + + return TRUE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp new file mode 100644 index 000000000..8bf86d291 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp @@ -0,0 +1,157 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CAEA0 + void AICState ::aiUpdateTaxesAndRations(int playerID) + { + int _offset; + int _newTaxesVal; + int _newTaxes; + int _popularity; + int _currentTaxes; + int _taxesMin; + int _taxesMax; + int _peasants; + int _decision; + int _totalFood_2; + int _totalFood_1; + int _taxes; + AITypeInt _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) { + return; + } + + _offset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + + _popularity = DAT_GameState::instance.playerDataArray[playerID].popularity; + + // criticalPopularity - comparison order matches original: first jg sets decision=2 (critical) + if (*(int*)((int)this + _offset + 0x18) >= _popularity) { + DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 2; + } else if (*(int*)((int)this + _offset + 0x1c) < _popularity) { + // highestPopularity + if (*(int*)((int)this + _offset + 0x20) >= _popularity) { + DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 0; + } + } else { + DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 1; + } + + _decision = DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue; + + if (_decision == 2) { + _totalFood_2 = DAT_GameState::instance.playerDataArray[playerID].totalFood; + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 2; + + if (_totalFood_2 <= 0) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; + } else if (_totalFood_2 < 5) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; + } else { + int _r = 0; + if (_totalFood_2 > 8) _r = 1; + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = _r + 3; + } + + goto LAB_004cb010; + } + + if (_decision == 1) { + _currentTaxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; + _taxesMin = *(int*)((int)this + _offset + 0x24); + + if (_taxesMin < _currentTaxes) { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _currentTaxes - 1; + } else { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxesMin; + } + + _totalFood_1 = DAT_GameState::instance.playerDataArray[playerID].totalFood; + + if (_totalFood_1 <= 0) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; + } else { + if (_totalFood_1 <= 0xa) + goto LAB_004caff1; + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 3; + } + } else { + if (_decision != 0) + goto LAB_004cb010; + + _taxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; + _taxesMax = *(int*)((int)this + _offset + 0x28); + + if (_taxes < _taxesMax) { + _peasants = DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants; + int _r2 = 0; + if (_peasants < 0xf) { + if (_peasants >= 0xa) _r2 = 1; + _newTaxesVal = _r2 + 4; + } else { + _newTaxesVal = 6; + } + + if (DAT_GameState::instance.playerDataArray[playerID].storedPopularityPercent > _popularity) { + if (_taxes <= _newTaxesVal) + goto LAB_004cafcd; + _newTaxes = _taxes - 1; + } else { + _newTaxes = _taxes + 1; + } + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _newTaxes; + } else { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxesMax; + } + + LAB_004cafcd: + _totalFood_1 = DAT_GameState::instance.playerDataArray[playerID].totalFood; + + if (_totalFood_1 < 0xb) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; + goto LAB_004cb010; + } + + LAB_004caff1: + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; + } + + _newTaxes = *(int*)((int)this + _offset + 0xa8); + + if ((_newTaxes != 0) && (_newTaxes <= _totalFood_1)) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; + } + + LAB_004cb010: + if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting < 0) { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 0; + } + + if (11 < DAT_GameState::instance.playerDataArray[playerID].taxesSetting) { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 11; + } + + if (DAT_GameState::instance.playerDataArray[playerID].rationsSetting < 0) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; + } + + if (4 < DAT_GameState::instance.playerDataArray[playerID].rationsSetting) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; + } + + return; + } +} +} diff --git a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp index 5cbcef48a..f3cfc8926 100644 --- a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp +++ b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp @@ -41,7 +41,8 @@ namespace AI { MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); return; } - _tribeID = MACRO_CALL_MEMBER(AICState_Func::smallestTribeOfUnitType, this)(_playerID, _unitTypeIndex); + _tribeID = MACRO_CALL_MEMBER(AICState_Func::smallestTribeOfUnitType, this)( + _playerID, (OpenSHC::Map::Units::UnitType)((int)_unitTypeIndex)); MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); } } diff --git a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp new file mode 100644 index 000000000..27cb9b4c3 --- /dev/null +++ b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp @@ -0,0 +1,129 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" +#include "OpenSHC/Game/Resources/ResourceTypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Game::Resources::ResourceType; + using OpenSHC::Game::Resources::ResourceTypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + Walks the AIC resource acquisition preference order (up to 25 entries in + DAT_ResourceAcquisitionPreferenceOrder) and attempts to buy the first resource for which the + player has a non-zero resourcesToAcquireArray entry and meets one of the spending conditions: + popularity is below the AIC minimum threshold (only checked for the first 4 entries), the AI is + nervous, or the canStartSpending flag is set. If the AI is nervous, entries 0-11 (non-weapon + resources) are skipped entirely so it only buys weapons. A special override fires first inside + the loop: if the building-destroy tracker is non-zero AND the player has fewer than 20 wood, the + resource type is forced to RT_WOOD regardless of the preference order. Before calling buyGoods() + the required gold is computed via getBuyPrice(); if the AI cannot afford the purchase it calls + requestGoods() from a teammate at double the desired amount instead. On a successful purchase + resourcesToAcquireArray for that resource is cleared and the function returns immediately, + buying at most one resource type per call. */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D39B0 + void AICState ::buyRequiredGoods(int param_1) + + { + + AITypeInt AVar1; + + int amount; + + int playerID; + + int iVar2; + + BOOLEnum BVar3; + + ResourceTypeInt resourceType; + + playerID = param_1; + + /* + buying */ + + AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + + return; + } + + /* + reused! playerID now means a counter */ + + param_1 = 0; + + do { + + resourceType = DAT_SkirmishDefinedData::instance.DAT_ResourceAcqusitionPreferenceOrder[param_1]; + + /* + If nervous, only buy from entry 12 onwards, which are weapons */ + + if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) || (12 < param_1)) { + + if ((DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker != 0) + && (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] < 20)) { + + /* + if short on wood, buy wood! */ + + resourceType = OpenSHC::Game::Resources::RT_WOOD; + } + + amount = DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType]; + + if ((amount != 0) + && ((((param_1 < 4 + && (DAT_GameState::instance.playerDataArray[playerID].popularity + < *(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x18))) + || (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker)) + || (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)))) { + + iVar2 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::getBuyPrice, DAT_GameState::ptr)( + playerID, (int)((int)(resourceType)), amount); + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < iVar2) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::requestGoods, this)( + playerID, (ResourceType)((int)(resourceType)), amount * 2); + + } + + else { + + BVar3 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::buyGoods, this)( + playerID, (ResourceType)((int)(resourceType)), amount); + + if (BVar3 != FALSE) { + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType] = 0; + + return; + } + } + } + } + + param_1 = param_1 + 1; + + } while (param_1 < 25); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp new file mode 100644 index 000000000..595a02e11 --- /dev/null +++ b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp @@ -0,0 +1,105 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingTypeInt.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Buildings::BuildingTypeInt; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDB20 + int AICState ::chooseRandomBuildingIDFromPlayersArrayOfBuildings(int playerID) + + { + + int _chosenBuilding; + + int _selectionIndex; + + int _chosenBuildingTypeIndex; + + short* _ptr_buildingIDArray; + + int _buildingID; + + BuildingTypeInt _buildingType; + + bool bVar1; + + _selectionIndex = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + + _chosenBuilding = 0; + + _chosenBuildingTypeIndex = 46; + + if (0 < _selectionIndex) { + + _ptr_buildingIDArray = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings; + + playerID = _selectionIndex; + + do { + + _buildingID = (int)*_ptr_buildingIDArray; + + if ((_buildingID != 0) && (_selectionIndex = 0, 0 < _chosenBuildingTypeIndex)) { + + _buildingType + = (BuildingTypeInt)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType; + + do { + + if (((byte)SEC_RNG::instance.currentNumber2 & 7) < 2) { + + bVar1 = _buildingType + == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet3[_selectionIndex]; + + } + + else if (((byte)SEC_RNG::instance.currentNumber2 & 7) < 4) { + + bVar1 = _buildingType + == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet2[_selectionIndex]; + + } + + else { + + bVar1 = _buildingType + == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_selectionIndex]; + } + + if (bVar1) { + + /* + very unique way to break from a loop ;) */ + + _chosenBuilding = _buildingID; + + _chosenBuildingTypeIndex = _selectionIndex; + } + + _selectionIndex = _selectionIndex + 1; + + } while (_selectionIndex < _chosenBuildingTypeIndex); + } + + _ptr_buildingIDArray = _ptr_buildingIDArray + 1; + + playerID = playerID + -1; + + } while (playerID != 0); + } + + return _chosenBuilding; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp new file mode 100644 index 000000000..91ef8a70c --- /dev/null +++ b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp @@ -0,0 +1,67 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF870 + void AICState ::clearOutdatedAITribes(int playerID) + + { + + if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { + + int _index = 0; + + do { + + if (_index != 8) { + + int _groupCount + = DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[_index][1]; + + int _tribeType + = DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[_index][0]; + + int _offset = 0; + + if (0 < _groupCount) { + + short* _ptrTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeType; + + do { + int _tribeIDVal = (int)*_ptrTribeID; + if ((_tribeIDVal != 0) + && (DAT_TribesState::instance.tribes[_tribeIDVal].uid + != DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_offset + _tribeType])) { + + *_ptrTribeID = 0; + + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_offset + _tribeType] = 0; + } + + _offset = _offset + 1; + + _ptrTribeID = _ptrTribeID + 1; + + } while (_offset < _groupCount); + } + } + + _index = _index + 1; + + } while (_index < 0xb); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp new file mode 100644 index 000000000..ca0fa349b --- /dev/null +++ b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp @@ -0,0 +1,52 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Synchrony::GameSynchronyState; + + /* + 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 0x004CAC70 + void AICState ::clearPlayerDataInformationChunk() + + { + + GameSynchronyState* piVar1; + + int* _Dst; + + _Dst = &DAT_GameState::instance.playerDataArray[0].aiFarmIndex; + + piVar1 = (GameSynchronyState*)DAT_GameSynchronyState::instance.currentAIArray; + + do { + + if ((piVar1->currentPlayerFullIDArray[0] != -1) || (piVar1->currentAIArray[0] == 0)) { + + MACRO_CALL(OpenSHC::OS_Func::_memset)(_Dst, 0, (size_t)((int)(3748))); + } + + piVar1 = (GameSynchronyState*)(piVar1->currentAIArray + 1); + + _Dst = _Dst + 3709; + + } while ((int)piVar1 < 0x191dea0); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp new file mode 100644 index 000000000..548106804 --- /dev/null +++ b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp @@ -0,0 +1,89 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE790 + void AICState ::clearRallyFlagOnAllAIAttackTribes(int param_1) + + { + + int _tribeID; + + int _counter; + + short* _ptrTribeID; + + int* _ptrTribeCount; + + int _tribeCount; + + int _tribeType; + + if (DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) { + + _ptrTribeCount + = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + /* + first iteration: 3 */ + + _tribeCount = *_ptrTribeCount; + + /* + first iteration: 186 */ + + _tribeType = (*(int (*)[2])(_ptrTribeCount + -1))[0]; + + /* + first iteration: 0 */ + + _counter = 0; + + if (0 < _tribeCount) { + + _ptrTribeID = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + _tribeType; + + do { + + _tribeID = (int)*_ptrTribeID; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1] + .aiTribeUIDs[_counter + _tribeType])) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, + DAT_TribesState::ptr)(_tribeID); + } + + _counter = _counter + 1; + + _ptrTribeID = _ptrTribeID + 1; + + } while (_counter < _tribeCount); + } + + _ptrTribeCount = _ptrTribeCount + 2; + + } while ((int)_ptrTribeCount < 0xb42a2c); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp b/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp new file mode 100644 index 000000000..d701a1a34 --- /dev/null +++ b/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp @@ -0,0 +1,68 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF7C0 + void AICState ::commandFourTribesToMove(int playerID) + + { + + if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { + + int _counter2 = 0; + + int _counter = 0; + + short* _ptrTribeIDArray = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xba; + + do { + + int _tribeID = (int)*_ptrTribeIDArray; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_counter + 0xba])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; + + /* + fixme: array too small? */ + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_counter2] + .xOffset)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_counter2] + .yOffset)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + _counter2 = _counter2 + 1; + } + + _counter = _counter + 1; + + _ptrTribeIDArray = _ptrTribeIDArray + 1; + + } while (_counter < 3); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp new file mode 100644 index 000000000..e73d9dff7 --- /dev/null +++ b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp @@ -0,0 +1,60 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Game::Player::PlayerData; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2EC0 + void AICState ::computeAttackPossibilities(int playerID) + + { + + PlayerData* piVar1; + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID]; + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIInfoLayer))); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackPrimeInfo, this)(playerID, piVar1->attackedPlayerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::recomputeTargetedBuildingTilesArray, + DAT_TroopValueState::ptr)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::recomputeAttackInfo, DAT_TroopValueState::ptr)( + playerID, piVar1->attackedPlayerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::computeSiegeSpotScores, DAT_TroopValueState::ptr)( + piVar1->attackedPlayerID, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setScale3, DAT_TroopValueState::ptr)(1, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setTown2, DAT_TroopValueState::ptr)(1, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setGate2, DAT_TroopValueState::ptr)(1, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setWide3, DAT_TroopValueState::ptr)(1, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setMoat3, DAT_TroopValueState::ptr)(1, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::calculateAttackVectorsToCampFireOfPlayer, + DAT_GameState::ptr)(piVar1->attackedPlayerID); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp new file mode 100644 index 000000000..3143812d5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp @@ -0,0 +1,173 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/AI/TileDistancePair.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::TileDistancePair; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE200 + void AICState ::computeEnemyKeepApproachTile(int playerID) + + { + + int _shortestDistanceTile; + + int _shortestDistanceX; + + TileDistancePair* _tilePointer; + + int iVar1; + + int* _distancePointer; + + int _shortestDistance; + + int local_c; + + int _keepX; + + int _keepY; + + int _tile; + + short _y; + + _keepX = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; + + _keepY = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; + + this->aiBorderTilesIndex = 0; + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 8000, '\0', (void*)((int)(this->aiBorderTiles))); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); + + local_c = 0; + + if (0 < this->aiBorderTilesIndex) { + + _distancePointer = &this->aiBorderTiles[0].distance; + + do { + + _tile = ((TileDistancePair*)(_distancePointer + -1))->tile; + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(_keepX, _keepY, + _tile + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance + .DAT_TileTranslationMatrix_YComponent[_tile]] + .addXgetTile, + (int)((int)(DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]))); + + /* + avoiding unit death areas */ + + *_distancePointer = (uint)DAT_TileMapState::instance.unitDeathHeatMap[_tile] + + DAT_DirectionAlgorithmState::instance.distanceHigh; + + local_c = local_c + 1; + + _distancePointer = _distancePointer + 2; + + } while (local_c < this->aiBorderTilesIndex); + } + + _shortestDistanceTile = 0; + + _shortestDistance = 100000; + + if (0 < this->aiBorderTilesIndex) { + + _tilePointer = this->aiBorderTiles; + + iVar1 = this->aiBorderTilesIndex; + + do { + + if (_tilePointer->distance < _shortestDistance) { + + _shortestDistanceTile = _tilePointer->tile; + + _shortestDistance = _tilePointer->distance; + } + + _tilePointer = _tilePointer + 1; + + iVar1 = iVar1 + -1; + + } while (iVar1 != 0); + } + + /* + sets the first attack distance to the enemy keep */ + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile = 0; + + if (0 < _shortestDistanceTile) { + + _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_shortestDistanceTile]; + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY = (int)_y; + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile = _shortestDistanceTile; + + _shortestDistanceX + = _shortestDistanceTile - DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX = _shortestDistanceX; + + DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][0] = _shortestDistanceX; + + DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][1] + = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY; + + if ((short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX] + != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)( + (int)(short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]); + } + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + DAT_PathFindingState::ptr)(DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][0], + (uint)((int)(DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][1])), -1, -1, 2000, + FALSE); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::storeDestinationOptionsUnk, + DAT_PathFindingState::ptr)(playerID + -1); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/computeNervousness.cpp b/src/OpenSHC/AI/AICState/computeNervousness.cpp new file mode 100644 index 000000000..2d0d9f26e --- /dev/null +++ b/src/OpenSHC/AI/AICState/computeNervousness.cpp @@ -0,0 +1,86 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3780 + void AICState ::computeNervousness(int playerID) + + { + + int iVar1; + + int _someCutoff; + + int _totalTroopValueOfEnemy; + + iVar1 = DAT_TroopValueState::instance.attackInfo.playerTotalTroopValueOfTroopsNearKeep[playerID]; + + _totalTroopValueOfEnemy = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; + + int _one = 1; + + if (_totalTroopValueOfEnemy < 50) { + + _someCutoff = _one - 0x15; + + } + + else if (_totalTroopValueOfEnemy < 100) { + + _someCutoff = 0; + + } + + else if (_totalTroopValueOfEnemy < 200) { + + _someCutoff = 20; + + } + + else if (_totalTroopValueOfEnemy < 400) { + + _someCutoff = 100; + + } + + else if (_totalTroopValueOfEnemy < 600) { + + _someCutoff = 200; + + } + + else { + + _someCutoff = ((_totalTroopValueOfEnemy >= 800) - _one & 0xffffff38) + 500; + } + + if (iVar1 > _someCutoff + _totalTroopValueOfEnemy) { + + DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue = 0; + + return; + } + + if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue == 0) { + + if (iVar1 < DAT_GameState::instance.playerDataArray[playerID] + .totalEnemyTroopValueByPlayerID[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playNervous1BikFromPlayer, this)(playerID); + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playRequestHelpBikFromPlayer, this)(playerID); + } + + DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue = _one; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp b/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp new file mode 100644 index 000000000..e58e36158 --- /dev/null +++ b/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp @@ -0,0 +1,63 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/Unit.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitTypeShort.hpp" + +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Unit; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::UnitTypeShort; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFBC0 + int AICState::countSiegeEngineUnits(int playerID) + { + int _count = 0; + Unit* _units = &DAT_UnitsState::instance.units[0]; + + for (int i = 1; i < 2500; i += 1) { + // Unit[1] + if (_units[i].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE && _units[i].owner == playerID + && _units[i].unknownSiegeTentRelated02 == 3 && _units[i].aiUnitBehaviourType != 0x15) { + UnitTypeShort t = _units[i].unitType; + if (t == OpenSHC::Map::Units::UT_S_CATAPULT || t == OpenSHC::Map::Units::UT_S_TREBUCHET + || t == OpenSHC::Map::Units::UT_S_TOWER || t == OpenSHC::Map::Units::UT_S_BATTERINGRAM + || t == OpenSHC::Map::Units::UT_S_FBALLISTA) { + _count = _count + 1; + } + } + + // Compiler unrolled the loop because 2499 is divisible by 3? + // // Unit[2] + // if (_units[i + 1].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE && _units[i + 1].owner == playerID + // && _units[i + 1].unknownSiegeTentRelated02 == 3 && _units[i + 1].aiUnitBehaviourType != 0x15) { + // UnitTypeShort t = _units[i + 1].unitType; + // if (t == OpenSHC::Map::Units::UT_S_CATAPULT || t == OpenSHC::Map::Units::UT_S_TREBUCHET + // || t == OpenSHC::Map::Units::UT_S_TOWER || t == OpenSHC::Map::Units::UT_S_BATTERINGRAM + // || t == OpenSHC::Map::Units::UT_S_FBALLISTA) { + // _count = _count + 1; + // } + // } + + // // Unit[3] + // if (_units[i + 2].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE && _units[i + 2].owner == playerID + // && _units[i + 2].unknownSiegeTentRelated02 == 3 && _units[i + 2].aiUnitBehaviourType != 0x15) { + // UnitTypeShort t = _units[i + 2].unitType; + // if (t == OpenSHC::Map::Units::UT_S_CATAPULT || t == OpenSHC::Map::Units::UT_S_TREBUCHET + // || t == OpenSHC::Map::Units::UT_S_TOWER || t == OpenSHC::Map::Units::UT_S_BATTERINGRAM + // || t == OpenSHC::Map::Units::UT_S_FBALLISTA) { + // _count = _count + 1; + // } + // } + }; + + return _count; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp new file mode 100644 index 000000000..59f8a77c5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp @@ -0,0 +1,287 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1A00 + void AICState ::decideOnTribeAttackLocation(uint tribeID_OR_moatWasHit) + + { + + short* psVar1; + + short sVar2; + + bool bVar3; + + BOOLEnum _canHaveActivity; + + int _unitID; + + BOOLEnum BVar4; + + int _targetBuilding; + + int _buildingID; + + int _buildingID_2; + + int iVar5; + + int _destinationX; + + int _targetPlayer; + + int _destinationY; + + int _y; + + int _x; + + int _buildingUID; + + int _rng; + + int _destinationTile; + + uint _tribeID; + + _tribeID = tribeID_OR_moatWasHit; + + _canHaveActivity + = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(tribeID_OR_moatWasHit, FALSE, TRUE); + + if (_canHaveActivity != FALSE) { + + DAT_TribesState::instance.tribes[_tribeID].counter = 0; + + return; + } + + _targetPlayer = (int)DAT_TribesState::instance.tribes[_tribeID].targetPlayer_outpost; + + if (DAT_TribesState::instance.tribes[_tribeID].randomNumber == 0) { + + DAT_TribesState::instance.tribes[_tribeID].randomNumber = (int)SEC_RNG::instance.currentNumber2; + + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + } + + _rng = DAT_TribesState::instance.tribes[_tribeID].randomNumber; + + psVar1 = &DAT_TribesState::instance.tribes[_tribeID].counter; + + *psVar1 = *psVar1 + 1; + + if ((int)DAT_TribesState::instance.tribes[_tribeID].counter == _rng % 6 + 7) { + + DAT_TribesState::instance.tribes[_tribeID].counter = 0; + + /* + WARNING: tribeID has a new purpose */ + + tribeID_OR_moatWasHit = tribeID_OR_moatWasHit & 0xffffff00; + + _x = 0; + + _y = 0; + + _unitID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::getUnitIDForIndexInTribe, DAT_TribesState::ptr)(_tribeID, 0); + + if ((_unitID != 0) + && (bVar3 = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, + DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[_tribeID].owner, _targetPlayer, + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), (byte*)&tribeID_OR_moatWasHit, + &_x, &_y), + bVar3)) { + + if ((char)tribeID_OR_moatWasHit != '\0') { + + /* + moat was not hit */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + _tribeID, ((UnitInstructionType)0x23), + DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile + _x, 0, 0); + + return; + } + + /* + moat was hit */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + _tribeID, OpenSHC::Map::Units::UIT_FILL_MOAT, _x, _y, 1000); + + return; + } + } + + sVar2 = DAT_TribesState::instance.tribes[_tribeID].tribeSubtype1; + + if ((sVar2 != 0xb6) && (sVar2 != 0xb9)) { + + BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, FALSE); + + if (BVar4 != FALSE) { + + return; + } + + _targetBuilding = (int)DAT_TribesState::instance.tribes[_tribeID].targetBuildingID; + + if ((((_targetBuilding != 0) + && (DAT_BuildingsState::instance.buildings[_targetBuilding].uid + == DAT_TribesState::instance.tribes[_tribeID].targetBuildingUID)) + && (DAT_BuildingsState::instance.buildings[_targetBuilding].fireDuration == 0)) + && (BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, TRUE), + BVar4 != FALSE)) { + + if (DAT_GameState::instance.mapAndTime.yearChanged == 0) { + + return; + } + + DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = 0; + + return; + } + + _buildingID = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + DAT_GameState::ptr)(_targetPlayer); + + if (_buildingID != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + _tribeID, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, _buildingID, + DAT_BuildingsState::instance.buildings[_buildingID].uid, 0); + + _buildingUID = DAT_BuildingsState::instance.buildings[_buildingID].uid; + + DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = (short)_buildingID; + + DAT_TribesState::instance.tribes[_tribeID].targetBuildingUID = _buildingUID; + + return; + } + + _destinationX = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; + + DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = 0; + + _destinationY = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry; + + BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(_tribeID, + DAT_ViewportRenderState::instance.translationMatrix[_destinationY].addXgetTile + _destinationX); + + if (BVar4 == FALSE) { + + return; + } + + goto LAB_004d1c59; + } + + _buildingID_2 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + DAT_GameState::ptr)(_targetPlayer); + + if (_buildingID_2 == 0) { + + iVar5 = DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] + .addXgetTile; + + LAB_004d1d11: + _destinationTile = iVar5 + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; + + } + + else { + + iVar5 = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; + + if (iVar5 == 0) { + + _destinationTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryY] + .addXgetTile; + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathfindingForAttacksUnk, + DAT_PathFindingState::ptr)(_tribeID, _buildingID_2, 1, + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance.units[iVar5].tile])), + _targetPlayer); + + _destinationTile = DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile1; + + if (DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper == 0) { + + iVar5 = DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer] + .campground.yEntry] + .addXgetTile; + + goto LAB_004d1d11; + } + } + } + + if (_destinationTile != 0) { + + _destinationY + = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_destinationTile]; + + _destinationX + = _destinationTile - DAT_ViewportRenderState::instance.translationMatrix[_destinationY].addXgetTile; + + BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( + _tribeID, _destinationTile); + + if (BVar4 != FALSE) { + + LAB_004d1c59: + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + _tribeID, (uint)((int)(_destinationX)), (uint)((int)(_destinationY)), 1); + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(_tribeID, _targetPlayer); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp index 85d25c03d..e34daac0d 100644 --- a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp +++ b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp @@ -14,24 +14,30 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB940 undefined4 AICState::destroyBuildingIfNoWorker(int buildingID) { - short _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; - int _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; + short _value; + int _owner; + _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; + _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; if ((((0 < _value) && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1)) && (DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0)) && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY)) { - if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] == 0) { - if (0x13 < _value) { - MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( - (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, - (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( - buildingID); - return 1; + if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] != 0) { +LAB_CHECK_MONTH: + if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { + DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = _value + -1; } - } else if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { - DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = _value + -1; + } else { + if (!((short)0x14 <= _value)) { + goto LAB_CHECK_MONTH; + } + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( + buildingID); + return 1; } } return 0; diff --git a/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp b/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp new file mode 100644 index 000000000..ecdd9457b --- /dev/null +++ b/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp @@ -0,0 +1,55 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D38C0 + BOOLEnum AICState ::determineAIPlayerAttackRequestResponse( + int playerID, undefined4 param_2, int requestedByPlayerID) + + { + + AITypeInt AVar1; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 != OpenSHC::AI::AIT_NULL) { + + if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue == 0) { + + if (DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops + < *(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x1fc)) { + + MACRO_CALL(OpenSHC::Global_Func::PlayWillNotAttack2BikFromPlayerToPlayer)( + playerID, requestedByPlayerID); + + return FALSE; + } + + MACRO_CALL(OpenSHC::Global_Func::PlayWillAttackBikFromPlayerToPlayer)(playerID, requestedByPlayerID); + + return TRUE; + } + + MACRO_CALL(OpenSHC::Global_Func::PlayWillNotAttack1BikFromPlayerToPlayer)(playerID, requestedByPlayerID); + } + + return FALSE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp b/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp new file mode 100644 index 000000000..41f1ba2ec --- /dev/null +++ b/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp @@ -0,0 +1,53 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3850 + BOOLEnum AICState ::determineAIPlayerHelp(int playerID, int requestedByPlayerID) + + { + + AITypeInt AVar1; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 != OpenSHC::AI::AIT_NULL) { + + if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue == 0) { + + if (DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + < *(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x1fc)) { + + MACRO_CALL(OpenSHC::Global_Func::PlayWillNotHelp2BikFromPlayerToPlayer)( + playerID, requestedByPlayerID); + + return FALSE; + } + + MACRO_CALL(OpenSHC::Global_Func::PlayWillHelpBikFromPlayerToPlayer)(playerID, requestedByPlayerID); + + return TRUE; + } + + MACRO_CALL(OpenSHC::Global_Func::PlayWillNotHelp1BikFromPlayerToPlayer)(playerID, requestedByPlayerID); + } + + return FALSE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp b/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp new file mode 100644 index 000000000..531b03abe --- /dev/null +++ b/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp @@ -0,0 +1,72 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/Unit.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitTypeShort.hpp" + +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Unit; + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::UnitTypeShort; + using OpenSHC::Map::Units::States::UnitState; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFB20 + void AICState ::disbandAIPlayerSiegeUnits(int playerID) + + { + + Unit* _unit; + + int _unitIDCounter; + + UnitTypeShort _unitType; + + _unitIDCounter = 1; + + _unit = &DAT_UnitsState::instance.units[1]; + + do { + + if ((((_unit->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) && (_unit->owner == playerID)) + && (((_unitType = _unit->unitType, + _unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || (((_unitType == OpenSHC::Map::Units::UT_S_TREBUCHET + || (_unitType == OpenSHC::Map::Units::UT_S_TOWER)) + || (_unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM)))) + || ((_unitType == OpenSHC::Map::Units::UT_S_SHIELD + || (_unitType == OpenSHC::Map::Units::UT_S_FBALLISTA)))))) + && ((_unit->unknownSiegeTentRelated02 == 3 && (_unit->aiUnitBehaviourType != 0x15)))) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( + (int)_unit->tribeID, OpenSHC::Map::Units::UIT_EXIT_SIEGE_EQUIPMENT, _unitIDCounter, _unit->uid, 0); + + /* + shouldn't logicalState be set to something too? */ + + (_unit->state).generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } + + _unit = _unit + 0x248; + + _unitIDCounter = _unitIDCounter + 1; + + } while ((int)_unit < 0x165141a); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp new file mode 100644 index 000000000..68b449749 --- /dev/null +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -0,0 +1,117 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000This function finds the first active AI + attack tribe for a player (validating it's still alive via UID matching), then traces a path from + that tribe's position toward the player's own defenses, storing the resulting tile coordinates in + the player's game state. It's likely used by the AI to rally or redirect attacking forces — + perhaps pulling them back toward defensive structures when needed, or seeding a waypoint for a + retreat/regroup maneuver. */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE930 + void AICState ::findAttackTribePositionAndPathToDefenses(int playerID) + + { + + int iVar1; + + int _tile; + + int iVar2; + + short* psVar3; + + int* local_c; + + uint local_8; + + uint local_4; + + short _y; + + local_8 = 0; + + local_4 = 0; + + local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + iVar2 = 0; + + if (0 < *local_c) { + + psVar3 + = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + (*(int (*)[2])(local_c + -1))[0]; + + do { + + iVar1 = (int)*psVar3; + + if ((iVar1 != 0) + && (DAT_TribesState::instance.tribes[iVar1].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[iVar2 + (*(int (*)[2])(local_c + -1))[0]])) { + + iVar2 = (int)DAT_TribesState::instance.tribes[iVar1].selectionTargetUnitID; + + local_8 = (uint)DAT_UnitsState::instance.units[iVar2].x; + + local_4 = (uint)DAT_UnitsState::instance.units[iVar2].y; + + if (iVar2 != 0) + goto LAB_004ce9f1; + + break; + } + + iVar2 = iVar2 + 1; + + psVar3 = psVar3 + 1; + + } while (iVar2 < *local_c); + } + + local_c = local_c + 2; + + if (0xb42a2b < (int)local_c) { + + LAB_004ce9f1: + DAT_GameState::instance.playerDataArray[playerID].someTile = 0; + + if ((local_8 != 0) + && (_tile = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: + tracePathToFriendlyDefensesAndReturnTileUnk, + DAT_PathFindingState::ptr)(playerID, local_8, local_4), + 0 < _tile)) { + + _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + + DAT_GameState::instance.playerDataArray[playerID].someTile = _tile; + + iVar2 = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + + DAT_GameState::instance.playerDataArray[playerID].someY = (int)_y; + + DAT_GameState::instance.playerDataArray[playerID].someX = _tile - iVar2; + } + + return; + } + + } while (true); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp new file mode 100644 index 000000000..581d2e863 --- /dev/null +++ b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp @@ -0,0 +1,106 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitTypeShort.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::UnitTypeShort; + + /* + 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 0x004CC420 + void AICState ::generateSiegeCreationInformation(int playerID, int buildingID, int unitID) + + { + + UnitTypeShort UVar1; + + int iVar2; + + int _siegeIndex; + + int _engineIndexUnk; + + int _nextIndex; + + int _goal; + + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) + && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != OpenSHC::Game::GM_SOLITARY)) { + + UVar1 = DAT_UnitsState::instance.units[unitID].unitType; + + if (UVar1 == OpenSHC::Map::Units::UT_S_TREBUCHET) { + + _siegeIndex = 2; + + } + + else { + + if (UVar1 != OpenSHC::Map::Units::UT_S_FBALLISTA) { + + return; + } + + _siegeIndex = 3; + } + + iVar2 = DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeIndex].slot; + + _goal = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[iVar2]; + + if (0 < _goal) { + + _engineIndexUnk = 0; + + while ((_nextIndex = _engineIndexUnk + 1, + *(int*)(playerID * 0x39f4 + iVar2 * 40 + 0x115eb14 + _engineIndexUnk * 4) < 1 + || (buildingID + != *(int*)(playerID * 0x39f4 + 0x115f494 + (_engineIndexUnk + _siegeIndex * 5) * 0x14)))) { + + _engineIndexUnk = _nextIndex; + + if (_goal <= _nextIndex) { + + return; + } + } + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeIndex][_engineIndexUnk] + .unitID = unitID; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeIndex][_engineIndexUnk] + .uid = DAT_UnitsState::instance.units[unitID].uid; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeIndex][_engineIndexUnk] + .buildingID = 0; + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp new file mode 100644 index 000000000..3b82b7d3d --- /dev/null +++ b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp @@ -0,0 +1,100 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CCAF0 + int AICState ::getSmallestPatrolTribe(int playerID, int tribeCount) + + { + + int _selectedTribeID; + + int _tribeID; + + int _tribeNumber; + + short* _pTribeID; + + int _selectedTribeNumber; + + short _lowestTribeUnitCount; + + short _tribeSize; + + _selectedTribeID = 0; + + _tribeNumber = 0; + + _selectedTribeNumber = 0; + + _lowestTribeUnitCount = 1000; + + if (0 < tribeCount) { + + _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; + + do { + + _tribeID = (int)*_pTribeID; + + if ((_tribeID == 0) + || (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeNumber + 0xaa])) { + + _selectedTribeID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + + _selectedTribeNumber = _tribeNumber; + + goto LAB_004ccb9d; + } + + _tribeSize = DAT_TribesState::instance.tribes[_tribeID].size; + + if (_tribeSize < _lowestTribeUnitCount) { + + _selectedTribeID = _tribeID; + + _selectedTribeNumber = _tribeNumber; + + _lowestTribeUnitCount = _tribeSize; + } + + _tribeNumber = _tribeNumber + 1; + + _pTribeID = _pTribeID + 1; + + } while (_tribeNumber < tribeCount); + + if (_selectedTribeID != 0) { + + LAB_004ccb9d: + /* + pTribeID = selectedTribeID */ + + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_selectedTribeNumber + 0xaa] + = (short)_selectedTribeID; + + /* + pTribeUID = selectedTribeUID */ + + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_selectedTribeNumber + 0xaa] + = DAT_TribesState::instance.tribes[_selectedTribeID].uid; + + return _selectedTribeID; + } + } + + return 0; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp new file mode 100644 index 000000000..5cb3f087a --- /dev/null +++ b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp @@ -0,0 +1,116 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/Map/Buildings/BuildingTypeInt.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Game::Player::PlayerData; + using OpenSHC::Map::Buildings::BuildingTypeInt; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDBC0 + int AICState ::getTargetableBuildingForPlayerID(int playerID, int param_2) + + { + + int* piVar1; + + PlayerData* pPVar2; + + int iVar3; + + int _candidateBuilding; + + BuildingTypeInt* _pTargets; + + int _index; + + int _aiType; + + int _outerPatrolGroupsCount; + + int _tracker; + + iVar3 = playerID; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if ((_aiType != 0) + && (_outerPatrolGroupsCount = *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x174), + 0 < _outerPatrolGroupsCount)) { + + _tracker = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + + if (0 < _tracker) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].someCounter2; + + *piVar1 = *piVar1 + 1; + + if (_tracker <= DAT_GameState::instance.playerDataArray[playerID].someCounter2) { + + DAT_GameState::instance.playerDataArray[playerID].someCounter2 = 0; + } + + pPVar2 = DAT_GameState::instance.playerDataArray + playerID; + + playerID = 0; + + _index = ((_tracker / _outerPatrolGroupsCount) * param_2 + pPVar2->someCounter2) % _tracker; + + if (0 < _tracker) { + + do { + + _candidateBuilding + = (int)DAT_GameState::instance.playerDataArray[iVar3].top100TargetableBuildings[_index]; + + _index = _index + 1; + + if (_tracker <= _index) { + + _index = 0; + } + + if (_candidateBuilding != 0) { + + _pTargets = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1; + + do { + + if ((int)(short)DAT_BuildingsState::instance.buildings[_candidateBuilding].buildingType + == *_pTargets) { + + return _candidateBuilding; + } + + _pTargets = _pTargets + 1; + + /* + Iterates only over resource buildings, so if resource building, return + */ + + } while ((int)_pTargets < 0xb427c8); + } + + playerID = playerID + 1; + + } while (playerID < _tracker); + } + } + + return 0; + } + + return 0; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp b/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp new file mode 100644 index 000000000..fcf4860b8 --- /dev/null +++ b/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp @@ -0,0 +1,118 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/AIUnitBehaviourType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIUnitBehaviourType; + using OpenSHC::Map::Units::UnitType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC250 + UnitType AICState ::getUnitTypeForUnitBehaviourType(int playerID, AIUnitBehaviourType unitBehaviourType) + + { + + AITypeInt AVar1; + + int iVar2; + + UnitType UVar3; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + + return ((UnitType)0); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_ENGINEERING) { + + return OpenSHC::Map::Units::UT_E_ENGINEER; + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_DIGGING) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttDiggingUnit); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_ASSASSINATION) { + + return OpenSHC::Map::Units::UT_A_ASSASSIN; + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_ATTUNIT2) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnit2); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_LADDERING) { + + return OpenSHC::Map::Units::UT_E_LADDER; + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_TUNNELING) { + + return OpenSHC::Map::Units::UT_TUNNELER; + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_PATROLLING) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitPatrol); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_BACKUPING) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitBackup); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_ENGAGING) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitEngage); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_SIEGEDEFENSE) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitSiegeDef); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_ATTUNITMAIN) { + + if (*(int*)((int)this->aics + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex * 4 + + AVar1 * 0x2a4 + -0x1c) + == 0) { + + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = 0; + } + + if (3 < DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex) { + + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = 0; + } + + iVar2 = DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex; + + /* + AttUnitMain[] */ + + UVar3 = *(UnitType*)((int)this->aics + AVar1 * 0x2a4 + iVar2 * 4 + -0x1c); + + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = iVar2 + 1; + + return UVar3; + } + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitMain1); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp new file mode 100644 index 000000000..b9bce3061 --- /dev/null +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp @@ -0,0 +1,106 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CEB50 + void AICState ::giveMoveCommandToAttackTribes(int playerID) + + { + + int _aiTribeID; + + int _counter; + + int _groupCounter; + + int* _ptrGroupCount; + + int _groupCount; + + int _playerID; + + int _tribeType; + + _playerID = playerID; + + if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { + + _counter = 0; + + _ptrGroupCount + = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + _tribeType = (*(int (*)[2])(_ptrGroupCount + -1))[0]; + + _groupCount = *_ptrGroupCount; + + if ((((_tribeType != 18) && (_tribeType != 190)) && (_tribeType != 15)) + && (_groupCounter = 0, 0 < _groupCount)) { + + /* + fixme: param reusage */ + + playerID = (_playerID * 0x1cfa + _tribeType) * 2 + 0x115ef04; + + do { + + _aiTribeID = (int)*(short*)playerID; + + if ((_aiTribeID != 0) + && (DAT_TribesState::instance.tribes[_aiTribeID].uid + == DAT_GameState::instance.playerDataArray[_playerID] + .aiTribeUIDs[_groupCounter + _tribeType])) { + + /* + bug: why give a random unit stance? */ + + DAT_TribesState::instance.tribes[_aiTribeID].unitStance + = (short)(char)((byte)SEC_RNG::instance.currentNumber2 & 1); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(_aiTribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[_playerID * 5][_counter] + .xOffset)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[_playerID * 5][_counter] + .yOffset)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + _counter = _counter + 1; + } + + playerID = playerID + 2; + + _groupCounter = _groupCounter + 1; + + } while (_groupCounter < _groupCount); + } + + _ptrGroupCount = _ptrGroupCount + 2; + + } while ((int)_ptrGroupCount < 0xb42a2c); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp new file mode 100644 index 000000000..6c36b0a2e --- /dev/null +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp @@ -0,0 +1,105 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD8F0 + void AICState ::giveMoveCommandToSortieUnits(int playerID) + + { + + int iVar1; + + int _tribeID; + + int _aiType; + + int _unitID; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == 0) { + return; + } + + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa7]; + + if (_tribeID == 0) { + return; + } + + if (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa7]) { + return; + } + + if ((int)DAT_TribesState::instance.tribes[_tribeID].size + < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 + -1) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::syncBehaviourType7UnitTribes, this)(playerID); + } + + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { + goto LAB_sendToKeep; + } + + /* + SortieUnitMeleeMin */ + + if ((int)DAT_TribesState::instance.tribes[_tribeID].size + < *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x154)) + goto LAB_004cda3c; + + _unitID = DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitID; + + if (((_unitID != 0) + && (DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitUID + == DAT_UnitsState::instance.units[_unitID].uid)) + && (iVar1 = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, + (dword)(( + int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID] + .tile])), + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance.units[_unitID].tile])), + 0), + iVar1 != 0)) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, + DAT_TribesState::ptr)(_tribeID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(_tribeID, (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + return; + } + + LAB_sendToKeep: + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); + + LAB_004cda3c: + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp new file mode 100644 index 000000000..0228ab5f7 --- /dev/null +++ b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp @@ -0,0 +1,70 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF920 + undefined4 AICState ::giveSomeRaidCommand(int tribeIndex, int tribeType) + + { + + int _chosenBuildingID; + + int _targetBuildingID; + + int _attacked; + + _targetBuildingID = (int)DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID; + + if ((((tribeType != 0xba) && (tribeType != 0x12)) && (tribeType != 0xe)) && (tribeType != 0xd)) { + + if (((_targetBuildingID != 0) + && (DAT_BuildingsState::instance.buildings[_targetBuildingID].uid + == DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID)) + && (DAT_BuildingsState::instance.buildings[_targetBuildingID].fireDuration == 0)) { + + return (undefined4)(1); + } + + _attacked = DAT_GameState::instance.playerDataArray[DAT_TribesState::instance.tribes[tribeIndex].owner] + .attackedPlayerID; + + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = 0; + + _chosenBuildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)(_attacked); + + if (_chosenBuildingID != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::queueDisbandAndAttackCommand4Params, + DAT_UnitsState::ptr)(tribeIndex, 9, (undefined4)((int)(_chosenBuildingID)), + (undefined4)((int)(DAT_BuildingsState::instance.buildings[_chosenBuildingID].uid))); + + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID + = DAT_BuildingsState::instance.buildings[_chosenBuildingID].uid; + + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = (short)_chosenBuildingID; + + DAT_TribesState::instance.tribes[tribeIndex].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + + return (undefined4)(1); + } + } + + return (undefined4)(0); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp index 32fca0836..d550e65f5 100644 --- a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp +++ b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp @@ -8,43 +8,46 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CFFD0 BOOLEnum AICState::hasNoTroopsOrAllAreDiggers(int playerID) { - int _totalBackup; - int _totalBackup2; - int _total1; int _totalTroops; int _halfOfDiggingTroops; - int _totalBackupLate; - int _totalBackupLate2; - _total1 = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + int _totalMisc = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops; _halfOfDiggingTroops = 0; if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState == 6) { - if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 17) { - _totalBackup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + _totalMisc += DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops; + int _attackTicker = DAT_GameState::instance.playerDataArray[playerID].attackTicker; + int _backup; + if (_attackTicker > 0x10) { + int _bp = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + _backup = (_bp + (_bp >> 0x1f & 7)) >> 3; } else { - _totalBackupLate = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - _totalBackup = (int)(_totalBackupLate + (_totalBackupLate >> 0x1f & 7U)) >> 3; + _backup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; } - _totalTroops = _total1 + DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops - + _totalBackup + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + _totalMisc += _backup; + _totalTroops = _totalMisc + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops - + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops; } else { - _halfOfDiggingTroops = DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops / 2; - if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 13) { - _totalBackup2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + int _digging = DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops; + _halfOfDiggingTroops = _digging / 2; + int _attackTicker = DAT_GameState::instance.playerDataArray[playerID].attackTicker; + int _backup; + if (_attackTicker > 0xc) { + int _bp2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + _backup = (_bp2 + (_bp2 >> 0x1f & 7)) >> 3; } else { - _totalBackupLate2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - _totalBackup2 = (int)(_totalBackupLate2 + (_totalBackupLate2 >> 0x1f & 7U)) >> 3; + _backup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; } - _totalTroops = _total1 + _totalBackup2 - + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + _totalMisc += _backup; + _totalTroops = _totalMisc + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops - + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops; } - if ((1 < _totalTroops) && ((4 < _totalTroops || (_halfOfDiggingTroops <= _totalTroops * 2)))) { + if ((1 < _totalTroops) && ((4 < _totalTroops) || (_halfOfDiggingTroops <= _totalTroops + _totalTroops))) { return FALSE; } return TRUE; diff --git a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp new file mode 100644 index 000000000..414d34b99 --- /dev/null +++ b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp @@ -0,0 +1,116 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD7B0 + void AICState ::instructTribe166ToMove(int playerID) + + { + + BOOLEnum _keepEnclosed; + + int _tribeID; + + int _counter; + + AITypeInt _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) { + + return; + } + + _counter = DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01; + + if (0 < _counter) { + + DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 = _counter + -1; + } + + if (50 < DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01) { + + DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 = 50; + } + + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; + + _keepEnclosed = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + + if (_tribeID == 0) { + + return; + } + + if (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa6]) { + + return; + } + + if ((int)DAT_TribesState::instance.tribes[_tribeID].size + < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 + -5) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitsToTribe166, this)(playerID); + } + + if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) + || (_keepEnclosed != FALSE)) { + + /* + SortieUnitRangedMin */ + + if ((int)DAT_TribesState::instance.tribes[_tribeID].size + < *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x14c)) + goto LAB_004cd86b; + + if ((0 < DAT_GameState::instance.playerDataArray[playerID].someXPosition) + && (0 < DAT_GameState::instance.playerDataArray[playerID].someYPosition)) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, + DAT_TribesState::ptr)(_tribeID); + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, + (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someXPosition)), + (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someYPosition)), 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + return; + } + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); + + LAB_004cd86b: + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp index 8168e916d..17c068b42 100644 --- a/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp +++ b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp @@ -8,15 +8,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D3960 void AICState::makeOutpostTribesAttack() { - uint _tribeID; - int _countDown; - short* _tribeIDs; - int* _tribeUIDs; - _tribeUIDs = this->tribeUIDArray; - _tribeIDs = this->tribeIDArray; - _countDown = 1000; + int* _tribeUIDs = this->tribeUIDArray; + short* _tribeIDs = this->tribeIDArray; + int _countDown = 1000; do { - _tribeID = (uint)*_tribeIDs; + unsigned int _tribeID = (uint)*_tribeIDs; if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid == *_tribeUIDs)) { MACRO_CALL_MEMBER(AICState_Func::decideOnTribeAttackLocation, this)(_tribeID); } diff --git a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp new file mode 100644 index 000000000..4c1c47ab2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp @@ -0,0 +1,100 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CEA50 + void AICState ::makeUnitsGoDefensiveAndBackToSomeLocation(int param_1) + + { + + int iVar1; + + int iVar2; + + int _commandResult; + + short* psVar3; + + int tribeID; + + int iVar4; + + int* local_c; + + uint _x; + + if ((DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) + && (DAT_GameState::instance.playerDataArray[param_1].someTile != 0)) { + + local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + iVar1 = *local_c; + + iVar2 = (*(int (*)[2])(local_c + -1))[0]; + + iVar4 = 0; + + if (0 < iVar1) { + + psVar3 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + iVar2; + + do { + + tribeID = (int)*psVar3; + + if ((tribeID != 0) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar4 + iVar2])) { + + _x = DAT_GameState::instance.playerDataArray[param_1].someX; + + DAT_TribesState::instance.tribes[tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + + _commandResult = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, _x, (uint)((int)(DAT_GameState::instance.playerDataArray[param_1].someY)), 0, + 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + if (_commandResult == 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::removeAllTribeUnits, + DAT_TribesState::ptr)(tribeID); + } + } + + iVar4 = iVar4 + 1; + + psVar3 = psVar3 + 1; + + } while (iVar4 < iVar1); + } + + local_c = local_c + 2; + + } while ((int)local_c < 0xb42a2c); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp new file mode 100644 index 000000000..46999d708 --- /dev/null +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -0,0 +1,104 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE830 + void AICState ::moveAttackTribesToLocations(short* playerID) + + { + + int iVar1; + + int iVar2; + + short* psVar3; + + int tribeID; + + int iVar4; + + int iVar5; + + int* local_c; + + psVar3 = playerID; + + if (DAT_GameState::instance.playerDataArray[(int)playerID].aiType != OpenSHC::AI::AIT_NULL) { + + iVar4 = 0; + + local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + iVar1 = *local_c; + + iVar2 = (*(int (*)[2])(local_c + -1))[0]; + + iVar5 = 0; + + if (0 < iVar1) { + + playerID = DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeIDs + iVar2; + + do { + + tribeID = (int)*playerID; + + if ((tribeID != 0) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeUIDs[iVar5 + iVar2])) { + + DAT_TribesState::instance.tribes[tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + + /* + fixme: array too small? + */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(tribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[(int)psVar3 * 5][iVar4] + .xOffset)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[(int)psVar3 * 5][iVar4] + .yOffset)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + iVar4 = iVar4 + 1; + } + + playerID = playerID + 1; + + iVar5 = iVar5 + 1; + + } while (iVar5 < iVar1); + } + + local_c = local_c + 2; + + } while ((int)local_c < 0xb42a2c); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp b/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp new file mode 100644 index 000000000..18634bdf2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp @@ -0,0 +1,151 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2F80 + void AICState ::moveAttackingUnitsToNextRallyPoint(int playerID) + + { + + short sVar1; + + short* _ptrAttackingUnitsTribeID; + + BOOLEnum _allArrived; + + int _rallyPointIndex; + + uint _x; + + uint _y; + + int _tribeID; + + bool bVar2; + + bool bVar3; + + bool bVar4; + + int _counter; + + short _totalRallyPointSteps; + + short _targetUnitID; + + if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { + + _ptrAttackingUnitsTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xbe; + + _counter = 0; + + do { + + _tribeID = (int)*_ptrAttackingUnitsTribeID; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_counter + 0xbe])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + _allArrived + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::allUnitsReachedTheirDestination, + DAT_TribesState::ptr)(_tribeID); + + if (_allArrived != FALSE) { + + DAT_TribesState::instance.tribes[_tribeID].unknownAttackRelatedUpdateCounter = 0; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addRallyPointForTribe, this)(_tribeID); + + _totalRallyPointSteps = DAT_TribesState::instance.tribes[_tribeID].rallyPointCount; + + _rallyPointIndex = DAT_TribesState::instance.tribes[_tribeID].currentRallyPointIndex + 1; + + if (_totalRallyPointSteps <= _rallyPointIndex) { + + _rallyPointIndex = 0; + } + + _x = (uint)DAT_TribesState::instance.tribes[_tribeID].rallyPointArray[_rallyPointIndex][0]; + + _y = (uint)DAT_TribesState::instance.tribes[_tribeID].rallyPointArray[_rallyPointIndex][1]; + + _targetUnitID = DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; + + DAT_TribesState::instance.tribes[_tribeID].currentRallyPointIndex = (short)_rallyPointIndex; + + if (0 < _totalRallyPointSteps) { + + if (_totalRallyPointSteps < 2) { + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)( + (int)DAT_UnitsState::instance.units[_targetUnitID].x, + (int)((int)(DAT_UnitsState::instance.units[_targetUnitID].y)), (int)((int)(_x)), + (int)((int)(_y))); + + bVar4 = (DAT_DirectionAlgorithmState::instance.distanceHigh < 5); + + bVar3 = DAT_DirectionAlgorithmState::instance.distanceHigh + -5 < 0; + + bVar2 = DAT_DirectionAlgorithmState::instance.distanceHigh == 5; + + } + + else { + + sVar1 = DAT_UnitsState::instance.units[_targetUnitID].closestEnemyMicroDistance; + + bVar4 = (sVar1 < 96); + + bVar3 = (short)(sVar1 + 96) < 0; + + bVar2 = sVar1 == 96; + } + + if (!bVar2 && bVar4 == bVar3) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)( + _tribeID, _x, _y, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + } + } + } + } + + _counter = _counter + 1; + + _ptrAttackingUnitsTribeID = _ptrAttackingUnitsTribeID + 1; + + } while (_counter < 2); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp new file mode 100644 index 000000000..8d942cd2a --- /dev/null +++ b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp @@ -0,0 +1,96 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CED90 + BOOLEnum AICState ::percentageNonMovingTribesGTEAICSpecified(int playerID) + + { + + int _tribe; + + int _index; + + short* _ptrTribeNumber; + + int _tribesCount; + + int _movingFewerThan20Percent; + + int* _ptrSize; + + AITypeInt _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) { + + return FALSE; + } + + _tribesCount = 0; + + _movingFewerThan20Percent = 0; + + _ptrSize = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + _index = 0; + + if (0 < *_ptrSize) { + + _ptrTribeNumber + = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + (*(int (*)[2])(_ptrSize + -1))[0]; + + do { + + _tribe = (int)*_ptrTribeNumber; + + if (((_tribe != 0) + && (DAT_TribesState::instance.tribes[_tribe].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_index + (*(int (*)[2])(_ptrSize + -1))[0]])) + && (_tribesCount = _tribesCount + 1, + DAT_TribesState::instance.tribes[_tribe].percentageMovingUnk < 20)) { + + _movingFewerThan20Percent = _movingFewerThan20Percent + 1; + } + + _index = _index + 1; + + _ptrTribeNumber = _ptrTribeNumber + 1; + + } while (_index < *_ptrSize); + } + + _ptrSize = _ptrSize + 2; + + } while ((int)_ptrSize < 0xb42a2c); + + if (0 < _tribesCount) { + + return (uint)(*(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x204) + <= (_movingFewerThan20Percent * 100) / _tribesCount); + } + + return FALSE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp new file mode 100644 index 000000000..c9b015a83 --- /dev/null +++ b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp @@ -0,0 +1,333 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CBA50 + void AICState ::planToBuyWhenLowOnResourceAndSnoozeBuildings(int playerID) + + { + + int _buildingBurning; + + int _offset; + + int _currentWood; + + int _noWood; + + int _currentPopulation; + + int* _pResourceCounter; + + int _hasArmoyUnk; + + int* _pNoBeerCounter; + + int* _pNoHopsTracker; + + int* _pNoFlourTracker; + + int* _pNoIronTracker; + + bool _enoughFood; + + bool _enoughGold; + + bool _enoughPeopleUnk; + + int _nerves; + + int _noBeerCounterUnk; + + int _noFlourCounterUnk; + + int _noHopsCounterUnk; + + int _noIronCounterUnk; + + bool _noNerves; + + int* _pNoWoodTracker; + + int _resourceCounter; + + _offset = playerID * 0x39f4; + + if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { + + _enoughPeopleUnk = true; + + _enoughFood = true; + + _enoughGold = true; + + _buildingBurning = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::playerHasBurningBuilding, + DAT_BuildingsState::ptr)(playerID); + + _currentWood = DAT_GameState::instance.playerDataArray[playerID].currentResources[2]; + + if (_currentWood < 1) { + + _pNoWoodTracker = &DAT_GameState::instance.playerDataArray[playerID].noWoodTracker; + + *_pNoWoodTracker = *_pNoWoodTracker + 1; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].noWoodTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[6] < 1) { + + _pNoIronTracker = &DAT_GameState::instance.playerDataArray[playerID].noIronTracker; + + *_pNoIronTracker = *_pNoIronTracker + 1; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].noIronTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0x10] < 1) { + + _pNoFlourTracker = &DAT_GameState::instance.playerDataArray[playerID].noFlourTracker; + + *_pNoFlourTracker = *_pNoFlourTracker + 1; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].noFlourTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[3] < 1) { + + _pNoHopsTracker = &DAT_GameState::instance.playerDataArray[playerID].noHopsTracker; + + *_pNoHopsTracker = *_pNoHopsTracker + 1; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].noHopsTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xe] < 1) { + + _pNoBeerCounter = &DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk; + + *_pNoBeerCounter = *_pNoBeerCounter + 1; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk = 0; + } + + _pResourceCounter = &DAT_GameState::instance.playerDataArray[playerID].someResourceCounter; + + *_pResourceCounter = *_pResourceCounter + 1; + + if (DAT_GameState::instance.playerDataArray[playerID].countFletchersPoleturners < 1) { + + DAT_GameState::instance.playerDataArray[playerID].noWoodTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].countArmorersAndBlacksmiths < 1) { + + DAT_GameState::instance.playerDataArray[playerID].noIronTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].countBakers < 1) { + + DAT_GameState::instance.playerDataArray[playerID].noFlourTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].countBrewers < 1) { + + DAT_GameState::instance.playerDataArray[playerID].noHopsTracker = 0; + } + + _currentPopulation = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; + + if ((_currentPopulation < 10) + && ((DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers != 0 + || (2 < DAT_GameState::instance.playerDataArray[playerID].countWoodcutters)))) { + + _enoughPeopleUnk = false; + } + + if ((((20 < _currentWood) && (_currentPopulation < 10)) + && (DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers != 0)) + && (DAT_GameState::instance.playerDataArray[playerID].totalFood < 8)) { + + _enoughFood = false; + } + + if (((_buildingBurning == 0) + && (DAT_GameState::instance.playerDataArray[playerID].countFarms + <= DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers)) + && (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < 500)) { + + _enoughGold = false; + } + + _hasArmoyUnk = DAT_GameState::instance.playerDataArray[playerID].armory.id; + + _noWood = DAT_GameState::instance.playerDataArray[playerID].noWoodTracker; + + _noIronCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noIronTracker; + + _resourceCounter = DAT_GameState::instance.playerDataArray[playerID].someResourceCounter; + + _noFlourCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noFlourTracker; + + _noHopsCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noHopsTracker; + + _noBeerCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk; + + _nerves = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + _noNerves = _nerves < 1; + + if (!_noNerves) { + + _enoughPeopleUnk = false; + + _enoughFood = false; + } + + if (_enoughGold) { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[27] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x46] = false; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1b] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x46] = true; + } + + if (_enoughPeopleUnk) { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[20] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[4] = false; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x14] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[4] = true; + } + + *(bool*)(_offset + 0x115df8f) = !_enoughFood; + + *(bool*)(_offset + 0x115df91) = !_noNerves; + + *(bool*)(_offset + 0x115df92) = !_noNerves; + + *(bool*)(_offset + 0x115df98) = _nerves < 1 && (36 < _noWood || _hasArmoyUnk == 0); + + *(bool*)(_offset + 0x115df9a) = _nerves < 1 && (36 < _noWood || _hasArmoyUnk == 0); + + *(bool*)(_offset + 0x115df99) = _noNerves && (0x24 < _noIronCounterUnk || _hasArmoyUnk == 0); + + *(bool*)(_offset + 0x115df9b) = _noNerves && (0x24 < _noIronCounterUnk || _hasArmoyUnk == 0); + + *(bool*)(_offset + 0x115df9c) = _noNerves && (0x24 < _resourceCounter || _hasArmoyUnk == 0); + + *(bool*)(_offset + 0x115df9d) = !_noNerves || 0x24 < _noFlourCounterUnk; + + *(bool*)(_offset + 0x115df9e) = !_noNerves || 0x48 < _noHopsCounterUnk; + + *(bool*)(_offset + 0x115dfa2) = !_noNerves || 0x48 < _noBeerCounterUnk; + + if (_noNerves) { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1e] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1f] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x20] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x21] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[7] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[34] = false; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1e] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1f] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x20] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x21] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[7] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x22] = true; + } + + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0) { + + if ((36 < DAT_GameState::instance.playerDataArray[playerID].noWoodTracker) + && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] == 0)) { + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] = 5; + } + + if ((36 < DAT_GameState::instance.playerDataArray[playerID].noIronTracker) + && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[6] == 0)) { + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[6] = 2; + } + + if ((36 < DAT_GameState::instance.playerDataArray[playerID].noFlourTracker) + && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[0x10] == 0)) { + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[0x10] = 2; + } + + if ((72 < DAT_GameState::instance.playerDataArray[playerID].noHopsTracker) + && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[3] == 0)) { + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[3] = 2; + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp index a0679b77a..b520df926 100644 --- a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp @@ -17,10 +17,11 @@ namespace AI { int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( killerPlayerID); if (iVar1 != 0) { - if (killedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + int _curPlayer = DAT_GameSynchronyState::instance.currentPlayerSlotID; + if (killedPlayerID == _curPlayer) { iVar1 = 0xc; } else { - if (killerPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (killerPlayerID == _curPlayer) { MACRO_CALL_MEMBER( Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); @@ -28,8 +29,7 @@ namespace AI { do { if ((DAT_GameState::instance.playerDataArray[i].aiType != AITA_NULL) && (DAT_GameState::instance.mapAndTime.playerTeams[i] - == DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + == DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer])) { int iVar2 = MACRO_CALL_MEMBER( Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i); if (iVar2 != 0) { @@ -42,25 +42,21 @@ namespace AI { } while (i < 9); return; } - iVar1 = DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]; - if (iVar1 == DAT_GameState::instance.mapAndTime.playerTeams[killedPlayerID]) { + int _curTeam = DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer]; + if (_curTeam == DAT_GameState::instance.mapAndTime.playerTeams[killedPlayerID]) { MACRO_CALL_MEMBER( Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 0x10); return; } - if (DAT_GameState::instance.mapAndTime.playerTeams[killerPlayerID] == iVar1) { - MACRO_CALL_MEMBER( - Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + if (DAT_GameState::instance.mapAndTime.playerTeams[killerPlayerID] == _curTeam) { MACRO_CALL_MEMBER( Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 0x12); return; } - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); iVar1 = 0xd; } MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( diff --git a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp index e95658878..cc48af4ee 100644 --- a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp @@ -17,19 +17,20 @@ namespace AI { int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { - iVar1 = 0; - if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] - == DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { - iVar1 = 0x17; + int _aiTypeMinusOne = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + int _myTeam = DAT_GameState::instance.mapAndTime.playerTeams[playerID]; + int _curPlayer = DAT_GameSynchronyState::instance.currentPlayerSlotID; + int _bik = 0; + if (_myTeam == DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer]) { + _bik = 0x17; } - if (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID - == DAT_GameSynchronyState::instance.currentPlayerSlotID) { - if (iVar1 == 0) { - iVar1 = ((byte)SEC_RNG::instance.currentNumber2 & 3) + 1; - } + int _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + if (_bik == 0) { + _bik = ((byte)SEC_RNG::instance.currentNumber2 & 3) + 1; + } + if (_attackedPlayerID == _curPlayer) { MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, iVar1); + playerID, _aiTypeMinusOne, _bik); } } } diff --git a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp new file mode 100644 index 000000000..7eaedffbb --- /dev/null +++ b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp @@ -0,0 +1,111 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CEEA0 + BOOLEnum AICState ::processAttForceRallyPercentage(int playerID) + + { + + AITypeInt AVar1; + + int iVar2; + + int iVar3; + + int _tribeID; + + short* psVar4; + + int iVar5; + + int _tribeTotal; + + int _notReallyMoving; + + int* local_c; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + + return FALSE; + } + + _tribeTotal = 0; + + _notReallyMoving = 0; + + local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + iVar2 = (*(int (*)[2])(local_c + -1))[0]; + + iVar3 = *local_c; + + if ((((iVar2 != 0x12) && (iVar2 != 0xbe)) && (iVar2 != 0xf)) && (iVar5 = 0, 0 < iVar3)) { + + psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar2; + + do { + + _tribeID = (int)*psVar4; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar5 + iVar2])) { + + _tribeTotal = _tribeTotal + 1; + + if (DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0x14) { + + _notReallyMoving = _notReallyMoving + 1; + } + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; + } + + iVar5 = iVar5 + 1; + + psVar4 = psVar4 + 1; + + } while (iVar5 < iVar3); + } + + local_c = local_c + 2; + + } while ((int)local_c < 0xb42a2c); + + if (0 < _tribeTotal) { + + /* + AttForceRallyPercentage */ + + return (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x200) + <= (_notReallyMoving * 100) / _tribeTotal); + } + + return FALSE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp new file mode 100644 index 000000000..c9ffdb38b --- /dev/null +++ b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp @@ -0,0 +1,233 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/AIUnitBehaviourType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIUnitBehaviourType; + + /* + doc: + Determines which AI unit behaviour groups need recruiting because AIC Max units hasn't been + reached for that category, then randomly selects one of those groups to recruit + + @returns AiUnitBehaviourType The selected unit behaviour type + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC070 + AIUnitBehaviourType AICState ::randomlySelectAttackUnitTypeToRecruit(int playerID) + + { + + int* piVar1; + + dword _engineersCount; + + int _index2; + + int _rng; + + int _index; + + int _aiTypeMin1; + + dword _maxDiggingUnits; + + dword _maxAssassins; + + dword _maxUnit2; + + dword _maxLaddermen; + + dword _maxTunnelers; + + dword _maxUnitPatrol; + + AITypeInt _aiType; + + int _attackedPlayerID; + + dword _maxEngineers; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) { + + return OpenSHC::AI::AIUBT_ATTUNITMAIN; + } + + _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + + _index = 0; + + /* + clear out flags */ + + piVar1 = DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[0] + 1; + + do { + + *piVar1 = 0; + + piVar1 = piVar1 + 2; + + } while ((int)piVar1 < 0xb425ec); + + _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxEngineers; + + _engineersCount = DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; + + if ((int)_maxEngineers < (int)_engineersCount) { + + _engineersCount = _maxEngineers; + } + + if ((_maxEngineers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops + < (int)_engineersCount)) { + + _index = 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[0][1] = 1; + } + + _maxDiggingUnits = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttDiggingUnitMax; + + if (((_maxDiggingUnits != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops < (int)_maxDiggingUnits)) + && (5 < DAT_GameState::instance.playerDataArray[_attackedPlayerID].field992_0x396c)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[1][1] = 1; + } + + _maxAssassins = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxAssassins; + + if ((_maxAssassins != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops < (int)_maxAssassins)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[2][1] = 1; + } + + _maxUnit2 = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnit2Max; + + if ((_maxUnit2 != 0) && (DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops < (int)_maxUnit2)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[3][1] = 1; + } + + _maxLaddermen = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxLaddermen; + + if ((_maxLaddermen != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalLaddermenTroops < (int)_maxLaddermen)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[4][1] = 1; + } + + _maxTunnelers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxTunnelers; + + if ((_maxTunnelers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalTunnelerTroops < (int)_maxTunnelers)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[5][1] = 1; + } + + _maxUnitPatrol = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitPatrolMax; + + if ((_maxUnitPatrol != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops < (int)_maxUnitPatrol)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[6][1] = 1; + } + + _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitBackupMax; + + if ((_maxEngineers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops < (int)_maxEngineers)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[7][1] = 1; + } + + _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitEngageMax; + + if ((_maxEngineers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops < (int)_maxEngineers)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[8][1] = 1; + } + + _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitSiegeDefMax; + + if ((_maxEngineers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops < (int)_maxEngineers)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[9][1] = 1; + } + + _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxDefault; + + if ((_maxEngineers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops < (int)_maxEngineers)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[10][1] = 1; + } + + if (_index != 0) { + + _rng = (int)SEC_RNG::instance.currentNumber2 % _index; + + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + + _index2 = 0; + + do { + + if (DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[_index2][1] != 0) { + + if (_rng == 0) { + + return (AIUnitBehaviourType)(DAT_SkirmishDefinedData::instance + .DAT_AIBehaviourTypeUnitRequired[_index2][0]); + } + + _rng = _rng + -1; + } + + _index2 = _index2 + 1; + + } while (_index2 < 0xb); + } + + return OpenSHC::AI::AIUBT_ATTUNITMAIN; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp new file mode 100644 index 000000000..a25c39500 --- /dev/null +++ b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp @@ -0,0 +1,93 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE040 + void AICState ::recomputeAIPathCostToAttackedKeep(int playerID, int useBorderDistance) + + { + + BOOLEnum BVar1; + + uint _borderDistance; + + bool _cannotNavigateToKeep; + + int _attackedPlayerID; + + int _bd; + + ushort _keepArea; + + _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + + _keepArea = DAT_TileMapState::instance + .PathConnectionLayer[DAT_GameState::instance.playerDataArray[playerID].campground.tileEntry]; + + _bd = DAT_GameState::instance.playerDataArray[_attackedPlayerID].unknownPathBorderDistanceRelated; + + if (_bd < 120) { + + _borderDistance = ((_bd < 90) - 1 & 20) + 50; + + } + + else { + + _borderDistance = 98; + } + + if (useBorderDistance == 0) { + + _borderDistance = 0; + } + + *(int*)((int)DAT_TroopValueState::instance.attackInfo.hackValuesArray + playerID * 0x177bc + -0x10) + = _attackedPlayerID; + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); + + BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + _cannotNavigateToKeep = BVar1 == FALSE; + + if (_cannotNavigateToKeep) { + + _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + + } + + else { + + _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + } + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, + DAT_PathFindingState::ptr)(_attackedPlayerID, (int)((int)((uint)!_cannotNavigateToKeep))); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkLayerAndAIPathCostLayer, + DAT_PathFindingState::ptr)(110, _borderDistance, (dword)((int)((int)(short)_keepArea)), playerID); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp new file mode 100644 index 000000000..6213b44c7 --- /dev/null +++ b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp @@ -0,0 +1,42 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE1A0 + void AICState ::recomputeAIZonerLayer() + + { + + DAT_TroopValueState::instance.attackInfo.playerInfo[0].currentPlayerID_OR_attackedPlayerID_OR_one = 1; + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, DAT_PathFindingState::ptr)(1, 2); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkLayerAndAIPathCostLayer, + DAT_PathFindingState::ptr)(252, 0, 1, 1); + + DAT_GameState::instance.playerDataArray[1].unknownPathBorderDistanceRelated + = DAT_PathFindingState::instance.distance; + + DAT_TroopValueState::instance.attackInfo.playerInfo[0].currentPlayerID_OR_attackedPlayerID_OR_one = 1; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp new file mode 100644 index 000000000..8ab398ad0 --- /dev/null +++ b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp @@ -0,0 +1,71 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/AttackInfoSubElement.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::AttackInfoSubElement; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE110 + void AICState ::recomputeAttackAIZone() + + { + + int* _pBorderDistance; + + int _playerID; + + AttackInfoSubElement* _pi; + + int _fullID; + + _playerID = 1; + + _pi = DAT_TroopValueState::instance.attackInfo.playerInfo; + + _pBorderDistance = &DAT_GameState::instance.playerDataArray[1].unknownPathBorderDistanceRelated; + + do { + + _fullID = DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_playerID]; + + _pi->currentPlayerID_OR_attackedPlayerID_OR_one = _playerID; + + if ((_fullID != -1) || (DAT_GameSynchronyState::instance.currentAIArray[_playerID] != 0)) { + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, + DAT_PathFindingState::ptr)(_playerID, 2); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkLayerAndAIPathCostLayer, + DAT_PathFindingState::ptr)(252, 0, 1, _playerID); + + *_pBorderDistance = DAT_PathFindingState::instance.distance; + + _pi->currentPlayerID_OR_attackedPlayerID_OR_one = 1; + } + + _playerID = _playerID + 1; + + _pBorderDistance = _pBorderDistance + 0xe7d; + + _pi = _pi + 1; + + } while (_playerID < 9); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp index a733ce5f7..78ed1689a 100644 --- a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp +++ b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp @@ -10,7 +10,7 @@ namespace AI { void AICState::recreateEngineersTribe(int playerID) { if (0 < DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops) { - int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; + int _tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { diff --git a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp new file mode 100644 index 000000000..21cd5785b --- /dev/null +++ b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp @@ -0,0 +1,254 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIVState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/Tribes/AITribeType.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Unit.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::Tribes::AITribeType; + using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::Unit; + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD2A0 + void AICState ::recruitHarrassingSiegeEngines(int playerID) + + { + + uint _unitID; + + int iVar1; + + Unit* pUVar4; + + int _unit; + + int _tribeID; + + int _harrassingSiegeEnginesMax; + + int _recruitTimeoutValue; + + int _engineersGuild; + + int _aiType; + + int _tribeUID; + + int _buildingID; + + int _aicEnginesArrayIndex; + + CommandBuildingType _siegeEngineToBuild; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + _engineersGuild = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + + if ((_aiType != 0) && (499 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf])) { + + _harrassingSiegeEnginesMax = *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x1ec); + + if (0 < _harrassingSiegeEnginesMax) { + + _recruitTimeoutValue = DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout; + + if (_recruitTimeoutValue != 0) { + + DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout + = _recruitTimeoutValue + -1; + + return; + } + + if ((DAT_GameState::instance.playerDataArray[playerID].harassingSiegeEnginesCountUnk + < _harrassingSiegeEnginesMax) + && (DAT_GameState::instance.playerDataArray[playerID].unknownHarrassingSiegeRelated < 0x14)) { + + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa5]; + + if ((_tribeID == 0) + || ((DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa5] + || (DAT_TribesState::instance.tribes[_tribeID].size < 2)))) { + + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) { + + return; + } + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < 30) { + + return; + } + + if (_engineersGuild < 1) { + + return; + } + + if (DAT_BuildingsState::instance.buildings[_engineersGuild].buildingType + != OpenSHC::Map::Buildings::BT_ENGINEERSGUILD) { + + return; + } + + _unitID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + OpenSHC::Map::Units::UT_E_ENGINEER, (undefined4)((int)(_engineersGuild)), playerID, 0); + + if (_unitID == 0) { + + return; + } + + if ((_tribeID == 0) + || (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa5])) { + + _tribeID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, + DAT_TribesState::ptr)(playerID); + } + + _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; + + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa5] = (short)_tribeID; + + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa5] = _tribeUID; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + _unitID, _tribeID); + + DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType = 0x16; + + } + + else { + + if (7 < DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex) { + + DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = 0; + } + + iVar1 = (_aiType + -1) * 0xa9; + + if (*(int*)((int)this + + (DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex + + iVar1) + * 4 + + 0x1cc) + == 0) { + + DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = 0; + } + + _aicEnginesArrayIndex + = DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex; + + _siegeEngineToBuild + = *(CommandBuildingType*)((int)this + (iVar1 + _aicEnginesArrayIndex) * 4 + 0x1cc); + + DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex + = _aicEnginesArrayIndex + 1; + + iVar1 = MACRO_CALL_MEMBER( + OpenSHC::AI::AIVState_Func::findSpotNearEngineersGuild, DAT_AIVState::ptr)(playerID); + + if (iVar1 == 0) { + + return; + } + + iVar1 = DAT_AIVState::instance.DAT_BuildingAppropriateGridYPosition * 5; + + _aicEnginesArrayIndex = DAT_AIVState::instance.DAT_BuildingApproriateGridXPosition * 5; + + DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + + /* + palce siege engine tent? */ + + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)( + playerID, _aicEnginesArrayIndex, iVar1, _siegeEngineToBuild, 3, 0xf); + + _buildingID = DAT_TileMapState::instance.DAT_PlacedBuildingID; + + if (DAT_TileMapState::instance.buildingPlacementFail != FALSE) { + + return; + } + + DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.DAT_PlacedBuildingID] + .attackWave = 0; + + DAT_BuildingsState::instance.buildings[_buildingID].unknownSiegeTentRelated01 = 2; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, + DAT_TribesState::ptr)(_tribeID, + OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _buildingID, + DAT_BuildingsState::instance.buildings[_buildingID].uid, 0); + } + + _unit = 1; + + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + + pUVar4 = &DAT_UnitsState::instance.units[1]; + + do { + + if ((((pUVar4->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) && (pUVar4->dying == 0)) + && ((pUVar4->unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || (pUVar4->unitType == OpenSHC::Map::Units::UT_S_FBALLISTA)))) + && (pUVar4->aiUnitBehaviourType == 0x15)) { + + pUVar4->siegeTargetPlayerID + = (short)DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + } + + _unit = _unit + 1; + + pUVar4 = pUVar4 + 0x248; + + } while (_unit < (int)DAT_UnitsState::instance.maxUnitCount); + } + + DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout = 8; + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp b/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp new file mode 100644 index 000000000..34db026dd --- /dev/null +++ b/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp @@ -0,0 +1,66 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE430 + void AICState ::removeOrganismsAndSetMoveDestinationPairs(int playerID) + + { + + AITypeInt _aiType; + + if ((short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX] + != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)( + (int)(short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]); + } + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + /* + bug: special hardcoded exception for AI type 8 */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, + (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY)), -1, -1, 10000, FALSE); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::setMoveDestinationPairs, + DAT_PathFindingState::ptr)(playerID + -1, + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, + (int)((int)(*(int*)(DAT_TroopValueState::instance.attackInfo.scaleValuesArray + playerID * 0x177bc + -0x1c) + + (-(uint)(_aiType != OpenSHC::AI::AIT_SULTAN) & 0xc) + 8))); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp new file mode 100644 index 000000000..6367b31c8 --- /dev/null +++ b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp @@ -0,0 +1,248 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/Text/TextManager.func.hpp" +#include "OpenSHC/AI/AIC/AICSpecification.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AIStrengthType.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/Text/TextAlignment.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_BlendingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_RenderingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TextManagerObject.hpp" +#include "OpenSHC/Globals/MSVC_SecurityCookie.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AICState; + using OpenSHC::AI::AIStrengthType; + using OpenSHC::AI::AIType; + using OpenSHC::AI::AIC::AICSpecification; + using OpenSHC::Game::Player::PlayerData; + using OpenSHC::Text::TextAlignment; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + 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 0x004D1320 + void AICState ::renderDebugDataAiInfo(int x, int y, int width, int height) + + { + + uint foregroundColor; + + int iVar1; + + PlayerData* _playerData; + + int yParam; + + char* pcVar2; + + uint foregroundColor_00; + + char (*pPlayerNames)[250]; + + int _aiTypeMin1; + + AICSpecification* local_3f4; + + AICState* local_3f0; + + char local_3ec[1000]; + + uint local_4; + + int _playerID; + + local_4 = MSVC_SecurityCookie::instance ^ (uint)&_playerID; + + local_3f0 = this; + + _playerID = 1; + + _playerData = &DAT_GameState::instance.playerDataArray[1]; + + pPlayerNames = DAT_GameSynchronyState::instance.DAT_PlayerNames + 1; + + do { + + yParam = y + 0x18; + + if (((_playerData->playerDeathRelated == 0) && (_playerData->lordKilledByPlayerID == 0)) + && ((_playerData->aiType != OpenSHC::AI::AIT_NULL + || (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_playerID] != -1)))) { + + /* + aiType - 1 */ + + _aiTypeMin1 = _playerData->aiType + ~OpenSHC::AI::AIT_NULL; + + foregroundColor + = DAT_RenderingDefinedData::instance + .DAT_ColorArray[DAT_BlendingDefinedData::instance.SEC_PlayerSlotUnitColor[_playerID]]; + + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + _playerID, x + 6, yParam, OpenSHC::Text::TTA_LEFT, 0xc2f0eb, 0x12, FALSE, 0); + + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + "-", x + 0x10, yParam, OpenSHC::Text::TTA_LEFT, 0xc2f0eb, 0x12, FALSE, 0); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + *pPlayerNames, x + 0x1a, y + 0x19, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + if (_playerData->aiStrengthFeeling == OpenSHC::AI::AIST_WEAK) { + + pcVar2 = "Weak"; + + } + + else if (_playerData->aiStrengthFeeling == OpenSHC::AI::AIST_DEFAULT) { + + pcVar2 = "Normal"; + + } + + else { + + pcVar2 = "Strong"; + } + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + pcVar2, x + 0xca, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + "P:", x + 0x106, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumber2, DAT_TextManagerObject::ptr)( + _playerData->aivCurrentPause, x + 0x108, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, + TRUE, 0); + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)( + local_3ec, "Atk:%d W:%d", _playerData->attackedPlayerID, _playerData->aiAttackCoordinationLevel); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x12e, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + if (_playerData->aiType == OpenSHC::AI::AIT_NULL) { + + iVar1 = DAT_AIVState::instance.SEC_AIVS[_playerData->aivID].castleID; + + pcVar2 = "AIV:n/a"; + + } + + else { + + iVar1 = DAT_AIVState::instance.SEC_AIVS[_playerData->aivID].castleID; + + pcVar2 = "AIV: %d"; + } + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, (char const*)((int)(pcVar2)), iVar1 + 1); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x17e, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + local_3f4 = local_3f0->aics + _aiTypeMin1; + + /* + total engineers? */ + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, "E:%d/%d", _playerData->totalTroopsType6, + _playerData->unknownCounter_01 + local_3f0->aics[_aiTypeMin1].SortieUnitRangedMin); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x1c4, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + /* + total attack troops - engineer troops */ + + iVar1 = _playerData->totalAttackTroops - _playerData->totalAttackingEngineerTroops; + + /* + ai player state == attacking */ + + if (_playerData->aiPlayerState == 0) { + + /* + AttForceBase + currentWaveRandomAttackingStrength */ + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, "Sg:%d/%d", iVar1, + _playerData->currentWaveRandomAttackingStrength + local_3f4->AttForceBase); + + foregroundColor_00 = foregroundColor; + + } + + else { + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, "%d/%d", iVar1, _playerData->attackTicker); + + foregroundColor_00 = 0xffffff; + } + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x200, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor_00, 0, 0x12, FALSE, 0); + + iVar1 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, local_3f0)( + _aiTypeMin1, _playerID); + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)( + local_3ec, "Hr:%d/%d", _playerData->totalRaidingTroopsUnk, iVar1); + + /* + display raid/harassing units */ + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x250, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + /* + TotalDefensiveTroops / DefWalls */ + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)( + local_3ec, "Df:%d/%d", _playerData->totalDefensiveTroopsUnk, local_3f4->DefWalls); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x291, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + } + + pPlayerNames = pPlayerNames + 1; + + _playerID = _playerID + 1; + + _playerData = _playerData + 0xe7d; + + y = yParam; + + } while (_playerID < 9); + + ; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/requestGoods.cpp b/src/OpenSHC/AI/AICState/requestGoods.cpp new file mode 100644 index 000000000..20c9e32df --- /dev/null +++ b/src/OpenSHC/AI/AICState/requestGoods.cpp @@ -0,0 +1,70 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Game::Resources::ResourceType; + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1F00 + void AICState ::requestGoods(int playerID, ResourceType resourceType, int amount) + + { + + if ((((((DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) + && (DAT_GameState::instance.playerDataArray[playerID].aiRequestDelay == 0)) + && (resourceType != OpenSHC::Game::Resources::RT_WHEAT)) + && ((resourceType != OpenSHC::Game::Resources::RT_HOPS + && (resourceType != OpenSHC::Game::Resources::RT_ALE)))) + && ((((resourceType != OpenSHC::Game::Resources::RT_BREAD + && ((resourceType != OpenSHC::Game::Resources::RT_CHEESE + && (resourceType != OpenSHC::Game::Resources::RT_MEAT)))) + && (resourceType != OpenSHC::Game::Resources::RT_APPLE)) + || (DAT_GameState::instance.playerDataArray[playerID].totalFood < 5)))) + && (((((resourceType != OpenSHC::Game::Resources::RT_BREAD + && (resourceType != OpenSHC::Game::Resources::RT_CHEESE)) + && (resourceType != OpenSHC::Game::Resources::RT_MEAT)) + && (resourceType != OpenSHC::Game::Resources::RT_APPLE)) + || (DAT_GameState::instance.playerDataArray[playerID].totalFood < 5)))) { + + int iVar1; + int _playerID = 1; + + short* psVar2 = DAT_GameState::instance.playerDataArray[1].requestedGoodsArray1Unk + playerID; + + do { + + if (((DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_playerID] != -1) + && (DAT_GameState::instance.mapAndTime.playerTeams[_playerID] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID])) + && ((iVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_playerID), + iVar1 != 0 && (*psVar2 == 0)))) { + + *psVar2 = (short)resourceType; + + psVar2[10] = (short)amount; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playGoodsRequestBikFromPlayerToPlayer, this)( + playerID, _playerID); + } + + _playerID = _playerID + 1; + + psVar2 = psVar2 + 0x1cfa; + + } while (_playerID < 9); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp new file mode 100644 index 000000000..b9af53ac5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp @@ -0,0 +1,254 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AIC/AITargetChoiceInt.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Game/Player/PlayerData.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" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIC::AITargetChoice; + using OpenSHC::AI::AIC::AITargetChoiceInt; + using OpenSHC::Game::Player::PlayerData; + + /* + 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 0x004D4680 + void AICState ::selectAttackTarget(int playerID) + + { + + int fromXPosition; + + int fromYPosition; + + int iVar1; + + int _alive1; + + int _isLordAlive; + + int _lord; + + int _selectedPlayer; + + PlayerData* _pPlayerData2; + + int _iPlayer2; + + int _iPlayer; + + PlayerData* _ptrPlayerData; + + int _lowestDistance; + + int _highestGold; + + int _lowestPoints; + + int _currentGoldValue; + + int _points; + + int _reqState; + + int _reqState2; + + AITypeInt _aiType; + + AITargetChoiceInt _targetChoiceType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + _selectedPlayer = 0; + + if (_aiType != OpenSHC::AI::AIT_NULL) { + + fromXPosition = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; + + fromYPosition = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; + + _lowestDistance = 10000; + + _highestGold = 0; + + _lowestPoints = 1000000; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeNervousness, this)(playerID); + + _reqState = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; + + if (((_reqState == 2) || (_reqState == 1)) + && (iVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), + iVar1 == 0)) { + + DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; + } + + _reqState2 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; + + if (_reqState2 == 2) { + + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = 0; + + return; + } + + if (_reqState2 == 1) { + + _alive1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk); + + if (_alive1 != 0) { + + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID + = DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk; + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; + } + + _pPlayerData2 = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); + + _iPlayer = 1; + + do { + + if ((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] + != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) + && (_isLordAlive = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_iPlayer), + _isLordAlive != 0)) { + + /* + fixme:improve: use pythagoras */ + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)((_pPlayerData2->campground).xEntry, + (_pPlayerData2->campground).yEntry, fromXPosition, fromYPosition); + + _targetChoiceType = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].TargetChoice; + + _currentGoldValue = _highestGold; + + _points = _lowestPoints; + + if (_targetChoiceType == OpenSHC::AI::AIC::AITC_PLAYER) { + + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_iPlayer] != -1) { + + LAB_004d47c5: + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance) { + + _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + + LAB_004d4845: + _lowestPoints = _points; + + _highestGold = _currentGoldValue; + + _selectedPlayer = _iPlayer; + } + } + + } + + else { + + if (_targetChoiceType == OpenSHC::AI::AIC::AITC_CLOSEST) + goto LAB_004d47c5; + + if (_targetChoiceType == OpenSHC::AI::AIC::AITC_GOLD) { + + _currentGoldValue = _pPlayerData2->currentResources[0xf]; + + if (_highestGold <= _pPlayerData2->currentResources[0xf]) + goto LAB_004d4845; + + } + + else if ((_targetChoiceType == OpenSHC::AI::AIC::AITC_BALANCED) + && (_points = _pPlayerData2->currentPopulation * 5 + _pPlayerData2->totalTroopValue + + _pPlayerData2->currentResources[0xf] / 100 + + DAT_DirectionAlgorithmState::instance.distanceHigh * 2, + _points <= _lowestPoints)) + goto LAB_004d4845; + } + } + + _iPlayer = _iPlayer + 1; + + _pPlayerData2 = _pPlayerData2 + 0x39f4; + + } while (_iPlayer < 9); + + if (_selectedPlayer == 0) { + + _iPlayer2 = 1; + + _ptrPlayerData = &DAT_GameState::instance.playerDataArray[1]; + + do { + + if (((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer2] + != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) + && (_lord = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_iPlayer2), + _lord != 0)) + && (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, + (_ptrPlayerData->campground).yEntry, fromXPosition, fromYPosition), + DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance)) { + + _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + + _selectedPlayer = _iPlayer2; + } + + _iPlayer2 = _iPlayer2 + 1; + + /* + next player */ + + _ptrPlayerData = _ptrPlayerData + 0xe7d; + + } while (_iPlayer2 < 9); + + if (_selectedPlayer == 0) { + + return; + } + } + + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk = _selectedPlayer; + + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = _selectedPlayer; + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp new file mode 100644 index 000000000..1b1c2239a --- /dev/null +++ b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp @@ -0,0 +1,75 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDAB0 + int AICState ::selectBuildingFromAListOfBuildingTypes(int playerID) + + { + + int _selectedBuildingID; + + int _loopCounter; + + int _loopLimit; + + short* psVar1; + + int _arraySize; + + int _buildingID; + + _arraySize = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + + _selectedBuildingID = 0; + + _loopLimit = 0x2e; + + if (0 < _arraySize) { + + psVar1 = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings; + + do { + + _buildingID = (int)*psVar1; + + if ((_buildingID != 0) && (_loopCounter = 0, 0 < _loopLimit)) { + + do { + + if ((int)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType + == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_loopCounter]) { + + /* + fancy break statement? */ + + _selectedBuildingID = _buildingID; + + _loopLimit = _loopCounter; + } + + _loopCounter = _loopCounter + 1; + + } while (_loopCounter < _loopLimit); + } + + psVar1 = psVar1 + 1; + + _arraySize = _arraySize + -1; + + } while (_arraySize != 0); + } + + return _selectedBuildingID; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp b/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp new file mode 100644 index 000000000..072e4b84d --- /dev/null +++ b/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp @@ -0,0 +1,37 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDCA0 + int AICState ::selectRandomBuildingIDFromListOfBuildingTypes(int playerID, undefined4 param_2) + + { + + int iVar1; + + int iVar2; + + iVar1 = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + + if (iVar1 < 1) { + + return 0; + } + + iVar2 = (int)SEC_RNG::instance.currentNumber2; + + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + + return (int)DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings[iVar2 % iVar1]; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp new file mode 100644 index 000000000..412497ce2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -0,0 +1,147 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/Trading/AIResourceTradeCategory.hpp" +#include "OpenSHC/AI/Trading/AIResourceTradeCategoryInt.hpp" +#include "OpenSHC/AI/Trading/ResourceAICResourceMappingEntry.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::Trading::AIResourceTradeCategory; + using OpenSHC::AI::Trading::AIResourceTradeCategoryInt; + using OpenSHC::AI::Trading::ResourceAICResourceMappingEntry; + using OpenSHC::Game::Resources::ResourceType; + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1D60 + void AICState ::sellExcessGoods(int param_1) + + { + + AITypeInt AVar1; + + ResourceType resourceType; + + AIResourceTradeCategoryInt AVar2; + + int iVar3; + + uint uVar4; + + int iVar5; + + int iVar6; + + ResourceType* pRVar7; + + AIResourceTradeCategoryInt* local_18; + + AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + return; + } + + iVar3 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + + local_18 = &DAT_SkirmishDefinedData::instance.DAT_AIResourceTradeAICMapping[0].aic; + + do { + + resourceType + = (OpenSHC::Game::Resources::ResourceType)((ResourceAICResourceMappingEntry*)(local_18 + -1))->game; + + AVar2 = *local_18; + + iVar6 = *(int*)((int)this + iVar3 + 0xc0); + + if (AVar2 == OpenSHC::AI::Trading::AIRTC_WOOD) { + iVar5 = *(int*)((int)this + iVar3 + 0xac); + } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { + iVar5 = *(int*)((int)this + iVar3 + 0x80); + } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_STONE) { + iVar5 = *(int*)((int)this + iVar3 + 0xb0); + } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_WEAPONS) { + iVar5 = *(int*)((int)this + iVar3 + 0xb8); + } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_ALE) { + iVar5 = *(int*)((int)this + iVar3 + 0xbc); + } else { + iVar5 = *(int*)((int)this + iVar3 + 0xb4); + } + + uVar4 = iVar5 + iVar6; + + if ((DAT_GameState::instance.playerDataArray[param_1].aiNervousActionsTracker <= 0) + || (DAT_GameState::instance.playerDataArray[param_1].currentResources[0xf] >= 0x1f4)) { + + if (DAT_GameState::instance.playerDataArray[param_1].popularity < *(int*)((int)this + iVar3 + 0x18)) { + + if (AVar2 != OpenSHC::AI::Trading::AIRTC_FOOD) { + + if (AVar2 == OpenSHC::AI::Trading::AIRTC_WEAPONS) { + uVar4 = 0; + iVar6 = 0; + goto LAB_004d1e81; + } + + uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; + } + + iVar6 = 0; + + } else { + uVar4 = uVar4 + + DAT_GameState::instance.playerDataArray[param_1].resourcesToAcquireArray[resourceType]; + } + + } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { + + uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; + iVar6 = 0; + + } else { + + uVar4 = (AVar2 != OpenSHC::AI::Trading::AIRTC_WEAPONS) - 1 & 10000; + iVar6 = 0; + } + + LAB_004d1e81: + iVar5 = 0; + + pRVar7 = (ResourceType*)((int)this + iVar3 + 0xd4); + + do { + if (resourceType == *pRVar7) { + uVar4 = 0; + iVar6 = 0; + break; + } + iVar5 = iVar5 + 1; + pRVar7 = pRVar7 + 1; + } while (iVar5 < 0xf); + + if ((int)uVar4 < DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType]) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellGoods, this)(param_1, resourceType, + (DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType] - uVar4) + iVar6); + + return; + } + + local_18 = local_18 + 2; + + if (0xb4252b < (int)local_18) { + return; + } + + } while (true); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp new file mode 100644 index 000000000..83b899711 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp @@ -0,0 +1,109 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/AI/AIVUnitType.hpp" +#include "OpenSHC/AI/AIVUnitTypeInt.hpp" +#include "OpenSHC/AI/Tribes/AIVUnitTypeMaxLocationPair.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIVUnitType; + using OpenSHC::AI::AIVUnitTypeInt; + using OpenSHC::AI::Tribes::AIVUnitTypeMaxLocationPair; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4220 + void AICState ::sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed(int playerID) + + { + + BOOLEnum _enclosed; + + AIVUnitTypeInt* _ptr; + + int _tribe; + + int _index; + + int _limit; + + int* _nervous; + + _enclosed = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)( + playerID); + + _ptr = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_GroundUnits[0].aivUnitType; + + do { + + _limit = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*_ptr]; + + _index = 0; + + if (0 < _limit) { + + _nervous = &DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + do { + + _tribe = (int)DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index]; + + if ((_tribe != 0) + && (DAT_TribesState::instance.tribes[_tribe].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index])) { + + if ((*_nervous < 1) || (_enclosed != FALSE)) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( + _tribe, (AIVUnitType)((int)(*_ptr)), _index); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribe, playerID); + } + } + + /* + bug:fixme: _tribe could be 0 */ + + if ((*_nervous < 1) || (_enclosed != FALSE)) { + + DAT_TribesState::instance.tribes[_tribe].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + } + + else { + + DAT_TribesState::instance.tribes[_tribe].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + } + + _index = _index + 1; + + } while (_index < _limit); + } + + _ptr = _ptr + 2; + + } while ((int)_ptr < 0xb4277c); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp new file mode 100644 index 000000000..afc77615c --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp @@ -0,0 +1,104 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIVUnitType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIVUnitType; + using OpenSHC::Map::Units::UnitInstructionType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D44E0 + void AICState ::sendOilMenForOilPickupOrToAIVLocations(int playerID) + + { + + short* _ptrTribeIDArray; + + int _oilManLocationsCount; + + int _tribeID; + + int _index; + + int _oilSmelter; + + _oilSmelter = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id; + + _oilManLocationsCount = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1]; + + if (0 < _oilManLocationsCount) { + + if (_oilManLocationsCount == 10) { + + _oilManLocationsCount = 9; + } + + _index = 1; + + if (0 < _oilManLocationsCount) { + + /* + oil men offset in tribe id array */ + + _ptrTribeIDArray = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 71; + + do { + + _tribeID = (int)*_ptrTribeIDArray; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0x46])) { + + if (DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID] + .resourceToDeposit + == 0) { + + if (_oilSmelter != 0) { + + /* + send for oil duty */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, + DAT_UnitsState::ptr)(_tribeID, + OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, + _oilSmelter, DAT_BuildingsState::instance.buildings[_oilSmelter].uid, 0); + } + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, + DAT_TribesState::ptr)(_tribeID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( + _tribeID, OpenSHC::AI::AIVUT_ENGINEER, _index + -1); + } + } + + _index = _index + 1; + + _ptrTribeIDArray = _ptrTribeIDArray + 1; + + } while (_index <= _oilManLocationsCount); + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp new file mode 100644 index 000000000..429bb500b --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp @@ -0,0 +1,76 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIVUnitType.hpp" +#include "OpenSHC/AI/AIVUnitTypeInt.hpp" +#include "OpenSHC/AI/Tribes/AIVUnitTypeMaxLocationPair.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIVUnitType; + using OpenSHC::AI::AIVUnitTypeInt; + using OpenSHC::AI::Tribes::AIVUnitTypeMaxLocationPair; + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4130 + void AICState ::sendRangedUnitTribesToAIVSlotsOrKeepIfNervous(int playerID) + + { + + AIVUnitTypeInt* _ptr + = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_RangedUnits[0].aivUnitType; + + do { + + int _limit = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*_ptr]; + + int _index = 0; + + if (0 < _limit) { + + do { + + int _tribe = (int)DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index]; + + if ((_tribe != 0) + && (DAT_TribesState::instance.tribes[_tribe].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index])) { + + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { + + if ((DAT_TileMapState::instance.LogicLayer[DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[_tribe].selectionTargetUnitID] + .tile] + & 0x10000100U) + == 0) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribe, playerID); + } + + } else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( + _tribe, (AIVUnitType)((int)(*_ptr)), _index); + } + } + + _index = _index + 1; + + } while (_index < _limit); + } + + _ptr = _ptr + 2; + + } while ((int)_ptr < 0xb42744); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp new file mode 100644 index 000000000..3cd363930 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp @@ -0,0 +1,90 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIVUnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIVUnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + [doc] + @param slotIndex int slotIndex to browse to + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2E00 + void AICState ::sendTribeToAIVLocationSlot(int tribeID, AIVUnitType aivUnitType, int slotIndex) + + { + + int _slotIndex; + + BOOLEnum _canNavigate; + + int* _ptrSlot; + + int _tile; + + int _x; + + int _owner; + + short _y; + + /* + all experimental, heavy local reuse... */ + + _owner = DAT_TribesState::instance.tribes[tribeID].owner; + + _tile = 0; + + _slotIndex = 0; + + /* + aivUnitLocationSlots */ + + _ptrSlot = (int*)(_owner * 0x39f4 + 0x115eb14 + aivUnitType * 0x28); + + while ((*_ptrSlot == 0 || (slotIndex = slotIndex + -1, -1 < slotIndex))) { + + _slotIndex = _slotIndex + 1; + + _ptrSlot = _ptrSlot + 1; + + if (9 < _slotIndex) { + + LAB_004d2e6d: + _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + + _x = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + + _canNavigate = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, _tile); + + if (_canNavigate == FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, _owner); + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + tribeID, (uint)((int)(_tile - _x)), (uint)((int)((int)_y)), 0); + + return; + } + } + + _tile = DAT_GameState::instance.playerDataArray[_owner].aivUnitLocationSlots[aivUnitType][_slotIndex]; + + goto LAB_004d2e6d; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp new file mode 100644 index 000000000..6870e8369 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp @@ -0,0 +1,181 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D30E0 + undefined4 AICState ::sendUnitsToAttackBreachedCastle(int attackingPlayerIndex) + + { + + int tribeType; + + int _defendingLordIndex; + + int _successUnk; + + int iVar1; + + int _vector; + + int _tribeID; + + short* local_20; + + int local_18; + + int (*_ptrGroupCount)[2]; + + int _attackedPlayerID; + + int _groupCount; + + short _targetUnit; + + bool sentUnitsToAttackLord; + + _vector = 0; + + if (DAT_GameState::instance.playerDataArray[attackingPlayerIndex].aiType == OpenSHC::AI::AIT_NULL) { + + return (undefined4)(1); + } + + sentUnitsToAttackLord = false; + + _defendingLordIndex = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID); + + _ptrGroupCount + = (int (*)[2])(DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[0] + 1); + + do { + + tribeType = _ptrGroupCount[-1][1]; + + _groupCount = (*_ptrGroupCount)[0]; + + if ((((tribeType != 18) && (tribeType != 14)) && (tribeType != 13)) && (local_18 = 0, 0 < _groupCount)) { + + local_20 = DAT_GameState::instance.playerDataArray[attackingPlayerIndex].aiTribeIDs + tribeType; + + do { + + _tribeID = (int)*local_20; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[attackingPlayerIndex] + .aiTribeUIDs[local_18 + tribeType])) { + + _targetUnit = DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + + if ((sentUnitsToAttackLord) || ((_defendingLordIndex == 0 || (tribeType == 186)))) { + + iVar1 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveSomeRaidCommand, this)( + _tribeID, tribeType); + + if (iVar1 == 0) { + + if (tribeType == 0xba) { + + _vector = _vector + 4; + } + + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_8; + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + iVar1 = DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID; + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)( + (int)DAT_UnitsState::instance.units[_targetUnit].x, + (int)((int)(DAT_UnitsState::instance.units[_targetUnit].y)), + DAT_GameState::instance.mapAndTime.attackVectors[iVar1][_vector].x, + DAT_GameState::instance.mapAndTime.attackVectors[iVar1][_vector].y); + + if (4 < DAT_DirectionAlgorithmState::instance.distanceHigh) { + + _attackedPlayerID = DAT_GameState::instance.playerDataArray[attackingPlayerIndex] + .attackedPlayerID; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(_tribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .attackVectors[_attackedPlayerID][_vector] + .x)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .attackVectors[_attackedPlayerID][_vector] + .y)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + } + + _vector = _vector + 1; + } + + } + + else { + + /* + Send units to attack lord */ + + _successUnk = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + _tribeID, (uint)((int)((int)DAT_UnitsState::instance.units[_defendingLordIndex].x)), + (uint)((int)((int)DAT_UnitsState::instance.units[_defendingLordIndex].y)), 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + + if (_successUnk == 0) { + + return (undefined4)(0); + } + + sentUnitsToAttackLord = true; + } + } + + local_20 = local_20 + 1; + + local_18 = local_18 + 1; + + } while (local_18 < _groupCount); + } + + _ptrGroupCount = _ptrGroupCount + 1; + + } while ((int)_ptrGroupCount < 0xb42acc); + + return (undefined4)(1); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp index 8b0339efc..dd0c25b0d 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp @@ -9,7 +9,7 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CD0C0 - void AICState::sendUnitsToKeep(undefined4 tribeID, int playerID) + void AICState::sendUnitsToKeep(int tribeID, int playerID) { int iVar1 = DAT_GameState::instance.playerDataArray[playerID].keep.id; if (0 < iVar1) { diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp new file mode 100644 index 000000000..db61864a8 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -0,0 +1,165 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE5F0 + void AICState ::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, short* playerID2) + + { + + BOOLEnum BVar1; + + dword _gatehouseTile; + + int _tribeID; + + int _counter; + + int* local_10; + + uint _ghY; + + uint _ghX; + + int _maxTribeCount; + + int _p1_keepCampfireX; + + int _aiTribeBehaviourTypeOffset; + + uint _p1_keepCampfireY; + + short* _playerID2; + + _playerID2 = playerID2; + + _p1_keepCampfireY = DAT_GameState::instance.playerDataArray[playerID1].campground.yEntry; + + _p1_keepCampfireX = DAT_GameState::instance.playerDataArray[playerID1].campground.xEntry; + + BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID1, (int)((int)(playerID2))); + + if (BVar1 == FALSE) { + + _gatehouseTile = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findOwnedGatehouse, + DAT_PathFindingState::ptr)((int)playerID2, (uint)((int)(_p1_keepCampfireX)), _p1_keepCampfireY); + + if (_gatehouseTile == 0) { + + DAT_GameState::instance.playerDataArray[playerID1].requestStateUnk = 0; + + return; + } + + _ghY = (uint)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_gatehouseTile]; + + _ghX = _gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[_ghY].addXgetTile; + } + + local_10 = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + _maxTribeCount = *local_10; + + _aiTribeBehaviourTypeOffset = (*(int (*)[2])(local_10 + -1))[0]; + + _counter = 0; + + if (0 < _maxTribeCount) { + + /* + fixme: reused parameter */ + + playerID2 = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _aiTribeBehaviourTypeOffset; + + do { + + _tribeID = (int)*playerID2; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID1] + .aiTribeUIDs[_counter + _aiTribeBehaviourTypeOffset])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID1, (int)((int)(_playerID2))); + + if (BVar1 == FALSE) { + + /* + send to enemy gate house */ + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + _tribeID, _ghX, _ghY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + } + + else if (_aiTribeBehaviourTypeOffset == 0xbe) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, (int)((int)(_playerID2))); + + } + + else { + + BVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + + if (BVar1 == FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( + _tribeID, (int)((int)(_playerID2))); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, (int)((int)(_playerID2))); + } + } + } + + playerID2 = playerID2 + 1; + + _counter = _counter + 1; + + } while (_counter < _maxTribeCount); + } + + local_10 = local_10 + 2; + + } while ((int)local_10 < 0xb42a2c); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp new file mode 100644 index 000000000..b5d4cdd8e --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp @@ -0,0 +1,155 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/AIVUnitType.hpp" +#include "OpenSHC/AI/AIVUnitTypeInt.hpp" +#include "OpenSHC/AI/Tribes/AIVUnitTypeMaxLocationPair.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIVUnitType; + using OpenSHC::AI::AIVUnitTypeInt; + using OpenSHC::AI::Tribes::AIVUnitTypeMaxLocationPair; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4340 + void AICState ::sendWallPatrolUnitTribesToAIVLocations(int playerID) + + { + + BOOLEnum _enclosed; + + int _tribeID; + + AIVUnitTypeInt* _ptr; + + int _patrolGroupIndex; + + int _index; + + int _minCount; + + int _stepSize; + + int _defWallPatrolGroups; + + AITypeInt _aiType; + + int _count; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType != OpenSHC::AI::AIT_NULL) { + + _enclosed = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + + /* + defWallPatrolGroups */ + + _ptr = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_PatrolUnits[0].aivUnitType; + + do { + + _defWallPatrolGroups = *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x114); + + _count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*_ptr]; + + _index = 0; + + _minCount = _count; + + if (_defWallPatrolGroups < _count) { + + _minCount = _defWallPatrolGroups; + } + + if (0 < _minCount) { + + _stepSize = _count / _minCount; + + if (_stepSize < 1) { + + _stepSize = 1; + } + + if (0 < _minCount) { + + _patrolGroupIndex = 0; + + do { + + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + + _index]; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + + _index])) { + + if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) + || (_enclosed != FALSE)) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( + _tribeID, (AIVUnitType)((int)(*_ptr)), + (DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits + + _patrolGroupIndex) + % _count); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID); + } + + if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) + || (_enclosed != FALSE)) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + } + + else { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + } + } + + _patrolGroupIndex = _patrolGroupIndex + _stepSize; + + _index = _index + 1; + + } while (_index < _minCount); + } + } + + _ptr = _ptr + 2; + + } while ((int)_ptr < 0xb42794); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_06.cpp b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp new file mode 100644 index 000000000..2a28425db --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp @@ -0,0 +1,289 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C8110 + void AICState ::setAICParameters_06(int param_1) + + { + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].taxesMax = 0xc; + + this->aics[param_1].farm1 = 0x20; + + this->aics[param_1].farm3 = 0x20; + + this->aics[param_1].unknown011 = 0xc; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x32; + + this->aics[param_1].doubleRationsFoodThreshold = 0x32; + + this->aics[param_1].maxWood = 0x32; + + this->aics[param_1].maxStone = 0x32; + + this->aics[param_1].populationPerIronmine = 0xc; + + this->aics[param_1].flagType = 10; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 0; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 3; + + this->aics[param_1].farm2 = 0x1f; + + this->aics[param_1].populationPerFarm = 5; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].tradeAmountFood = 10; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 5; + + this->aics[param_1].maxBeer = 0xf; + + this->aics[param_1].maxResourceVariance = 5; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 10; + + this->aics[param_1].populationPerPitchrig = 7; + + this->aics[param_1].maxQuarries = 2; + + this->aics[param_1].maxIronmines = 1; + + this->aics[param_1].maxWoodcutters = 8; + + this->aics[param_1].maxPitchrigs = 10; + + this->aics[param_1].maxFarms = 10; + + this->aics[param_1].buildInterval = 3; + + this->aics[param_1].resourceRebuildDelay = 0x3c; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x12; + + this->aics[param_1].poleturnerSetting = 0x14; + + this->aics[param_1].defWallPatrolRallyTime = 5; + + this->aics[param_1].defWallPatrolGroups = 2; + + this->aics[param_1].defSiegeEngineGoldThreshold = 0x78; + + this->aics[param_1].defSiegeEngineBuildDelay = 8; + + this->aics[param_1].sellResource03 = 6; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource08 = 0x11; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].unknown072 = 100; + + this->aics[param_1].SortieUnitRangedMin = 7; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 0x14; + + this->aics[param_1].recruitProbAttackDefault = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 0; + + this->aics[param_1].RecruitInterval = 0; + + this->aics[param_1].RecruitIntervalStrong = 0; + + this->aics[param_1].SortieUnitMeleeMin = 5; + + this->aics[param_1].OuterPatrolGroupsCount = 2; + + this->aics[param_1].HarassingSiegeEnginesMax = 2; + + this->aics[param_1].recruitProbDefWeak = 0x50; + + this->aics[param_1].recruitProbDefDefault = 0x28; + + this->aics[param_1].recruitProbDefStrong = 0x28; + + this->aics[param_1].recruitProbRaidDefault = 0x28; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackStrong = 0x1e; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].SortieUnitMelee = 0x4b; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].DefDiggingUnit = 0x47; + + this->aics[param_1].DefWalls = 0x3c; + + this->aics[param_1].DefTotal = 0x3c; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 10; + + this->aics[param_1].DefUnit1 = 0x4c; + + this->aics[param_1].RaidUnitsBase = 0x1e; + + this->aics[param_1].RaidUnitsRandom = 0x1e; + + this->aics[param_1].RaidUnit1 = 0x47; + + this->aics[param_1].SortieUnitRanged = 0x46; + + this->aics[param_1].DefUnit2 = 0x46; + + this->aics[param_1].DefUnit3 = 0x46; + + this->aics[param_1].DefUnit4 = 0x46; + + this->aics[param_1].HarassingSiegeEngine1 = 0x166; + + this->aics[param_1].HarassingSiegeEngine2 = 0xbe; + + this->aics[param_1].RaidRetargetDelay = 3; + + this->aics[param_1].AttForceBase = 0xf; + + this->aics[param_1].AttForceRandom = 10; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x46; + + this->aics[param_1].AttForceRallyPercentage = 100; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 2; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 10; + + this->aics[param_1].AttCoordinationPreference = 0x32; + + this->aics[param_1].CowThrowInterval = 7; + + this->aics[param_1].SiegeEngine1 = 0x4d; + + this->aics[param_1].SiegeEngine2 = 0x4d; + + this->aics[param_1].SiegeEngine3 = 0x4d; + + this->aics[param_1].AttMaxEngineers = 6; + + this->aics[param_1].AttDiggingUnit = 0x47; + + this->aics[param_1].AttDiggingUnitMax = 0x14; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0x4b; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0x4a; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x4a; + + this->aics[param_1].AttUnitBackupMax = 0x28; + + this->aics[param_1].AttUnitBackupGroupsCount = 2; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0x46; + + this->aics[param_1].AttUnitSiegeDefMax = 10; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; + + this->aics[param_1].AttUnitMain1 = 0x4b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 5; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp new file mode 100644 index 000000000..84fc2c94a --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp @@ -0,0 +1,283 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C8530 + void AICState ::setAICParameters_07(int param_1) + + { + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].maxEquipment = 5; + + this->aics[param_1].maxResourceVariance = 5; + + this->aics[param_1].flagType = 10; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 0; + + this->aics[param_1].unknown005 = 0; + + this->aics[param_1].criticalPopularity = 5000; + + this->aics[param_1].lowestPopularity = 6000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 1; + + this->aics[param_1].taxesMax = 8; + + this->aics[param_1].farm1 = 0; + + this->aics[param_1].populationPerFarm = 100; + + this->aics[param_1].unknown011 = 0x14; + + this->aics[param_1].maxFood = 500; + + this->aics[param_1].minimumApples = 0x14; + + this->aics[param_1].tradeAmountFood = 10; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].aiRequestDelay = 0x1e; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0; + + this->aics[param_1].doubleRationsFoodThreshold = 0; + + this->aics[param_1].maxWood = 0x1e; + + this->aics[param_1].maxStone = 0x14; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxBeer = 0x14; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 2; + + this->aics[param_1].populationPerQuarry = 5; + + this->aics[param_1].populationPerIronmine = 0; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 2; + + this->aics[param_1].maxIronmines = 1; + + this->aics[param_1].maxWoodcutters = 0xf; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 6; + + this->aics[param_1].buildInterval = 5; + + this->aics[param_1].resourceRebuildDelay = 0x50; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource02 = 3; + + this->aics[param_1].sellResource03 = 6; + + this->aics[param_1].sellResource04 = 7; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource06 = 0xe; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource08 = 0x11; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 10; + + this->aics[param_1].defWallPatrolGroups = 2; + + this->aics[param_1].defSiegeEngineGoldThreshold = 200; + + this->aics[param_1].defSiegeEngineBuildDelay = 0x14; + + this->aics[param_1].unknown072 = 800; + + this->aics[param_1].unknown073 = 0x50; + + this->aics[param_1].recruitProbDefStrong = 0x1e; + + this->aics[param_1].recruitProbRaidWeak = 10; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackDefault = 0x1e; + + this->aics[param_1].DefDiggingUnitMax = 2; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 10; + + this->aics[param_1].RaidUnitsRandom = 10; + + this->aics[param_1].recruitProbDefWeak = 0x46; + + this->aics[param_1].recruitProbDefDefault = 0x32; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 0x14; + + this->aics[param_1].recruitProbAttackStrong = 0x28; + + this->aics[param_1].RecruitIntervalWeak = 8; + + this->aics[param_1].RecruitInterval = 8; + + this->aics[param_1].RecruitIntervalStrong = 4; + + this->aics[param_1].SortieUnitRangedMin = 0; + + this->aics[param_1].SortieUnitRanged = 0x48; + + this->aics[param_1].SortieUnitMeleeMin = 3; + + this->aics[param_1].SortieUnitMelee = 0x4b; + + this->aics[param_1].DefDiggingUnit = 0x47; + + this->aics[param_1].DefWalls = 0x28; + + this->aics[param_1].DefTotal = 0x32; + + this->aics[param_1].OuterPatrolGroupsMove = 0; + + this->aics[param_1].DefUnit1 = 0x48; + + this->aics[param_1].DefUnit2 = 0x48; + + this->aics[param_1].DefUnit3 = 0x4b; + + this->aics[param_1].RaidUnitsBase = 0x14; + + this->aics[param_1].RaidUnit1 = 0x48; + + this->aics[param_1].HarassingSiegeEnginesMax = 0; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].RaidRetargetDelay = 3; + + this->aics[param_1].AttForceBase = 10; + + this->aics[param_1].AttForceRandom = 0x14; + + this->aics[param_1].AttForceSupportAllyThreshold = 5; + + this->aics[param_1].AttForceRallyPercentage = 0x1e; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 0x28; + + this->aics[param_1].AttCoordinationPreference = 0x14; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0; + + this->aics[param_1].AttMaxEngineers = 0; + + this->aics[param_1].AttDiggingUnit = 0; + + this->aics[param_1].AttDiggingUnitMax = 0; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x46; + + this->aics[param_1].AttUnitBackupMax = 0x78; + + this->aics[param_1].AttUnitBackupGroupsCount = 1; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x4b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 1; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_08.cpp b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp new file mode 100644 index 000000000..fbc4839a2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp @@ -0,0 +1,289 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C8920 + void AICState ::setAICParameters_08(int param_1) + + { + + this->aics[param_1].farm2 = 0x20; + + this->aics[param_1].farm3 = 0x20; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].minimumApples = 5; + + this->aics[param_1].minimumCheese = 5; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].tradeAmountFood = 5; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown005 = 0; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 8000; + + this->aics[param_1].taxesMin = 3; + + this->aics[param_1].taxesMax = 10; + + this->aics[param_1].farm1 = 0x21; + + this->aics[param_1].populationPerFarm = 4; + + this->aics[param_1].unknown011 = 0xc; + + this->aics[param_1].maxFood = 200; + + this->aics[param_1].tradeAmountEquipment = 2; + + this->aics[param_1].aiRequestDelay = 0x16; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + + this->aics[param_1].doubleRationsFoodThreshold = 0x28; + + this->aics[param_1].maxWood = 0x32; + + this->aics[param_1].maxStone = 0x3c; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 10; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 10; + + this->aics[param_1].populationPerIronmine = 10; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 3; + + this->aics[param_1].maxIronmines = 4; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxFarms = 0xf; + + this->aics[param_1].buildInterval = 4; + + this->aics[param_1].resourceRebuildDelay = 0x14; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x14; + + this->aics[param_1].sellResource02 = 3; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource06 = 0xe; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].defWallPatrolRallyTime = 8; + + this->aics[param_1].defWallPatrolGroups = 4; + + this->aics[param_1].defSiegeEngineGoldThreshold = 200; + + this->aics[param_1].defSiegeEngineBuildDelay = 2; + + this->aics[param_1].unknown072 = 100; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x5a; + + this->aics[param_1].recruitProbDefDefault = 0x1e; + + this->aics[param_1].recruitProbDefStrong = 10; + + this->aics[param_1].recruitProbAttackWeak = 10; + + this->aics[param_1].RaidUnitsBase = 10; + + this->aics[param_1].recruitProbRaidWeak = 0; + + this->aics[param_1].recruitProbRaidDefault = 0; + + this->aics[param_1].recruitProbRaidStrong = 0; + + this->aics[param_1].SortieUnitRanged = 0x16; + + this->aics[param_1].DefDiggingUnitMax = 0; + + this->aics[param_1].DefWalls = 0x14; + + this->aics[param_1].OuterPatrolGroupsCount = 2; + + this->aics[param_1].DefUnit1 = 0x16; + + this->aics[param_1].DefUnit2 = 0x16; + + this->aics[param_1].RaidUnitsRandom = 4; + + this->aics[param_1].RaidUnit1 = 0x16; + + this->aics[param_1].HarassingSiegeEnginesMax = 2; + + this->aics[param_1].AttForceBase = 0x14; + + this->aics[param_1].recruitProbAttackDefault = 0x46; + + this->aics[param_1].recruitProbAttackStrong = 0x5a; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].RecruitInterval = 1; + + this->aics[param_1].RecruitIntervalStrong = 1; + + this->aics[param_1].SortieUnitRangedMin = 6; + + this->aics[param_1].SortieUnitMeleeMin = 6; + + this->aics[param_1].SortieUnitMelee = 0x19; + + this->aics[param_1].DefDiggingUnit = 0x19; + + this->aics[param_1].DefTotal = 0x28; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 5; + + this->aics[param_1].DefUnit3 = 0x19; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].RaidRetargetDelay = 5; + + this->aics[param_1].AttForceRandom = 5; + + this->aics[param_1].AttForceSupportAllyThreshold = 10; + + this->aics[param_1].AttForceRallyPercentage = 10; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0x14; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 2; + + this->aics[param_1].AttCoordinationPreference = 10; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x27; + + this->aics[param_1].SiegeEngine2 = 0x27; + + this->aics[param_1].SiegeEngine3 = 0x27; + + this->aics[param_1].SiegeEngine4 = 0x3b; + + this->aics[param_1].SiegeEngine5 = 0x28; + + this->aics[param_1].SiegeEngine6 = 0x28; + + this->aics[param_1].AttMaxEngineers = 0x10; + + this->aics[param_1].AttDiggingUnit = 0x19; + + this->aics[param_1].AttDiggingUnitMax = 6; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 3; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x16; + + this->aics[param_1].AttUnitBackupMax = 0x14; + + this->aics[param_1].AttUnitBackupGroupsCount = 2; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0x1b; + + this->aics[param_1].AttUnitSiegeDefMax = 4; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 2; + + this->aics[param_1].AttUnitMain1 = 0x1b; + + this->aics[param_1].AttUnitMain2 = 0x19; + + this->aics[param_1].AttUnitMain3 = 0x19; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 3; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_09.cpp b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp new file mode 100644 index 000000000..28bd5aac5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp @@ -0,0 +1,283 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C8D20 + void AICState ::setAICParameters_09(int param_1) + + { + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].minimumApples = 5; + + this->aics[param_1].minimumCheese = 5; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x3c; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 0x157c; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 3; + + this->aics[param_1].taxesMax = 10; + + this->aics[param_1].farm1 = 0x21; + + this->aics[param_1].farm2 = 0x20; + + this->aics[param_1].farm3 = 0x1f; + + this->aics[param_1].populationPerFarm = 4; + + this->aics[param_1].unknown011 = 0xc; + + this->aics[param_1].maxFood = 200; + + this->aics[param_1].tradeAmountFood = 10; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].aiRequestDelay = 0x16; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + + this->aics[param_1].doubleRationsFoodThreshold = 0x28; + + this->aics[param_1].maxResourceOther = 0xf; + + this->aics[param_1].maxEquipment = 0x14; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 0xc; + + this->aics[param_1].populationPerIronmine = 10; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 4; + + this->aics[param_1].maxIronmines = 5; + + this->aics[param_1].maxWoodcutters = 0xc; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 0xc; + + this->aics[param_1].buildInterval = 4; + + this->aics[param_1].resourceRebuildDelay = 0x1e; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = -999; + + this->aics[param_1].poleturnerSetting = 0x14; + + this->aics[param_1].sellResource04 = 7; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].defWallPatrolRallyTime = 8; + + this->aics[param_1].defWallPatrolGroups = 2; + + this->aics[param_1].defSiegeEngineGoldThreshold = 200; + + this->aics[param_1].defSiegeEngineBuildDelay = 2; + + this->aics[param_1].unknown072 = 100; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 100; + + this->aics[param_1].recruitProbDefDefault = 0x32; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 0; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x14; + + this->aics[param_1].RecruitInterval = 4; + + this->aics[param_1].RecruitIntervalStrong = 4; + + this->aics[param_1].SortieUnitRanged = 0x16; + + this->aics[param_1].SortieUnitMeleeMin = 4; + + this->aics[param_1].DefDiggingUnitMax = 10; + + this->aics[param_1].DefDiggingUnit = 0x16; + + this->aics[param_1].OuterPatrolRallyDelay = 10; + + this->aics[param_1].DefUnit1 = 0x16; + + this->aics[param_1].DefUnit2 = 0x16; + + this->aics[param_1].RaidUnitsBase = 4; + + this->aics[param_1].AttForceRandom = 4; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackWeak = 0; + + this->aics[param_1].recruitProbAttackDefault = 0x1e; + + this->aics[param_1].recruitProbAttackStrong = 0x32; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].SortieUnitRangedMin = 0xc; + + this->aics[param_1].SortieUnitMelee = 0x1b; + + this->aics[param_1].DefWalls = 0x32; + + this->aics[param_1].DefTotal = 0x50; + + this->aics[param_1].OuterPatrolGroupsCount = 2; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].DefUnit3 = 0x17; + + this->aics[param_1].RaidUnitsRandom = 0; + + this->aics[param_1].RaidUnit1 = 0x1c; + + this->aics[param_1].HarassingSiegeEnginesMax = 2; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].RaidRetargetDelay = 6; + + this->aics[param_1].AttForceBase = 0x1e; + + this->aics[param_1].AttForceRallyPercentage = 0x32; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0x14; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x32; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x28; + + this->aics[param_1].SiegeEngine2 = 0x28; + + this->aics[param_1].SiegeEngine3 = 0x28; + + this->aics[param_1].SiegeEngine4 = 0x28; + + this->aics[param_1].SiegeEngine5 = 0x28; + + this->aics[param_1].SiegeEngine6 = 0x28; + + this->aics[param_1].AttMaxEngineers = 0x12; + + this->aics[param_1].AttDiggingUnit = 0x16; + + this->aics[param_1].AttDiggingUnitMax = 0x14; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0x17; + + this->aics[param_1].AttUnitPatrolMax = 0x14; + + this->aics[param_1].AttUnitPatrolGroupsCount = 1; + + this->aics[param_1].AttUnitBackup = 0x16; + + this->aics[param_1].AttUnitBackupMax = 0x1e; + + this->aics[param_1].AttUnitBackupGroupsCount = 2; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0x17; + + this->aics[param_1].AttUnitSiegeDefMax = 10; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; + + this->aics[param_1].AttUnitMain1 = 0x1b; + + this->aics[param_1].AttUnitMain2 = 0x1b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 4; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp new file mode 100644 index 000000000..0d6b6afba --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp @@ -0,0 +1,283 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C9120 + void AICState ::setAICParameters_10(int param_1) + + { + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].farm1 = 0x20; + + this->aics[param_1].farm2 = 0x20; + + this->aics[param_1].tradeAmountEquipment = 2; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x3c; + + this->aics[param_1].resourceRebuildDelay = 0x3c; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 8000; + + this->aics[param_1].taxesMax = 10; + + this->aics[param_1].populationPerFarm = 5; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].minimumCheese = 10; + + this->aics[param_1].minimumBread = 10; + + this->aics[param_1].tradeAmountFood = 0x14; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + + this->aics[param_1].doubleRationsFoodThreshold = 0x32; + + this->aics[param_1].maxResourceOther = 0xf; + + this->aics[param_1].maxEquipment = 6; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 0; + + this->aics[param_1].populationPerIronmine = 7; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 1; + + this->aics[param_1].maxIronmines = 3; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 8; + + this->aics[param_1].buildInterval = 4; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource02 = 3; + + this->aics[param_1].sellResource04 = 7; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource06 = 0xe; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x46; + + this->aics[param_1].recruitProbDefDefault = 0x28; + + this->aics[param_1].RecruitIntervalWeak = 4; + + this->aics[param_1].RecruitInterval = 4; + + this->aics[param_1].RecruitIntervalStrong = 4; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].DefWalls = 4; + + this->aics[param_1].OuterPatrolGroupsCount = 4; + + this->aics[param_1].RaidUnitsBase = 4; + + this->aics[param_1].RaidUnitsRandom = 4; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 0x14; + + this->aics[param_1].recruitProbRaidStrong = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 10; + + this->aics[param_1].recruitProbAttackDefault = 0x14; + + this->aics[param_1].SortieUnitRanged = 0x16; + + this->aics[param_1].SortieUnitMeleeMin = 0x14; + + this->aics[param_1].DefTotal = 0x14; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].DefUnit2 = 0x16; + + this->aics[param_1].DefUnit3 = 0x16; + + this->aics[param_1].DefUnit4 = 0x16; + + this->aics[param_1].DefUnit5 = 0x16; + + this->aics[param_1].DefUnit6 = 0x16; + + this->aics[param_1].HarassingSiegeEnginesMax = 1; + + this->aics[param_1].recruitProbRaidDefault = 0x28; + + this->aics[param_1].recruitProbAttackStrong = 0x3c; + + this->aics[param_1].SortieUnitRangedMin = 2; + + this->aics[param_1].SortieUnitMelee = 0x18; + + this->aics[param_1].DefDiggingUnit = 0x18; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].DefUnit1 = 0x1c; + + this->aics[param_1].RaidUnit1 = 0x1c; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].AttForceBase = 10; + + this->aics[param_1].AttForceRandom = 0x14; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x28; + + this->aics[param_1].AttForceRallyPercentage = 0x28; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x46; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0; + + this->aics[param_1].AttMaxEngineers = 0; + + this->aics[param_1].AttDiggingUnit = 0x18; + + this->aics[param_1].AttDiggingUnitMax = 0x3c; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0x18; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0; + + this->aics[param_1].AttUnitBackupMax = 0; + + this->aics[param_1].AttUnitBackupGroupsCount = 0; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x18; + + this->aics[param_1].AttUnitMain2 = 0x18; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 2; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_11.cpp b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp new file mode 100644 index 000000000..9f6a82e8a --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp @@ -0,0 +1,281 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C94F0 + void AICState ::setAICParameters_11(int param_1) + + { + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].minimumApples = 0xffffffff; + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 2; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].flagType = 10; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 0x1194; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 8000; + + this->aics[param_1].taxesMax = 0xc; + + this->aics[param_1].farm1 = 0x1e; + + this->aics[param_1].populationPerFarm = 5; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].tradeAmountFood = 0x14; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].aiRequestDelay = 0x16; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x1e; + + this->aics[param_1].doubleRationsFoodThreshold = 0x32; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x28; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 4; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 100; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 6; + + this->aics[param_1].populationPerIronmine = 0xc; + + this->aics[param_1].populationPerPitchrig = 6; + + this->aics[param_1].maxQuarries = 3; + + this->aics[param_1].maxIronmines = 1; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxPitchrigs = 4; + + this->aics[param_1].maxFarms = 8; + + this->aics[param_1].buildInterval = 3; + + this->aics[param_1].resourceRebuildDelay = 0x32; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource02 = 3; + + this->aics[param_1].sellResource03 = 6; + + this->aics[param_1].sellResource06 = 0xe; + + this->aics[param_1].sellResource08 = 0x11; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x46; + + this->aics[param_1].recruitProbDefDefault = 0x1e; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].recruitProbRaidStrong = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 0x1e; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].RaidUnitsBase = 0x1e; + + this->aics[param_1].HarassingSiegeEnginesMax = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].SortieUnitMeleeMin = 10; + + this->aics[param_1].RaidUnitsRandom = 10; + + this->aics[param_1].recruitProbRaidWeak = 0; + + this->aics[param_1].recruitProbAttackDefault = 0x32; + + this->aics[param_1].recruitProbAttackStrong = 0x3c; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].RecruitInterval = 1; + + this->aics[param_1].RecruitIntervalStrong = 1; + + this->aics[param_1].SortieUnitRangedMin = 6; + + this->aics[param_1].SortieUnitMelee = 0x4b; + + this->aics[param_1].DefDiggingUnit = 0x47; + + this->aics[param_1].DefWalls = 0x28; + + this->aics[param_1].DefTotal = 0x28; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].DefUnit1 = 0x46; + + this->aics[param_1].DefUnit2 = 0x4c; + + this->aics[param_1].HarassingSiegeEngine1 = 0x166; + + this->aics[param_1].AttForceBase = 0x28; + + this->aics[param_1].AttForceRandom = 5; + + this->aics[param_1].SortieUnitRanged = 0x4a; + + this->aics[param_1].RaidUnit1 = 0x4a; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; + + this->aics[param_1].AttForceRallyPercentage = 0x50; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 4; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x5a; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x28; + + this->aics[param_1].SiegeEngine2 = 0x4d; + + this->aics[param_1].SiegeEngine3 = 0x4d; + + this->aics[param_1].SiegeEngine4 = 0x4d; + + this->aics[param_1].AttMaxEngineers = 9; + + this->aics[param_1].AttDiggingUnit = 0x47; + + this->aics[param_1].AttDiggingUnitMax = 0xf; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x4a; + + this->aics[param_1].AttUnitBackupMax = 0x50; + + this->aics[param_1].AttUnitBackupGroupsCount = 1; + + this->aics[param_1].AttUnitEngageMax = 10; + + this->aics[param_1].AttUnitEngage = 0x4c; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x4b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 2; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp new file mode 100644 index 000000000..a09be5a21 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp @@ -0,0 +1,281 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C9900 + void AICState ::setAICParameters_12(int param_1) + + { + + this->aics[param_1].farm1 = 0x1e; + + this->aics[param_1].farm3 = 0x1e; + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].flagType = 10; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 0x1194; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].taxesMax = 0xc; + + this->aics[param_1].farm2 = 0x20; + + this->aics[param_1].farm4 = 0x1f; + + this->aics[param_1].populationPerFarm = 4; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 0x50; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].minimumWheat = 2; + + this->aics[param_1].minimumHop = 2; + + this->aics[param_1].tradeAmountFood = 0x14; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + + this->aics[param_1].doubleRationsFoodThreshold = 0x28; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x3c; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 4; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 6; + + this->aics[param_1].populationPerIronmine = 10; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 4; + + this->aics[param_1].maxIronmines = 3; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 0x10; + + this->aics[param_1].buildInterval = 2; + + this->aics[param_1].resourceRebuildDelay = 0x28; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x50; + + this->aics[param_1].recruitProbDefDefault = 0x28; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 10; + + this->aics[param_1].SortieUnitRangedMin = 4; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 10; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].SortieUnitMeleeMin = 0x14; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].RaidUnitsRandom = 10; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackDefault = 0x28; + + this->aics[param_1].recruitProbAttackStrong = 0x32; + + this->aics[param_1].RecruitInterval = 0; + + this->aics[param_1].RecruitIntervalStrong = 0; + + this->aics[param_1].SortieUnitRanged = 0x46; + + this->aics[param_1].SortieUnitMelee = 0x4b; + + this->aics[param_1].DefDiggingUnit = 0x16; + + this->aics[param_1].DefWalls = 0x32; + + this->aics[param_1].DefTotal = 0x32; + + this->aics[param_1].DefUnit1 = 0x16; + + this->aics[param_1].DefUnit2 = 0x46; + + this->aics[param_1].RaidUnitsBase = 0x1e; + + this->aics[param_1].RaidUnit1 = 0x4b; + + this->aics[param_1].HarassingSiegeEnginesMax = 3; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].HarassingSiegeEngine2 = 0xbe; + + this->aics[param_1].HarassingSiegeEngine3 = 0x166; + + this->aics[param_1].AttForceBase = 0x1e; + + this->aics[param_1].AttForceRandom = 10; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x14; + + this->aics[param_1].AttForceRallyPercentage = 0x50; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x50; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x27; + + this->aics[param_1].SiegeEngine2 = 0x27; + + this->aics[param_1].SiegeEngine3 = 0x3d; + + this->aics[param_1].AttMaxEngineers = 6; + + this->aics[param_1].AttDiggingUnit = 0x16; + + this->aics[param_1].AttDiggingUnitMax = 0xf; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x4a; + + this->aics[param_1].AttUnitBackupMax = 0x50; + + this->aics[param_1].AttUnitBackupGroupsCount = 1; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x4b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 2; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_13.cpp b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp new file mode 100644 index 000000000..be05cbf93 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp @@ -0,0 +1,275 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C9CF0 + void AICState ::setAICParameters_13(int param_1) + + { + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].minimumWheat = 5; + + this->aics[param_1].minimumHop = 5; + + this->aics[param_1].recruitGoldThreshold = 100; + + this->aics[param_1].flagType = 10; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 0x1194; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].taxesMax = 0xc; + + this->aics[param_1].farm1 = 0x1e; + + this->aics[param_1].farm2 = 0x1e; + + this->aics[param_1].farm3 = 0x1e; + + this->aics[param_1].farm4 = 0x1f; + + this->aics[param_1].populationPerFarm = 3; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].tradeAmountFood = 10; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x1e; + + this->aics[param_1].doubleRationsFoodThreshold = 0x1e; + + this->aics[param_1].maxWood = 0x32; + + this->aics[param_1].maxStone = 0x28; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 4; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 0x14; + + this->aics[param_1].populationPerIronmine = 10; + + this->aics[param_1].populationPerPitchrig = 0xf; + + this->aics[param_1].maxQuarries = 1; + + this->aics[param_1].maxIronmines = 2; + + this->aics[param_1].maxWoodcutters = 0xc; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 0x10; + + this->aics[param_1].buildInterval = 1; + + this->aics[param_1].resourceRebuildDelay = 0x14; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource03 = 6; + + this->aics[param_1].sellResource08 = 0x11; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x50; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackDefault = 0x1e; + + this->aics[param_1].RecruitIntervalStrong = 1; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].RecruitInterval = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].recruitProbDefDefault = 0x32; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 0; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 0x14; + + this->aics[param_1].recruitProbAttackStrong = 0x32; + + this->aics[param_1].RecruitIntervalWeak = 8; + + this->aics[param_1].SortieUnitRanged = 0x46; + + this->aics[param_1].SortieUnitMeleeMin = 0xf; + + this->aics[param_1].SortieUnitMelee = 0x46; + + this->aics[param_1].DefDiggingUnitMax = 0x3c; + + this->aics[param_1].DefDiggingUnit = 0x47; + + this->aics[param_1].DefWalls = 0x50; + + this->aics[param_1].DefTotal = 0x50; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].DefUnit1 = 0x46; + + this->aics[param_1].HarassingSiegeEnginesMax = 0; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].AttForceBase = 0x28; + + this->aics[param_1].AttForceRandom = 0; + + this->aics[param_1].SortieUnitRangedMin = 5; + + this->aics[param_1].RaidUnitsBase = 5; + + this->aics[param_1].RaidUnitsRandom = 5; + + this->aics[param_1].RaidUnit1 = 0x49; + + this->aics[param_1].AttForceSupportAllyThreshold = 10; + + this->aics[param_1].AttForceRallyPercentage = 0x32; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x32; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x27; + + this->aics[param_1].AttMaxEngineers = 0; + + this->aics[param_1].AttDiggingUnit = 0x47; + + this->aics[param_1].AttDiggingUnitMax = 0x14; + + this->aics[param_1].AttMaxAssassins = 0x28; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x4a; + + this->aics[param_1].AttUnitBackupMax = 0; + + this->aics[param_1].AttUnitBackupGroupsCount = 0; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x49; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 4; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp new file mode 100644 index 000000000..c5590667e --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp @@ -0,0 +1,289 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CA0C0 + void AICState ::setAICParameters_14(int param_1) + + { + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 2; + + this->aics[param_1].tradeAmountEquipment = 2; + + this->aics[param_1].defWallPatrolGroups = 2; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].aiRequestDelay = 0x28; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x28; + + this->aics[param_1].doubleRationsFoodThreshold = 0x28; + + this->aics[param_1].defSiegeEngineGoldThreshold = 200; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 6000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 3; + + this->aics[param_1].taxesMax = 0xb; + + this->aics[param_1].farm1 = 0x20; + + this->aics[param_1].farm2 = 0x1f; + + this->aics[param_1].farm3 = 0x21; + + this->aics[param_1].populationPerFarm = 4; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 300; + + this->aics[param_1].minimumApples = 0x14; + + this->aics[param_1].minimumCheese = 0x14; + + this->aics[param_1].tradeAmountFood = 10; + + this->aics[param_1].maxWood = 0x32; + + this->aics[param_1].maxStone = 0x32; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 10; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 5; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 10; + + this->aics[param_1].populationPerIronmine = 0xc; + + this->aics[param_1].populationPerPitchrig = 0xf; + + this->aics[param_1].maxQuarries = 3; + + this->aics[param_1].maxIronmines = 6; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxPitchrigs = 4; + + this->aics[param_1].maxFarms = 10; + + this->aics[param_1].buildInterval = 3; + + this->aics[param_1].resourceRebuildDelay = 8; + + this->aics[param_1].blacksmithSetting = 0x15; + + this->aics[param_1].fletcherSetting = 0x12; + + this->aics[param_1].poleturnerSetting = 0x14; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource08 = 0x11; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 8; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown073 = 0x1e; + + this->aics[param_1].recruitProbDefWeak = 100; + + this->aics[param_1].recruitProbDefDefault = 0x32; + + this->aics[param_1].recruitProbDefStrong = 0x1e; + + this->aics[param_1].recruitProbRaidDefault = 0x1e; + + this->aics[param_1].RecruitInterval = 4; + + this->aics[param_1].RecruitIntervalStrong = 4; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].RaidUnitsRandom = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].recruitProbAttackDefault = 0x14; + + this->aics[param_1].recruitProbAttackStrong = 0x14; + + this->aics[param_1].recruitProbRaidStrong = 0x32; + + this->aics[param_1].SortieUnitRangedMin = 10; + + this->aics[param_1].SortieUnitMeleeMin = 10; + + this->aics[param_1].DefTotal = 0x32; + + this->aics[param_1].RaidUnitsBase = 10; + + this->aics[param_1].recruitProbRaidWeak = 0; + + this->aics[param_1].recruitProbAttackWeak = 0; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].SortieUnitRanged = 0x17; + + this->aics[param_1].DefWalls = 0x28; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 5; + + this->aics[param_1].DefUnit1 = 0x17; + + this->aics[param_1].DefUnit2 = 0x17; + + this->aics[param_1].DefUnit3 = 0x17; + + this->aics[param_1].DefUnit4 = 0x4c; + + this->aics[param_1].DefUnit5 = 0x49; + + this->aics[param_1].HarassingSiegeEnginesMax = 5; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].HarassingSiegeEngine2 = 0x166; + + this->aics[param_1].SortieUnitMelee = 0x1a; + + this->aics[param_1].DefDiggingUnit = 0x1a; + + this->aics[param_1].RaidUnit1 = 0x1a; + + this->aics[param_1].AttForceBase = 0x32; + + this->aics[param_1].AttForceRandom = 0x14; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x32; + + this->aics[param_1].AttForceRallyPercentage = 0x50; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 5; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 8; + + this->aics[param_1].AttCoordinationPreference = 0x32; + + this->aics[param_1].CowThrowInterval = 6; + + this->aics[param_1].SiegeEngine1 = 0x27; + + this->aics[param_1].SiegeEngine2 = 0x27; + + this->aics[param_1].SiegeEngine3 = 0x4d; + + this->aics[param_1].SiegeEngine4 = 0x4d; + + this->aics[param_1].SiegeEngine5 = 0x4d; + + this->aics[param_1].AttMaxEngineers = 10; + + this->aics[param_1].AttDiggingUnit = 0x47; + + this->aics[param_1].AttDiggingUnitMax = 0x50; + + this->aics[param_1].AttMaxAssassins = 10; + + this->aics[param_1].AttUnit2 = 0x1a; + + this->aics[param_1].AttUnit2Max = 10; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0x4c; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x17; + + this->aics[param_1].AttUnitBackupMax = 0x32; + + this->aics[param_1].AttUnitBackupGroupsCount = 1; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0x1a; + + this->aics[param_1].AttUnitSiegeDefMax = 6; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; + + this->aics[param_1].AttUnitMain1 = 0x1a; + + this->aics[param_1].AttUnitMain2 = 0x1a; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 3; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_15.cpp b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp new file mode 100644 index 000000000..db36e5ca0 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp @@ -0,0 +1,275 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CA4D0 + void AICState ::setAICParameters_15(int param_1) + + { + + this->aics[param_1].farm1 = 0x21; + + this->aics[param_1].farm3 = 0x21; + + this->aics[param_1].farm4 = 0x21; + + this->aics[param_1].populationPerFarm = 5; + + this->aics[param_1].minimumHop = 5; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 7; + + this->aics[param_1].populationPerIronmine = 7; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].maxResourceOther = 0xc; + + this->aics[param_1].maxIronmines = 3; + + this->aics[param_1].buildInterval = 3; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 8000; + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].taxesMax = 10; + + this->aics[param_1].farm2 = 0x1f; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].minimumCheese = 10; + + this->aics[param_1].tradeAmountFood = 0x14; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0; + + this->aics[param_1].doubleRationsFoodThreshold = 0x50; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x32; + + this->aics[param_1].maxEquipment = 10; + + this->aics[param_1].maxBeer = 6; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 1; + + this->aics[param_1].maxWoodcutters = 8; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 9; + + this->aics[param_1].resourceRebuildDelay = 0x28; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource04 = 7; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].RecruitIntervalStrong = 4; + + this->aics[param_1].SortieUnitRangedMin = 4; + + this->aics[param_1].SortieUnitMeleeMin = 4; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].RaidUnitsRandom = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].recruitProbRaidWeak = 0x28; + + this->aics[param_1].recruitProbRaidDefault = 0x28; + + this->aics[param_1].recruitProbAttackWeak = 10; + + this->aics[param_1].SortieUnitRanged = 0x16; + + this->aics[param_1].DefDiggingUnit = 0x16; + + this->aics[param_1].DefTotal = 0x28; + + this->aics[param_1].DefUnit1 = 0x16; + + this->aics[param_1].AttForceBase = 10; + + this->aics[param_1].AttForceSupportAllyThreshold = 10; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x32; + + this->aics[param_1].recruitProbDefDefault = 0x1e; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackDefault = 0x1e; + + this->aics[param_1].recruitProbAttackStrong = 0x32; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].RecruitInterval = 1; + + this->aics[param_1].SortieUnitMelee = 0x1c; + + this->aics[param_1].DefWalls = 0x1e; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].RaidUnitsBase = 0x10; + + this->aics[param_1].RaidUnit1 = 0x1c; + + this->aics[param_1].HarassingSiegeEnginesMax = 1; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].AttForceRandom = 0x14; + + this->aics[param_1].AttForceRallyPercentage = 0x32; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x46; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x28; + + this->aics[param_1].SiegeEngine2 = 0x28; + + this->aics[param_1].AttMaxEngineers = 6; + + this->aics[param_1].AttDiggingUnit = 0x16; + + this->aics[param_1].AttDiggingUnitMax = 0x14; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x16; + + this->aics[param_1].AttUnitBackupMax = 0x1e; + + this->aics[param_1].AttUnitBackupGroupsCount = 3; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x1b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 2; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_16.cpp b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp new file mode 100644 index 000000000..98b8a0d26 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp @@ -0,0 +1,277 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CA8A0 + void AICState ::setAICParameters_16(int param_1) + + { + + this->aics[param_1].taxesMax = 0xc; + + this->aics[param_1].farm2 = 0x1e; + + this->aics[param_1].farm3 = 0x1e; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].maxFarms = 0xc; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 0x1194; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].farm1 = 0x1f; + + this->aics[param_1].populationPerFarm = 4; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 2; + + this->aics[param_1].minimumHop = 2; + + this->aics[param_1].tradeAmountFood = 5; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + + this->aics[param_1].doubleRationsFoodThreshold = 0x28; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x28; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 4; + + this->aics[param_1].maxBeer = 5; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 0x32; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 6; + + this->aics[param_1].populationPerIronmine = 10; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 4; + + this->aics[param_1].maxIronmines = 2; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxPitchrigs = 0; + + this->aics[param_1].buildInterval = 2; + + this->aics[param_1].resourceRebuildDelay = 0x28; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource03 = 6; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x50; + + this->aics[param_1].recruitProbDefDefault = 0x28; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 10; + + this->aics[param_1].SortieUnitRangedMin = 4; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].RecruitInterval = 1; + + this->aics[param_1].RecruitIntervalStrong = 1; + + this->aics[param_1].SortieUnitRanged = 0x16; + + this->aics[param_1].DefDiggingUnit = 0x16; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].DefUnit1 = 0x16; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackWeak = 10; + + this->aics[param_1].recruitProbAttackDefault = 0x28; + + this->aics[param_1].recruitProbAttackStrong = 0x32; + + this->aics[param_1].SortieUnitMeleeMin = 0x14; + + this->aics[param_1].SortieUnitMelee = 0x25; + + this->aics[param_1].DefWalls = 0x1e; + + this->aics[param_1].DefTotal = 0x1e; + + this->aics[param_1].RaidUnitsBase = 0x1e; + + this->aics[param_1].RaidUnitsRandom = 10; + + this->aics[param_1].RaidUnit1 = 0x25; + + this->aics[param_1].HarassingSiegeEnginesMax = 5; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].AttForceBase = 0x32; + + this->aics[param_1].AttForceRandom = 10; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x28; + + this->aics[param_1].AttForceRallyPercentage = 0x50; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x50; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x27; + + this->aics[param_1].SiegeEngine2 = 0x27; + + this->aics[param_1].SiegeEngine3 = 0x27; + + this->aics[param_1].SiegeEngine4 = 0x27; + + this->aics[param_1].AttMaxEngineers = 8; + + this->aics[param_1].AttDiggingUnit = 0x16; + + this->aics[param_1].AttDiggingUnitMax = 10; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x16; + + this->aics[param_1].AttUnitBackupMax = 0x28; + + this->aics[param_1].AttUnitBackupGroupsCount = 1; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x25; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 2; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp index 2a27d6607..339f09d84 100644 --- a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp +++ b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp @@ -18,14 +18,14 @@ namespace AI { if (90 < _willingnessPercentage) { _willingnessPercentage = 90; } - int _rng = (int)SEC_RNG::instance.currentNumber2; + int _rngMod100 = (int)(short)SEC_RNG::instance.currentNumber2 % 100; MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - if (_rng % 100 < _willingnessPercentage / 2) { + if (_rngMod100 < _willingnessPercentage / 2) { DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = 2; return; } DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel - = (uint)(_rng % 100 < _willingnessPercentage); + = (uint)(_rngMod100 < _willingnessPercentage); } } } diff --git a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp index 772489730..79dbdfb54 100644 --- a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp +++ b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp @@ -13,14 +13,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF5E0 void AICState::setEightTribe0xc0TribesToAggressiveAndAttack(int playerID) { - int _tribeID; - int iVar1; - short* psVar2; if (DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) { - iVar1 = 0; - psVar2 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xc0; + int iVar1 = 0; + short* psVar2 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xc0; do { - _tribeID = (int)*psVar2; + int _tribeID = (int)*psVar2; if (((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar1 + 0xc0])) diff --git a/src/OpenSHC/AI/AICState/setInitialAIC.cpp b/src/OpenSHC/AI/AICState/setInitialAIC.cpp new file mode 100644 index 000000000..e8bcb8cdb --- /dev/null +++ b/src/OpenSHC/AI/AICState/setInitialAIC.cpp @@ -0,0 +1,52 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D18B0 + void AICState ::setInitialAIC() + + { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::wipeAICMemory, this)(); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_01, this)(1); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_02, this)(2); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_03, this)(3); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_04, this)(4); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_05, this)(5); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_06, this)(6); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_07, this)(7); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_08, this)(8); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_09, this)(9); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_10, this)(10); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_11, this)(0xb); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_12, this)(0xc); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_13, this)(0xd); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_14, this)(0xe); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_15, this)(0xf); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_16, this)(0x10); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp b/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp new file mode 100644 index 000000000..072dc6674 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp @@ -0,0 +1,52 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE3B0 + void AICState ::setNextMoveLocationForUnits(int playerID) + + { + + if ((short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX] + != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)( + (int)(short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]); + } + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, + (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY)), -1, -1, 4000, FALSE); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::setDestinationPairsBasedOnPreviousSearch, + DAT_PathFindingState::ptr)( + playerID + -1, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp new file mode 100644 index 000000000..080fa0a94 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp @@ -0,0 +1,196 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AIC/AITargetChoiceInt.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + using OpenSHC::AI::AIC::AITargetChoiceInt; + using OpenSHC::Game::Player::PlayerData; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CACB0 + void AICState ::setTargetForTribeBasedOnTargetChoiceLogic(int owner, int tribe) + + { + + int _lord; + + int _lordBackup; + + int _minDistance; + + int _distance; + + int _targetPlayer; + + PlayerData* _ptrPlayerData; + + int _playerID_backup; + + int _player; + + PlayerData* _ptrPlayerData_backup; + + int _maxGold; + + int _minPoints; + + int _aiType; + + int _gold; + + int _points; + + int _ownerKeepX; + + int _ownerKeepY; + + AITargetChoiceInt _targetChoice; + + _aiType = DAT_GameState::instance.playerDataArray[owner].aiType; + + _targetPlayer = 0; + + if (_aiType != 0) { + + _ownerKeepY = DAT_GameState::instance.playerDataArray[owner].campground.yEntry; + + _ownerKeepX = DAT_GameState::instance.playerDataArray[owner].campground.xEntry; + + _minDistance = 10000; + + _maxGold = 0; + + _minPoints = 1000000; + + _player = 1; + + _ptrPlayerData = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); + + do { + + if ((DAT_GameState::instance.mapAndTime.playerTeams[_player] + != DAT_GameState::instance.mapAndTime.playerTeams[owner]) + && (_lord = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_player), + _lord != 0)) { + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, + (_ptrPlayerData->campground).yEntry, _ownerKeepX, _ownerKeepY); + + _targetChoice = this->aics[_aiType + -1].TargetChoice; + + _gold = _maxGold; + + _points = _minPoints; + + if (_targetChoice == OpenSHC::AI::AIC::AITC_PLAYER) { + + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_player] != -1) { + + joined_r0x004cad9a: + _distance = DAT_DirectionAlgorithmState::instance.distanceHigh; + + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _minDistance) { + + LAB_004cadf6: + _minPoints = _points; + + _maxGold = _gold; + + _minDistance = _distance; + + _targetPlayer = _player; + } + } + + } + + else { + + if (_targetChoice == OpenSHC::AI::AIC::AITC_CLOSEST) + goto joined_r0x004cad9a; + + _distance = _minDistance; + + if (_targetChoice == OpenSHC::AI::AIC::AITC_GOLD) { + + _gold = _ptrPlayerData->currentResources[0xf]; + + if (_maxGold <= _ptrPlayerData->currentResources[0xf]) + goto LAB_004cadf6; + + } + + else if ((_targetChoice == OpenSHC::AI::AIC::AITC_BALANCED) + && (_points = _ptrPlayerData->currentPopulation * 5 + _ptrPlayerData->totalTroopValue + + _ptrPlayerData->currentResources[0xf] / 100 + + DAT_DirectionAlgorithmState::instance.distanceHigh * 2, + _points <= _minPoints)) + goto LAB_004cadf6; + } + } + + _player = _player + 1; + + _ptrPlayerData = _ptrPlayerData + 1; + + } while (_player < 9); + + if (_targetPlayer == 0) { + + _playerID_backup = 1; + + _ptrPlayerData_backup = &DAT_GameState::instance.playerDataArray[1]; + + do { + + if (((DAT_GameState::instance.mapAndTime.playerTeams[_playerID_backup] + != DAT_GameState::instance.mapAndTime.playerTeams[owner]) + && (_lordBackup + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_playerID_backup), + _lordBackup != 0)) + && (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData_backup->campground).xEntry, + (_ptrPlayerData_backup->campground).yEntry, _ownerKeepX, _ownerKeepY), + DAT_DirectionAlgorithmState::instance.distanceHigh <= _minDistance)) { + + _minDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + + _targetPlayer = _playerID_backup; + } + + _playerID_backup = _playerID_backup + 1; + + _ptrPlayerData_backup = _ptrPlayerData_backup + 1; + + } while (_playerID_backup < 9); + + if (_targetPlayer == 0) { + + return; + } + } + + DAT_TribesState::instance.tribes[tribe].targetPlayer_outpost = (short)_targetPlayer; + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp new file mode 100644 index 000000000..f7b90a16b --- /dev/null +++ b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp @@ -0,0 +1,152 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" +#include "OpenSHC/Game/Resources/ResourceTypeShort.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Buildings/BuildingTypeShort.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Game::Resources::ResourceType; + using OpenSHC::Game::Resources::ResourceTypeShort; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Buildings::BuildingTypeShort; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CBE30 + void AICState ::setupWorkshopProductionType(int playerID, int buildingID) + + { + + AITypeInt AVar1; + + int _aiTypeMin1; + + ResourceTypeShort RVar2; + + BuildingTypeShort _buildingType; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + return; + } + + _buildingType = DAT_BuildingsState::instance.buildings[buildingID].buildingType; + + _aiTypeMin1 = AVar1 + ~OpenSHC::AI::AIT_NULL; + RVar2 = OpenSHC::Game::Resources::RT_SWORD; + + if (_buildingType == OpenSHC::Map::Buildings::BT_BLACKSMITH) { + + _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 200); + + if (_aiTypeMin1 == -999) { + + _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, + DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, + OpenSHC::Map::Buildings::BT_BLACKSMITH); + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = (ResourceTypeShort)_aiTypeMin1; + + return; + } + + RVar2 = OpenSHC::Game::Resources::RT_SWORD; + + if (_aiTypeMin1 == 0x16) + goto LAB_004cbf6a; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_MACE; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = OpenSHC::Game::Resources::RT_MACE; + + return; + } + + // orig: cmp dx, 0xe; jne 0x5a (skip poleturner block to fletcher/end) + // poleturner falls through, fletcher and end are jumped to + if (_buildingType == OpenSHC::Map::Buildings::BT_POLETURNER) { + + _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 0xd0); + + if (_aiTypeMin1 == -999) { + + _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, + DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, + OpenSHC::Map::Buildings::BT_POLETURNER); + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = (ResourceTypeShort)_aiTypeMin1; + + return; + } + + RVar2 = OpenSHC::Game::Resources::RT_SPEAR; + + if (_aiTypeMin1 == 0x13) + goto LAB_004cbf6a; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_PIKE; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_PIKE; + + return; + } + + if (_buildingType == OpenSHC::Map::Buildings::BT_FLETCHER) { + + _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 0xcc); + + if (_aiTypeMin1 == -999) { + + _aiTypeMin1 + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, + DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, + OpenSHC::Map::Buildings::BT_FLETCHER); + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType + = (ResourceTypeShort)_aiTypeMin1; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = (ResourceTypeShort)_aiTypeMin1; + + return; + } + + RVar2 = OpenSHC::Game::Resources::RT_BOW; + + if (_aiTypeMin1 == 0x11) + goto LAB_004cbf6a; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType + = OpenSHC::Game::Resources::RT_CROSSBOW; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = OpenSHC::Game::Resources::RT_CROSSBOW; + } + + return; + + LAB_004cbf6a: + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = RVar2; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = RVar2; + + return; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp b/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp new file mode 100644 index 000000000..80ba930bb --- /dev/null +++ b/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp @@ -0,0 +1,203 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Text/TextManager.func.hpp" +#include "OpenSHC/DE/SHCDE/eTextSections.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TextManagerObject.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::DE::SHCDE::eTextSections; + using OpenSHC::Game::Player::PlayerData; + + /* + 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 0x004D05D0 + int AICState ::shareGoldAmongTeamMembers(int playerID, int gold) + + { + + int* piVar1; + + char cVar2; + + int _playerOffset; + + int _goldPerPlayer; + + char* pcVar3; + + char* pcVar4; + + PlayerData* _ptrPlayerData; + + int _totalPlayers; + + int _candidates[9]; + + int _targetPlayer; + + int _playerIndex; + + int _playerIndexTracker; + + int* _ptrCurrentGold; + + _totalPlayers = 0; + + _ptrPlayerData = &DAT_GameState::instance.playerDataArray[2]; + + _playerOffset = 0; + + _playerIndex = 3; + + do { + + if ((((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 4) != 0) + || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 4) + != -1)) + && (_playerIndex + -2 != playerID)) + && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 4) + == DAT_GameState::instance.mapAndTime.playerTeams[playerID] + && (DAT_GameState::instance.playerDataArray[1].lordKilledByPlayerID == 0)))) { + + /* + if lord of team member not dead, then: */ + + _candidates[_totalPlayers] = _playerIndex + -2; + + _totalPlayers = _totalPlayers + 1; + } + + if (((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 8) != 0) + || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 8) + != -1)) + && ((_playerIndex + -1 != playerID + && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 8) + == DAT_GameState::instance.mapAndTime.playerTeams[playerID] + && (_ptrPlayerData->lordKilledByPlayerID == 0)))))) { + + _candidates[_totalPlayers] = _playerIndex + -1; + + _totalPlayers = _totalPlayers + 1; + } + + if ((((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 0xc) != 0) + || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 0xc) + != -1)) + && (_playerIndex != playerID)) + && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 0xc) + == DAT_GameState::instance.mapAndTime.playerTeams[playerID] + && (DAT_GameState::instance.playerDataArray[3].lordKilledByPlayerID == 0)))) { + + _candidates[_totalPlayers] = _playerIndex; + + _totalPlayers = _totalPlayers + 1; + } + + if (((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 0x10) != 0) + || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 0x10) + != -1)) + && ((_playerIndex + 1 != playerID + && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 0x10) + == DAT_GameState::instance.mapAndTime.playerTeams[playerID] + && (DAT_GameState::instance.playerDataArray[4].lordKilledByPlayerID == 0)))))) { + + _candidates[_totalPlayers] = _playerIndex + 1; + + _totalPlayers = _totalPlayers + 1; + } + + _playerIndexTracker = _playerIndex + 2; + + _playerOffset = _playerOffset + 16; + + _ptrPlayerData = _ptrPlayerData + 0x39f4; + + _playerIndex = _playerIndex + 4; + + } while (_playerIndexTracker < 9); + + /* + fixme: repurposed variable */ + + if (((_totalPlayers != 0) + && (_goldPerPlayer = gold / _totalPlayers, _playerOffset = _goldPerPlayer, _goldPerPlayer != 0)) + && (_playerIndex = 0, 0 < _totalPlayers)) { + + _ptrCurrentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources + 0xf; + + do { + + _targetPlayer = _candidates[_playerIndex]; + + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_targetPlayer] != -1) { + + /* + "Goods received from ally" + added by script: "Goods received from ally" */ + + pcVar3 = MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::getTextStringInGroupAtOffset, + DAT_TextManagerObject::ptr)(OpenSHC::DE::SHCDE::TEXT_ALLIES2, 1); + + pcVar4 = DAT_GameSynchronyState::instance.receivedChatMessage; + + do { + + cVar2 = *pcVar3; + + *pcVar4 = cVar2; + + pcVar3 = pcVar3 + 1; + + pcVar4 = pcVar4 + 1; + + } while (cVar2 != '\0'); + + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::addChatMessageToDisplayList, + DAT_GameSynchronyState::ptr)(_targetPlayer, 0); + + /* + "Goods types" + added by script: "Gold" */ + + pcVar3 = MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::getTextStringInGroupAtOffset, + DAT_TextManagerObject::ptr)(OpenSHC::DE::SHCDE::TEXT_GOODS, 0xf); + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)( + DAT_GameSynchronyState::instance.receivedChatMessage, "%d %s - ", _goldPerPlayer, pcVar3); + + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::addChatMessageToDisplayList, + DAT_GameSynchronyState::ptr)(_targetPlayer, playerID); + } + + *_ptrCurrentGold = *_ptrCurrentGold - _goldPerPlayer; + + piVar1 = DAT_GameState::instance.playerDataArray[_targetPlayer].currentResources + 0xf; + + *piVar1 = *piVar1 + _goldPerPlayer; + + _playerOffset = _targetPlayer * 0x39f4 + 0x115c304; + + _playerIndex = _playerIndex + 1; + + } while (_playerIndex < _totalPlayers); + } + + return _playerOffset; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp index 47697719a..e16bf1b27 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp @@ -9,11 +9,10 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004ECA90 BOOLEnum AICState::shouldNotBuildKillingPits(int playerID, Commands::CommandBuildingType commandBuildingType) { - BOOLEnum _totalAbove99 = FALSE; if (commandBuildingType == Commands::CBT_KILLINGPIT) { - _totalAbove99 = (BOOLEnum)(DAT_AIVState::instance.mapExtraInfo.playerTotalKillingPits[playerID] >= 100); + return (BOOLEnum)(DAT_AIVState::instance.mapExtraInfo.playerTotalKillingPits[playerID] >= 100); } - return _totalAbove99; + return FALSE; } } } diff --git a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp index 676b02f35..d2a7df33b 100644 --- a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp +++ b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp @@ -9,7 +9,6 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB700 BOOLEnum AICState::shouldWaitWithBuildingAPositiveFearFactor(int playerID, Commands::CommandBuildingType param_2) { - int* piVar1; switch (param_2) { case Commands::CBT_COMMUNAL_GARDEN1: case Commands::CBT_COMMUNAL_GARDEN2: @@ -39,8 +38,7 @@ namespace AI { case Commands::CBT_SMALL_POND_3: case Commands::CBT_LARGE_POND_3: case Commands::CBT_LARGE_POND_4: - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay; - *piVar1 = *piVar1 + 1; + DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay += 1; if (DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay < 200) { return TRUE; } diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp index a7b0d34e6..e4b8ffcd5 100644 --- a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -10,7 +10,7 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC9B0 - int AICState::smallestTribeOfUnitType(int playerID, short* unitType) + int AICState::smallestTribeOfUnitType(int playerID, UnitType unitType) { int iVar7 = 0; int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; @@ -22,15 +22,14 @@ namespace AI { int _tribeID = 0; int local_c = 0; short sVar4 = 1000; - if ((iVar3 < iVar6) - && (((unitType == (short*)0x8 || (unitType == (short*)0xa)) || (unitType == (short*)0x11)))) { + if ((iVar3 < iVar6) && (((unitType == 0x8 || (unitType == 0xa)) || (unitType == 0x11)))) { iVar6 = iVar3; } iVar3 = DAT_SkirmishDefinedData::instance.DAT_AiTribeIDOffsetForUnitType[(int)unitType]; if (0 < iVar6) { - unitType = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar3; + short* _aiTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar3; do { - int iVar5 = (int)*unitType; + int iVar5 = (int)*_aiTribeID; if ((iVar5 == 0) || (DAT_TribesState::instance.tribes[iVar5].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7])) { @@ -44,7 +43,7 @@ namespace AI { local_c = iVar7; sVar4 = sVar1; } - unitType = unitType + 1; + _aiTribeID = _aiTribeID + 1; iVar7 = iVar7 + 1; } while (iVar7 < iVar6); iVar7 = local_c; diff --git a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp new file mode 100644 index 000000000..7a9a56b30 --- /dev/null +++ b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp @@ -0,0 +1,210 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameCore.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" +#include "OpenSHC/Game/GameMode.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_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Commands::GameCommandType; + using OpenSHC::Game::GameMode; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + 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 0x004D10B0 + void AICState ::someChatMessageSelection() + + { + + BOOLEnum BVar1; + + DWORD DVar2; + + int iVar3; + + int iVar4; + + int iVar5; + + int iVar6; + + int aiStack_24[9]; + + BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)(); + + if ((BVar1 != FALSE) + && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode == OpenSHC::Game::GM_SKIRMISH_SINGLE_PLAYER)) { + + if (this->aiTauntResponseTimeWindow == 0) { + + return; + } + + DVar2 = timeGetTime(); + + if (DVar2 - this->aiTauntResponseTimeWindow < 2000) { + + return; + } + + iVar6 = 0; + + iVar3 = 0; + + iVar4 = 3; + + do { + + if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 4) != 0) + && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 4) + != DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + + aiStack_24[iVar6] = iVar4 + -2; + + iVar6 = iVar6 + 1; + } + + if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 8) != 0) + && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 8) + != DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + + aiStack_24[iVar6] = iVar4 + -1; + + iVar6 = iVar6 + 1; + } + + if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 0xc) != 0) + && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 0xc) + != DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + + aiStack_24[iVar6] = iVar4; + + iVar6 = iVar6 + 1; + } + + if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 0x10) != 0) + && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 0x10) + != DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + + aiStack_24[iVar6] = iVar4 + 1; + + iVar6 = iVar6 + 1; + } + + iVar5 = iVar4 + 2; + + iVar3 = iVar3 + 0x10; + + iVar4 = iVar4 + 4; + + } while (iVar5 < 9); + + if (0 < iVar6) { + + iVar3 = 0; + + iVar4 = 0; + + if (0 < iVar6) { + + do { + + iVar3 = iVar3 + + DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping + [DAT_GameState::instance.playerDataArray[aiStack_24[iVar4]].aiType + + OpenSHC::AI::AIT_FREDERICK][0]; + + iVar4 = iVar4 + 1; + + } while (iVar4 < iVar6); + + if (iVar3 != 0) { + + iVar5 = (int)SEC_RNG::instance.currentNumber1; + + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber1, SEC_RNG::ptr)(); + + iVar5 = iVar5 % iVar3; + + iVar4 = 0; + + do { + + iVar3 = aiStack_24[iVar4]; + + iVar5 = iVar5 + - DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping + [DAT_GameState::instance.playerDataArray[iVar3].aiType + + OpenSHC::AI::AIT_FREDERICK][0]; + + if (iVar5 < 0) { + + DAT_GameSynchronyState::instance.DAT_ChatTauntOrMessage = -2 + - DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping + [DAT_GameState::instance.playerDataArray[iVar3].aiType + + OpenSHC::AI::AIT_FREDERICK][1]; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[1] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[2] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[3] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[4] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[5] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[6] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[7] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[8] = 1; + + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = iVar3; + + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, + DAT_GameSynchronyState::ptr)(OpenSHC::Commands::GCT_TAUNT_OR_CHAT); + + this->aiTauntResponseTimeWindow = 0; + + return; + } + + iVar4 = iVar4 + 1; + + } while (iVar4 < iVar6); + } + } + } + } + + this->aiTauntResponseTimeWindow = 0; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp index 9633dd0c3..63e7743bd 100644 --- a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp +++ b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp @@ -19,43 +19,43 @@ namespace AI { / _totalEnemyTroopValue); } DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy = _relativeStrength; - if (param_2 == FALSE) { - if (DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue < 100) { - return FALSE; - } + if (param_2 != FALSE) { BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); if (BVar2 != FALSE) { - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 50) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 0x46) { return TRUE; } return FALSE; } if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 250) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 300) { return TRUE; } return FALSE; } - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 75) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 100) { return TRUE; } } else { + if (DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue < 100) { + return FALSE; + } BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); if (BVar2 != FALSE) { - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 0x46) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 50) { return TRUE; } return FALSE; } if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 300) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 250) { return TRUE; } return FALSE; } - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 100) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 75) { return TRUE; } } diff --git a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp new file mode 100644 index 000000000..258a3215f --- /dev/null +++ b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/Skirmish/SkirmishDefinedData.hpp" + +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Game::Skirmish::SkirmishDefinedData; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC8D0 + undefined4 AICState ::unitIDIsRangedOrArmored(int unitID) + + { + + SkirmishDefinedData* pSVar1; + + pSVar1 = DAT_SkirmishDefinedData::ptr; + + do { + + if (pSVar1->DAT_UnitTypes_RangedAndArmored[0] + == (int)(short)DAT_UnitsState::instance.units[unitID].unitType) { + + return (undefined4)(1); + } + + pSVar1 = (SkirmishDefinedData*)(pSVar1->DAT_UnitTypes_RangedAndArmored + 1); + + } while ((int)pSVar1 < 0xb3eb50); + + return (undefined4)(0); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp new file mode 100644 index 000000000..6946450dd --- /dev/null +++ b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp @@ -0,0 +1,165 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/AI/AIRecruitUnitChoice.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIRecruitUnitChoice; + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Game::Player::PlayerData; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D53E0 + void AICState ::updateAIBehaviour() + + { + + AITypeInt AVar1; + + PlayerData* _aiType; + + int _playerID; + + if (DAT_GameState::instance.mapAndTime.dayTicks == 10) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeOutpostTribesAttack, this)(); + } + + _aiType = &DAT_GameState::instance.playerDataArray[1]; + + _playerID = 1; + + do { + + AVar1 = _aiType->aiType; + + if (((AVar1 != OpenSHC::AI::AIT_NULL) && (_aiType->playerDeathRelated == 0)) + && (_aiType->lordKilledByPlayerID == 0)) { + + if (DAT_GameState::instance.mapAndTime.dayTicks == _playerID) { + + if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieRangedUnits, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieMeleeUnits, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitUnits, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recruitHarrassingSiegeEngines, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignMoatDiggers, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCreateSiegeUnits, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineers, this)(_playerID); + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiBuyAndSellGoods, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiGiveRaidInstructions, this)(_playerID); + } + + if (DAT_GameState::instance.mapAndTime.weekTicks == _playerID) { + + if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineerForOilDuty, this)(_playerID); + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateTribeLocations, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIPlayerState, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiUpdateTaxesAndRations, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setFoodBuyPlan, this)(_playerID); + + if (DAT_GameState::instance.mapAndTime.monthTicks != _playerID) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 0); + } + + if (_aiType->aiRequestDelay != 0) { + + _aiType->aiRequestDelay = _aiType->aiRequestDelay + -1; + } + + if (_aiType->nervousBikCountdown != 0) { + + _aiType->nervousBikCountdown = _aiType->nervousBikCountdown + -1; + } + + if (_aiType->someAiCountdown3 != 0) { + + _aiType->someAiCountdown3 = _aiType->someAiCountdown3 + -1; + } + + if (_aiType->someAiCountdown4 != 0) { + + _aiType->someAiCountdown4 = _aiType->someAiCountdown4 + -1; + } + + if (_aiType->someAiCountdown5 != 0) { + + _aiType->someAiCountdown5 = _aiType->someAiCountdown5 + -1; + } + + if (_aiType->someAiCountdown6 != 0) { + + _aiType->someAiCountdown6 = _aiType->someAiCountdown6 + -1; + } + } + + if (DAT_GameState::instance.mapAndTime.monthTicks == _playerID) { + + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::countMoatsOwnedByEachPlayer, DAT_TileMapState::ptr)(); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::instructTribe166ToMove, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToSortieUnits, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 1); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectAttackTarget, this)(_playerID); + + if (_aiType->aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_RAIDING) { + + _aiType->canStartSpending = 1; + + } + + else { + + /* + shouldSpend = recruitGoldTreshold < currentGold */ + + _aiType->canStartSpending + = (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0xc4) + < _aiType->currentResources[0xf]); + } + } + } + + _aiType = _aiType + 0xe7d; + + _playerID = _playerID + 1; + + } while ((int)_aiType < 0x117ea8c); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp new file mode 100644 index 000000000..b864cfc3e --- /dev/null +++ b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp @@ -0,0 +1,567 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D49E0 + void AICState ::updateAIPlayerState(int playerID) + + { + + short* psVar1; + + int* piVar2; + + short sVar3; + + AITypeInt AVar4; + + int _aiType; + + int iVar5; + + BOOLEnum _shouldAttack; + + int _attackedPlayerAlive; + + uint _rallyReady; + + BOOLEnum BVar6; + + int _aiPlayerState_2; + + int _aiPlayerState; + + int _playerID; + + AVar4 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar4 == OpenSHC::AI::AIT_NULL) { + + return; + } + + _aiType = AVar4 + ~OpenSHC::AI::AIT_NULL; + + iVar5 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; + + if (((iVar5 != 1) && (iVar5 == 2)) + && (iVar5 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), + iVar5 != 0)) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToPlayerIDsKeepIfPossible, this)( + playerID, (short*)((int)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk))); + + return; + } + + _aiPlayerState = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; + + if (_aiPlayerState == 0) { + + _shouldAttack = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::aiShouldAttackOrWaitForTeamCoordination, this)(playerID); + + if (_shouldAttack == FALSE) { + + /* + Send own units back to keep or campfire */ + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRetreatUnits, this)((short*)playerID); + + return; + } + + /* + proceedwithattack */ + + DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 1; + + DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue = 0; + + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience = 0; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackCoordinationLevel, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackStrength, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackRaidParameter, this)(playerID); + + piVar2 = (int*)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID * 0x39f4 + 0x115e9d4 + + playerID * 0x20); + + *piVar2 = *piVar2 + 1; + + } + + else { + + BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID); + + if ((((BVar6 != FALSE) && (_aiPlayerState != 9)) + || ((0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker + && (_aiPlayerState < 6)))) + || (199 < DAT_GameState::instance.playerDataArray[playerID].attackTicker)) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 8; + } + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); + + _attackedPlayerAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + if (_attackedPlayerAlive == 0) { + + /* + attacked player is dead */ + + iVar5 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; + + if (iVar5 < 4) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + + MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( + playerID); + + } + + else if (iVar5 < 7) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 7; + } + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearOutdatedAITribes, this)(playerID); + + _aiPlayerState_2 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; + + if (_aiPlayerState_2 != 1) { + + if (_aiPlayerState_2 == 2) { + + /* + the general state means to be attacking */ + + _rallyReady + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID); + + if (_rallyReady == 0) { + + return; + } + + /* + send the attacking units to move closer */ + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 3; + + MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setNextMoveLocationForUnits, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToAttackTribes, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0xe_toPlaceTunnels, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playTauntToAttackedPlayerBikFromPlayer, this)(playerID); + + return; + } + + if (_aiPlayerState_2 == 3) { + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + + /* + send the attacking units closer to the castle */ + + *piVar2 = *piVar2 + 1; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + + BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::processAttForceRallyPercentage, this)(playerID); + + if (BVar6 == FALSE) { + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 4; + + DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 0; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); + + return; + } + + if (_aiPlayerState_2 == 4) { + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + + *piVar2 = *piVar2 + 1; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); + + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::countSiegeEngineUnits, this)(playerID); + + if (iVar5 < 1) { + + DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 100; + } + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue; + + *piVar2 = *piVar2 + 1; + + if (DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue + <= *(int*)((int)this + _aiType * 0x2a4 + 0x208)) { + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocationFullVolume, DAT_SFXState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, 0x14); + + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + if (BVar6 == FALSE) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe11StandGroundToGate, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe13DefensiveWave, this)(playerID); + + LAB_004d4ed3: + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; + + return; + } + + } + + else { + + if (_aiPlayerState_2 != 5) { + + if (_aiPlayerState_2 == 6) { + + /* + Enemy castle breached! */ + + if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + } + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + + *piVar2 = *piVar2 + 1; + + _playerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + + DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; + + MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::calculateAttackVectorsToCampFireOfPlayer, + DAT_GameState::ptr)(_playerID); + + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToAttackBreachedCastle, this)( + playerID); + + if (iVar5 != 0) { + + return; + } + + BVar6 = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + if (BVar6 != FALSE) { + + return; + } + + BVar6 + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, + DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + if (BVar6 != FALSE) { + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; + + goto LAB_004d4ed3; + } + + if (_aiPlayerState_2 == 7) { + + piVar2 + = &DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue; + + *piVar2 = *piVar2 + 1; + + if (DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue + <= *(int*)((int)this + _aiType * 0x2a4 + 0x20c)) { + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( + playerID); + + return; + } + + if (_aiPlayerState_2 == 8) { + + /* + Retreat from attack. */ + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; + + DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( + playerID); + + if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) { + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playAnger1BikFromPlayer, this)(playerID); + + return; + } + + if (_aiPlayerState_2 != 9) { + + return; + } + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + + *piVar2 = *piVar2 + 1; + + if (((DAT_GameState::instance.playerDataArray[playerID].attackTicker < 20) + && (BVar6 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::percentageNonMovingTribesGTEAICSpecified, this)( + playerID), + BVar6 == FALSE)) + && (BVar6 + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID), + BVar6 == FALSE)) { + + return; + } + + goto LAB_004d4ff7; + } + + /* + _aiPlayerState_2 is 5 (Attack walls) */ + + if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + } + + psVar1 = &DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; + + *psVar1 = *psVar1 + 1; + + sVar3 = DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + + *piVar2 = *piVar2 + 1; + + DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; + + if (3 < sVar3) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandWallAssaultTribes, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + + MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::setTribe0x11ToAggressiveAndAttackIfConditionMet, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setEightTribe0xc0TribesToAggressiveAndAttack, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); + + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xCtoAggressiveAndAttack, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xbToAggressiveAndAttack, this)(playerID); + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + if ((BVar6 == FALSE) + && (BVar6 + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, + DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID), + BVar6 == FALSE)) { + + return; + } + } + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recreateEngineersTribe, this)(playerID); + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 2; + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::initializeGatePathfindingForOwner, + DAT_BuildingsState::ptr)(playerID); + + /* + computes the first siege location for units */ + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeEnemyKeepApproachTile, this)(playerID); + + if (0 < DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackTribesToLocations, this)((short*)playerID); + + return; + } + + LAB_004d4ff7: + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp new file mode 100644 index 000000000..22deecfe3 --- /dev/null +++ b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp @@ -0,0 +1,583 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/AI/AINervousDestroyBuildingCategory.hpp" +#include "OpenSHC/AI/AINervousDestroyBuildingCategoryInt.hpp" +#include "OpenSHC/AI/AIRecruitUnitChoice.hpp" +#include "OpenSHC/AI/AIStrengthType.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Game/TrailType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AINervousDestroyBuildingCategory; + using OpenSHC::AI::AINervousDestroyBuildingCategoryInt; + using OpenSHC::AI::AIRecruitUnitChoice; + using OpenSHC::AI::AIStrengthType; + using OpenSHC::Game::GameMode2; + using OpenSHC::Game::TrailType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + this functions info is based on np123 + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3320 + void AICState ::updateAIStrengthState(int playerID, int aiRecruitUnitChoicePreference) + + { + + int* piVar1; + + short* psVar2; + + int _totalTroopCount; + + int _aicOffset; + + int _rng; + + int _raidUnitCount; + + BOOLEnum _teamWeak; + + BOOLEnum _outOfSupplies2; + + BOOLEnum _teamWeak2; + + BOOLEnum _outOfSupplies; + + int _totalRecruitProb; + + bool bVar3; + + int _totalDefenseTroops; + + int _aiType; + + int _currentPopulation; + + int _totalFood; + + int _aiStrengthState; + + int _aiRecruitUnitChoiceState; + + int _subtraction; + + int _aiType_2; + + int _totalRaidTroops; + + int _defTotal; + + int _currentGold_2; + + int _aiNervousActionsTracker; + + AINervousDestroyBuildingCategoryInt _cat; + + int _aiNervousActionsTracker2; + + int _aiBuildingDestroyActionsTracker; + + int _currentGold; + + int _aiTypeMin1; + + AINervousDestroyBuildingCategory _cat2; + + int _recruitProbDefensive; + + int _recruitProbRaid; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + /* + is human */ + + if (_aiType == 0) { + + return; + } + + if ((char)aiRecruitUnitChoicePreference == '\0') { + + if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) { + + return; + } + + if (DAT_GameCore::instance.isSkirmishTrail != TRUE) { + + return; + } + + if (DAT_GameCore::instance.currentTrailType != OpenSHC::Game::TT_EXTREME) { + + return; + } + } + + _aiTypeMin1 = _aiType + -1; + + _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 0; + + /* + check if current gold less than 200 */ + + if (_currentGold < 200) { + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 0; + + } + + else { + + /* + 2 if currentGold > 1999 else 1 */ + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = (1999 < _currentGold) + 1; + } + + _currentPopulation = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; + + if (15 < _currentPopulation) { + + /* + if currentPopulation more than 14 */ + + if (_currentPopulation < 40) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + /* + if currentPopulation less than 40 */ + + *piVar1 = *piVar1 + 1; + + } + + else { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + /* + if current Population more than 40 */ + + *piVar1 = *piVar1 + 2; + } + } + + /* + check if total food higher than 20 */ + + _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; + + if (20 < _totalFood) { + + if (_totalFood < 200) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + *piVar1 = *piVar1 + 1; + + } + + else { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + *piVar1 = *piVar1 + 2; + } + } + + _totalTroopCount = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + + DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk + + DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; + + /* + check if troop strength above 7 */ + + if (7 < _totalTroopCount) { + + /* + check if troop strength smaller than 40 */ + + if (_totalTroopCount < 40) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + *piVar1 = *piVar1 + 2; + + } + + else { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + *piVar1 = *piVar1 + 4; + } + } + + _aiStrengthState = DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + if (_aiStrengthState < 3) { + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; + + } + + else if (_aiStrengthState < 8) { + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_DEFAULT; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_STRONG; + } + + if ((DAT_GameState::instance.playerDataArray[playerID].aivCurrentPauseIndex == 1) + && (0 < DAT_GameState::instance.playerDataArray[playerID].aivPauses[1])) { + + /* + if pausing at first pause + */ + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; + } + + /* + add the aiStrengthFeeling to (aiType * 169). The AI Personality struct is a + 169*4 long element of an array of 16 elements (all ai types, maybe more?) */ + + _aicOffset = DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + _aiTypeMin1 * 169; + + /* + fetch RecruitProbRaid for current aiType */ + + _recruitProbRaid = *(int*)((int)this + _aicOffset * 4 + 0x134); + + /* + fetch RecruitProbDefensive */ + + _recruitProbDefensive = *(int*)((int)this + _aicOffset * 4 + 0x128); + + /* + add RecruitProbAttack to the other two probs */ + + _totalRecruitProb = *(int*)((int)this + _aicOffset * 4 + 0x140) + _recruitProbRaid + _recruitProbDefensive; + + /* + check if recruitProb = 0 */ + + if (_totalRecruitProb == 0) { + + _aiRecruitUnitChoiceState = aiRecruitUnitChoicePreference; + + if (aiRecruitUnitChoicePreference == 1) { + + LAB_004d34e9: + /* + WARNING: reused variable _aiType */ + + _raidUnitCount = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(_aiTypeMin1, playerID); + + _totalDefenseTroops = DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk; + + bVar3 = (_totalDefenseTroops < _raidUnitCount); + + _subtraction = _totalDefenseTroops - _raidUnitCount; + + goto LAB_004d3515; + } + + if (aiRecruitUnitChoicePreference == 0) + goto LAB_004d3502; + + } + + else { + + _rng = (int)SEC_RNG::instance.currentNumber2; + + /* + WARNING: prob is now randomized */ + + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + + /* + if DAT_01fe7da8 < 4800 */ + + if ((int)DAT_GameCore::instance.mapTimeInTicks < 4800) { + + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; + + LAB_004d3502: + _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; + + /* + true if param1 > param0 */ + + _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); + + bVar3 = (_totalRaidTroops < _defTotal); + + _subtraction = _totalRaidTroops - _defTotal; + + LAB_004d3515: + if (bVar3 != _subtraction < 0) + goto LAB_004d351c; + + } + + else { + + /* + if RecruitProbDefensive > RandomizedRecruitProb */ + + if (_rng % _totalRecruitProb < _recruitProbDefensive) { + + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; + + goto LAB_004d3502; + } + + if (_rng % _totalRecruitProb < _recruitProbRaid + _recruitProbDefensive) { + + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_RAIDING; + + goto LAB_004d34e9; + } + } + + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_ATTACKING; + } + + LAB_004d351c: + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState != _aiRecruitUnitChoiceState) { + + DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = _aiRecruitUnitChoiceState; + } + + if ((char)aiRecruitUnitChoicePreference == '\0') { + + return; + } + + if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) { + + _teamWeak = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, TRUE); + + if (_teamWeak == FALSE) { + + DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = 0; + + return; + } + + /* + WARNING: aiType now means currentGold */ + + _currentGold_2 = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; + + DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; + + /* + if gold <= 500 */ + + if (_currentGold_2 < 500) { + + _aiNervousActionsTracker = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + if (_aiNervousActionsTracker < 8) { + + /* + destroy a good or bad thing */ + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS); + + _cat = OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS; + + } + + else { + + if (5 < _aiNervousActionsTracker) + goto LAB_004d35fb; + + /* + fixme: does this line ever happen? */ + + _cat = OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS; + } + + /* + destroy a workshop (2) or a resource building (iron mine... bakery) (6) */ + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, (AINervousDestroyBuildingCategory)((int)(_cat))); + + } + + else { + + /* + if gold > 2500 and... */ + + if (((2500 < _currentGold_2) + && (psVar2 = &DAT_GameState::instance.playerDataArray[playerID].aiStateCounter, + *psVar2 = *psVar2 + 1, + (DAT_GameState::instance.playerDataArray[playerID].aiStateCounter & 1U) != 0)) + && (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 20)) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::shareGoldAmongTeamMembers, this)( + playerID, _currentGold_2 / 10); + } + } + + LAB_004d35fb: + _aiNervousActionsTracker2 = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + if (_aiNervousActionsTracker2 < 2) { + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = _aiNervousActionsTracker2 + -1; + + return; + } + + /* + ********************************************************* + * From here on we process logic for destroying buildings + ********************************************************* */ + + _aiBuildingDestroyActionsTracker + = DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + + if (_aiBuildingDestroyActionsTracker < 1) { + + _teamWeak2 + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, FALSE); + + if (_teamWeak2 != FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playNervous2BikFromPlayer, this)(playerID); + + DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = 8; + + DAT_GameState::instance.playerDataArray[playerID].aiStateCounter = 0; + + return; + } + + _outOfSupplies = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); + + if (_outOfSupplies == FALSE) { + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 8; + + return; + } + + _outOfSupplies2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); + + if (_outOfSupplies2 == FALSE) { + + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 0; + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] = 20; + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; + + DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; + + if (_aiBuildingDestroyActionsTracker == 8) { + + _cat2 = OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS; + + } + + else { + + if (_aiBuildingDestroyActionsTracker == 7) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + + *piVar1 = *piVar1 + -1; + + return; + } + + if (_aiBuildingDestroyActionsTracker == 6) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_GATEHOUSES_TOWERS_GUILDS); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_BARRACKS_MERCPOST_STABLES); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WATER_BUILDINGS); + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + + *piVar1 = *piVar1 + -1; + + return; + } + + if (_aiBuildingDestroyActionsTracker == 5) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + + *piVar1 = *piVar1 + -1; + + return; + } + + if (_aiBuildingDestroyActionsTracker != 4) + goto LAB_004d3707; + + _cat2 = OpenSHC::AI::AINDBC_FARMS; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)(playerID, _cat2); + + LAB_004d3707: + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + + *piVar1 = *piVar1 + -1; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/updateTribeLocations.cpp b/src/OpenSHC/AI/AICState/updateTribeLocations.cpp new file mode 100644 index 000000000..65cc46e7b --- /dev/null +++ b/src/OpenSHC/AI/AICState/updateTribeLocations.cpp @@ -0,0 +1,74 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" + +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4940 + void AICState ::updateTribeLocations(int playerID) + + { + + int* piVar1; + + AITypeInt AVar2; + + AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar2 != OpenSHC::AI::AIT_NULL) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter; + + *piVar1 = *piVar1 + 1; + + /* + defWallPatrolRallyTime + */ + + if (*(int*)((int)DAT_EntityState::instance.seagullArray + AVar2 * 0x2a4 + 0x2580) + <= DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits; + + *piVar1 = *piVar1 + 1; + + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter = 0; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::ifHasTribe0SendUnitsToKeep, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeAtOffset1ToCampfire, this)(playerID); + + if (DAT_GameState::instance.mapAndTime.monthTicks == playerID) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::digNearestMoat, this)(playerID); + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendRangedUnitTribesToAIVSlotsOrKeepIfNervous, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed, + this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendWallPatrolUnitTribesToAIVLocations, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendOilMenForOilPickupOrToAIVLocations, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiGiveOuterPatrolCommand, this)(playerID); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp new file mode 100644 index 000000000..8011403c9 --- /dev/null +++ b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp @@ -0,0 +1,206 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/Tribes/AITribeType.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::Tribes::AITribeType; + using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::UnitInstructionType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CEFD0 + void AICState ::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers(int playerID) + + { + + AITypeInt AVar1; + + int iVar2; + + int _counterTill6; + + int _selectionID2; + + int iVar3; + + int* piVar4; + + CommandBuildingType _siegeEngineType; + + int iVar5; + + int _counterTill8; + + int _aiTribeID; + + int* _siegeEngineUnitType; + + int local_18; + + int _requiredEngineers; + + short _currentAttackWave; + + short _size; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 != OpenSHC::AI::AIT_NULL) { + + _aiTribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; + + if ((_aiTribeID != 0) + && (DAT_TribesState::instance.tribes[_aiTribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { + + _size = DAT_TribesState::instance.tribes[_aiTribeID].size; + + local_18 = (int)_size; + + iVar3 = 0; + + _siegeEngineUnitType = (int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x214); + + piVar4 = _siegeEngineUnitType; + + iVar5 = 0; + + do { + + if (*piVar4 < 1) + break; + + iVar2 = 0; + + do { + + if (*piVar4 == DAT_SkirmishDefinedData::instance.DAT_SiegeEngineUnitType[iVar2]) { + + _requiredEngineers + = DAT_SkirmishDefinedData::instance.DAT_SiegeEngineTypeRequiredEngineers[iVar2]; + + break; + } + + iVar2 = iVar2 + 1; + + } while (iVar2 < 6); + + iVar2 = _requiredEngineers + iVar5; + + if (local_18 < iVar2) + break; + + iVar3 = iVar3 + 1; + + piVar4 = piVar4 + 1; + + iVar5 = iVar2; + + } while (iVar3 < 8); + + if (0 < iVar5) { + + for (; (_size != 0 && (0 < iVar5)); iVar5 = iVar5 + -1) { + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::popUnitFromTribe, DAT_TribesState::ptr)(_aiTribeID); + + _size = DAT_TribesState::instance.tribes[_aiTribeID].size; + } + + _counterTill8 = 0; + + /* + fixme: parameter reuse */ + + _siegeEngineType = (CommandBuildingType)playerID; + + do { + + if (*_siegeEngineUnitType < 1) { + + return; + } + + _counterTill6 = 0; + + do { + + if (*_siegeEngineUnitType + == DAT_SkirmishDefinedData::instance.DAT_SiegeEngineUnitType[_counterTill6]) { + + _requiredEngineers = DAT_SkirmishDefinedData::instance + .DAT_SiegeEngineTypeRequiredEngineers[_counterTill6]; + + _siegeEngineType = (CommandBuildingType)DAT_SkirmishDefinedData::instance + .DAT_SiegeEngineCommandBuildingTypes[_counterTill6]; + + break; + } + + _counterTill6 = _counterTill6 + 1; + + } while (_counterTill6 < 6); + + if (local_18 < _requiredEngineers) { + + return; + } + + local_18 = local_18 - _requiredEngineers; + + _selectionID2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToSelection, this)( + playerID, _requiredEngineers); + + if (_selectionID2 == 0) { + + return; + } + + _currentAttackWave = (short)DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; + + DAT_TribesState::instance.tribes[_selectionID2].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + + DAT_TribesState::instance.tribes[_selectionID2].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + + DAT_TribesState::instance.tribes[_selectionID2].attackWave = _currentAttackWave; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func:: + placeSiegeTentOrTunnelAtSuitableLocationAndAssignEngineers, + DAT_TroopValueState::ptr)( + _selectionID2, _siegeEngineType, (uint)((int)(60)), (UnitInstructionType)((int)(15))); + + _counterTill8 = _counterTill8 + 1; + + _siegeEngineUnitType = _siegeEngineUnitType + 1; + + } while (_counterTill8 < 8); + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp new file mode 100644 index 000000000..ff4f4d85b --- /dev/null +++ b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp @@ -0,0 +1,80 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/Tribes/AITribeType.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::Tribes::AITribeType; + using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::UnitInstructionType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF180 + void AICState ::useAITribe_0xe_toPlaceTunnels(int playerID) + + { + + int _aiTribeID; + + uint _unitID; + + int _tribeID; + + int _countdown; + + short _size; + + if (((DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) + && (_aiTribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xe], + _aiTribeID != 0)) + && (DAT_TribesState::instance.tribes[_aiTribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xe])) { + + _size = DAT_TribesState::instance.tribes[_aiTribeID].size; + + for (_countdown = (int)_size; (_size != 0 && (0 < _countdown)); _countdown = _countdown + -1) { + + _unitID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::popUnitFromTribe, DAT_TribesState::ptr)(_aiTribeID); + + _tribeID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + + DAT_TribesState::instance.tribes[_tribeID].attackWave + = (short)DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; + + DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_TUNNELERS; + + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x415; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + _unitID, _tribeID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func:: + placeSiegeTentOrTunnelAtSuitableLocationAndAssignEngineers, + DAT_TroopValueState::ptr)(_tribeID, OpenSHC::Commands::CBT_TUNNEL_ENTRANCE, (uint)((int)(50)), + (UnitInstructionType)((int)(21))); + + _size = DAT_TribesState::instance.tribes[_aiTribeID].size; + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp index 20ee5094d..2a2e2abcc 100644 --- a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp +++ b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp @@ -9,14 +9,10 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004C6D30 void AICState::wipeAICMemory() { - AICSpecification* destination = this->aics; - int iVar1 = 20; - do { + for (int i = 0; i < 20; i++) { MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( - 676, '\0', destination); - destination = destination + 1; - iVar1 = iVar1 + -1; - } while (iVar1 != 0); + 676, '\0', &this->aics[i]); + } } } } diff --git a/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp b/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp index 851e01542..975bfa838 100644 --- a/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp +++ b/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp @@ -10,11 +10,8 @@ namespace AI { BOOLEnum AICState::woodCuttersHutWhileNoWoodAvailable( undefined4 playerID, Commands::CommandBuildingType commandBuildingType) { - if ((commandBuildingType == Commands::CBT_WOODCUTTERSHUT) - && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0)) { - return TRUE; - } - return FALSE; + return ((commandBuildingType == Commands::CBT_WOODCUTTERSHUT) + && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0)); } } } From 9e5eb41d8fbd90f2f76e5648f3f95d92874409b2 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Mon, 27 Jul 2026 22:45:08 +0200 Subject: [PATCH 009/242] fit improvements --- .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 6 ++-- src/OpenSHC/AI/AICState/buyRequiredGoods.cpp | 30 ++----------------- .../generateSiegeCreationInformation.cpp | 11 +------ .../AICState/hasNoTroopsOrAllAreDiggers.cpp | 5 ++-- ...BuyWhenLowOnResourceAndSnoozeBuildings.cpp | 3 -- .../AI/AICState/playAnger1BikFromPlayer.cpp | 15 +++++----- .../AICState/playRequestHelpBikFromPlayer.cpp | 2 +- .../AI/AICState/setAttackPrimeInfo.cpp | 16 +++++----- 8 files changed, 25 insertions(+), 63 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp index 20b5496f0..55025b43a 100644 --- a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -43,9 +43,9 @@ namespace AI { if (((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0xaa])) - && ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0xb - && ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk < 0xb - && (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk < 0xb)))))) { + && ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk <= 0xa + && ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk <= 0xa + && (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk <= 0xa)))))) { if (((int)this->aics[_aiType - 1].OuterPatrolGroupsMove == 0) || (_buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)( playerID, _index), diff --git a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp index 27cb9b4c3..9a0ea9e4e 100644 --- a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp +++ b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp @@ -18,20 +18,6 @@ namespace AI { using OpenSHC::Game::Resources::ResourceTypeInt; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - Walks the AIC resource acquisition preference order (up to 25 entries in - DAT_ResourceAcquisitionPreferenceOrder) and attempts to buy the first resource for which the - player has a non-zero resourcesToAcquireArray entry and meets one of the spending conditions: - popularity is below the AIC minimum threshold (only checked for the first 4 entries), the AI is - nervous, or the canStartSpending flag is set. If the AI is nervous, entries 0-11 (non-weapon - resources) are skipped entirely so it only buys weapons. A special override fires first inside - the loop: if the building-destroy tracker is non-zero AND the player has fewer than 20 wood, the - resource type is forced to RT_WOOD regardless of the preference order. Before calling buyGoods() - the required gold is computed via getBuyPrice(); if the AI cannot afford the purchase it calls - requestGoods() from a teammate at double the desired amount instead. On a successful purchase - resourcesToAcquireArray for that resource is cleared and the function returns immediately, - buying at most one resource type per call. */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D39B0 void AICState ::buyRequiredGoods(int param_1) @@ -51,9 +37,6 @@ namespace AI { playerID = param_1; - /* - buying */ - AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; if (AVar1 == OpenSHC::AI::AIT_NULL) { @@ -61,33 +44,24 @@ namespace AI { return; } - /* - reused! playerID now means a counter */ - param_1 = 0; do { resourceType = DAT_SkirmishDefinedData::instance.DAT_ResourceAcqusitionPreferenceOrder[param_1]; - /* - If nervous, only buy from entry 12 onwards, which are weapons */ - - if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) || (12 < param_1)) { + if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0) || (0xb < param_1)) { if ((DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker != 0) && (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] < 20)) { - /* - if short on wood, buy wood! */ - resourceType = OpenSHC::Game::Resources::RT_WOOD; } amount = DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType]; if ((amount != 0) - && ((((param_1 < 4 + && ((((param_1 <= 3 && (DAT_GameState::instance.playerDataArray[playerID].popularity < *(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x18))) || (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker)) diff --git a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp index 581d2e863..bc11333dd 100644 --- a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp +++ b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp @@ -17,15 +17,6 @@ namespace AI { using OpenSHC::Map::Units::UnitType; using OpenSHC::Map::Units::UnitTypeShort; - /* - 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 0x004CC420 void AICState ::generateSiegeCreationInformation(int playerID, int buildingID, int unitID) @@ -73,7 +64,7 @@ namespace AI { _engineIndexUnk = 0; while ((_nextIndex = _engineIndexUnk + 1, - *(int*)(playerID * 0x39f4 + iVar2 * 40 + 0x115eb14 + _engineIndexUnk * 4) < 1 + *(int*)(playerID * 0x39f4 + iVar2 * 40 + 0x115eb14 + _engineIndexUnk * 4) <= 0 || (buildingID != *(int*)(playerID * 0x39f4 + 0x115f494 + (_engineIndexUnk + _siegeIndex * 5) * 0x14)))) { diff --git a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp index d550e65f5..5862623d0 100644 --- a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp +++ b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp @@ -11,9 +11,10 @@ namespace AI { int _totalTroops; int _halfOfDiggingTroops; - int _totalMisc = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + // reversed order to match orig + int _totalMisc = DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops - + DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops; + + DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops; _halfOfDiggingTroops = 0; if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState == 6) { _totalMisc += DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops; diff --git a/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp index c9b015a83..dd0c5b813 100644 --- a/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp +++ b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp @@ -10,9 +10,6 @@ namespace AI { using OpenSHC::AI::AIType; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CBA50 void AICState ::planToBuyWhenLowOnResourceAndSnoozeBuildings(int playerID) diff --git a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp index d544ada7d..fed855c23 100644 --- a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp @@ -17,18 +17,17 @@ namespace AI { int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar2 != 0) { - int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] - != DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) - && (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID - == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { + int _playerTeam = DAT_GameState::instance.mapAndTime.playerTeams[playerID]; + int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + int _curPlayer = DAT_GameSynchronyState::instance.currentPlayerSlotID; + if ((_playerTeam != DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer]) + && (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID == _curPlayer)) { DWORD DVar3 = timeGetTime(); if ((INT_ARRAY_00eb0af0::instance[playerID] == 0) - || (599999 < DVar3 - INT_ARRAY_00eb0af0::instance[playerID])) { + || (DVar3 - INT_ARRAY_00eb0af0::instance[playerID] >= 0x927c0)) { INT_ARRAY_00eb0af0::instance[playerID] = DVar3; MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, - DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 5); + DAT_VideoBikQueue::ptr)(playerID, AVar1, 5); } } } diff --git a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp index fc2a1bac2..3be00819a 100644 --- a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp @@ -15,9 +15,9 @@ namespace AI { { int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - int iVar1 = DAT_GameSynchronyState::instance.currentPlayerSlotID; if ((iVar2 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 == 0)) { DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 = 0x30; + int iVar1 = DAT_GameSynchronyState::instance.currentPlayerSlotID; if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[iVar1]) && (DAT_GameState::instance.playerDataArray[iVar1].lordKilledByPlayerID == 0)) { diff --git a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp index 0689b2419..7910e23a0 100644 --- a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp +++ b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp @@ -12,16 +12,16 @@ namespace AI { void AICState::setAttackPrimeInfo(int playerID, int attackedPlayerID) { int _tile = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile; - DAT_TroopValueState::instance.attackInfo.startCon - = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; - DAT_TroopValueState::instance.attackInfo.startZone = (int)(char)DAT_TileMapState::instance.AIZoneLayer[_tile]; - DAT_TroopValueState::instance.attackInfo.zoneSize - = DAT_PathFindingState::instance - .zoneSizesArray[(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]]; + int _zone = (int)(char)DAT_TileMapState::instance.AIZoneLayer[_tile]; + int _pathCon = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; + int _zoneSize = DAT_PathFindingState::instance.zoneSizesArray[_pathCon]; + DAT_TroopValueState::instance.attackInfo.startCon = _pathCon; + int _attackedTile = DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry; + DAT_TroopValueState::instance.attackInfo.startZone = _zone; + DAT_TroopValueState::instance.attackInfo.zoneSize = _zoneSize; DAT_TroopValueState::instance.attackInfo.unknownOne_0x20f90 = 1; DAT_TroopValueState::instance.attackInfo.keepCon - = (int)(short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry]; + = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_attackedTile]; } } } From 8b73c02022fbea699d1bc6d9cbb1012d0265ff7f Mon Sep 17 00:00:00 2001 From: sourcehold Date: Tue, 28 Jul 2026 22:31:19 +0200 Subject: [PATCH 010/242] better or worse --- .../addUnitToSmallestBehaviourTypeTribe.cpp | 21 +- .../AI/AICState/aiCreateSiegeUnits.cpp | 584 ++++----------- .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 20 +- .../AI/AICState/aiGiveRaidInstructions.cpp | 401 ++++------- src/OpenSHC/AI/AICState/aiRecruitUnits.cpp | 583 +++++---------- .../AI/AICState/aiRequiresExtraOxtethers.cpp | 86 +-- ...iShouldAttackOrWaitForTeamCoordination.cpp | 115 ++- src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp | 15 +- .../AI/AICState/aiUpdateTaxesAndRations.cpp | 148 ++-- ...mBuildingIDFromPlayersArrayOfBuildings.cpp | 89 +-- .../clearPlayerDataInformationChunk.cpp | 30 +- .../AI/AICState/computeNervousness.cpp | 56 +- .../AICState/decideOnTribeAttackLocation.cpp | 206 ++---- .../AICState/destroyAnyBuildingInCategory.cpp | 121 ++-- .../AI/AICState/destroyBuildingIfNoWorker.cpp | 45 +- src/OpenSHC/AI/AICState/destroyHouse.cpp | 41 +- ...ndAttackTribePositionAndPathToDefenses.cpp | 110 +-- .../AI/AICState/getDefensiveTribeForUnit.cpp | 28 +- .../AI/AICState/getSmallestPatrolTribe.cpp | 69 +- .../AICState/giveMoveCommandToSortieUnits.cpp | 68 +- .../AI/AICState/giveSomeRaidCommand.cpp | 37 +- .../AICState/hasNoTroopsOrAllAreDiggers.cpp | 15 +- .../AI/AICState/hasNotEnoughSupplies.cpp | 30 +- .../AI/AICState/instructTribe166ToMove.cpp | 73 +- .../processAttForceRallyPercentage.cpp | 88 +-- .../AI/AICState/selectAttackTarget.cpp | 203 ++---- src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 94 +-- .../AICState/sendTribeToAIVLocationSlot.cpp | 80 +-- ...TargetForTribeBasedOnTargetChoiceLogic.cpp | 172 ++--- .../AICState/setupWorkshopProductionType.cpp | 120 +--- .../AICState/shouldDestroyWoodCutterUnk.cpp | 20 +- .../AI/AICState/shouldNotBeBuildingHovel.cpp | 32 +- ...rketArmoryGranaryBarracksMercenarypost.cpp | 19 +- .../AI/AICState/smallestTribeOfUnitType.cpp | 6 +- .../AI/AICState/unitIDIsRangedOrArmored.cpp | 14 +- src/OpenSHC/AI/AICState/updateAIBehaviour.cpp | 198 ++---- .../AI/AICState/updateAIPlayerState.cpp | 664 ++++++------------ .../AI/AICState/updateAIStrengthState.cpp | 567 +++------------ .../AI/AICState/updateTribeLocations.cpp | 23 +- 39 files changed, 1585 insertions(+), 3706 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp index fb1ce9974..402f0e208 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp @@ -24,25 +24,22 @@ namespace AI { int _smallestTribeOffset = 0; short _smallestTribeSize = 1000; dword _groupsCount; - switch (_tribeTypeOffset) { - case 0xf: + + if (_tribeTypeOffset == 0xf) { _groupsCount = this->aics[AVar1 - 1].AttUnitPatrolGroupsCount; - break; - default: - goto switchD_004ccd78_caseD_10; - case 0xba: + } else if (_tribeTypeOffset == 0xba) { _groupsCount = this->aics[AVar1 - 1].AttUnitBackupGroupsCount; - break; - case 0xbe: + } else if (_tribeTypeOffset == 0xbe) { _groupsCount = this->aics[AVar1 - 1].AttUnitSiegeDefGroupsCount; - break; - case 0xc0: + } else if (_tribeTypeOffset == 0xc0) { _groupsCount = this->aics[AVar1 - 1].AttMainGroupsCount; + } else { + _groupsCount = 1; } + int _selectedTribe; int _selectedSlot; - if (((int)_groupsCount < 1) || (_groupsCount == 1)) { - switchD_004ccd78_caseD_10: + if ((int)_groupsCount < 1 || _groupsCount == 1) { int _tribeID_groupsCount1 = (int)DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_tribeTypeOffset]; if ((_tribeID_groupsCount1 != 0) diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index ec0e19d76..704837eaf 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -38,477 +38,167 @@ namespace AI { using OpenSHC::Map::Units::UnitType; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D2000 void AICState ::aiCreateSiegeUnits(int playerID) - { - - int _existingBuildingID; - - int _spawnedUnit; - - int _requiredEngineerCount; - - int _remainingRequiredEngineers; - - int _tribeID; - - int _targetUnitID; - - int _area; - - int _engineersTribe; - - int _aicOffset; - - int _y; - - int _slotIndex; - - int _nextSlotIndex; - - int _tile; - - int _mappingOffset; - - int _incrementsBy5; - - int _siegeInfoIndex; - - int _tribeSize; - - int _requiredGold; - - int _engineersGuildID; - - int _newUID; - - int _newBuildingID; - - int* _pGold; - - int _engineIndex; - - int _uid; - - int _unitID; - - int _location; - - AITypeInt _aiType; - - BuildingTypeShort _existingBuildingType; - + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == OpenSHC::AI::AIT_NULL) + return; + + int _engineersGuildID = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + if (!((0 < _engineersGuildID) + && (DAT_BuildingsState::instance.buildings[_engineersGuildID].buildingType + == OpenSHC::Map::Buildings::BT_ENGINEERSGUILD)) + || DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) + return; + + int _siegeInfoIndex = 0; + int _incrementsBy5 = 0; + int _mappingOffset = 0; int* _pDelay; - UnitType _unitType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType != OpenSHC::AI::AIT_NULL) { - - _engineersGuildID = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + do { + UnitType _unitType = *(UnitType*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].unitType + _mappingOffset); + int _tribeSize = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + _mappingOffset)]; + int _slotIndex = 0; + int _nextSlotIndex; - if (((0 < _engineersGuildID) - && (DAT_BuildingsState::instance.buildings[_engineersGuildID].buildingType - == OpenSHC::Map::Buildings::BT_ENGINEERSGUILD)) - && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) { - - _siegeInfoIndex = 0; - - _incrementsBy5 = 0; - - _mappingOffset = 0; + if (_tribeSize >= 4) + _tribeSize = 3; + if (0 < _tribeSize) { do { + _nextSlotIndex = _slotIndex + 1; + int _location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + _mappingOffset)][_slotIndex]; + + if (0 < _location) { + int _existingBuildingID = (int)(short)DAT_TileMapState::instance.BuildingLayer[_location]; + int _engineIndex = _incrementsBy5 + _slotIndex; + int _unitID = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID; + int _uid = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid; + int _tile = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID; + + if ((_unitID == 0) || (DAT_UnitsState::instance.units[_unitID].uid == _uid)) { + if ((_tile == 0) || (DAT_BuildingsState::instance.buildings[_tile].uid == _uid)) { + if (_unitID == 0) { + if (_tile == 0) { + bool _doPlace = false; + if (_existingBuildingID == 0) { + if (0x1f < _mappingOffset) + _doPlace = true; + } else if ((_mappingOffset < 0x20)) { + BuildingTypeShort _existingBuildingType = DAT_BuildingsState::instance.buildings[_existingBuildingID].buildingType; + if (_existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER4 || _existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER5) + _doPlace = true; + } else { + _doPlace = true; + } - _unitType - = *(UnitType*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].unitType - + _mappingOffset); - - _tribeSize = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*( - int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot - + _mappingOffset)]; - - _slotIndex = 0; - - if (_tribeSize < 4) { - - if (0 < _tribeSize) - goto LAB_004d20c0; - - } - - else { - - _tribeSize = 3; - - LAB_004d20c0: - do { - - _nextSlotIndex = _slotIndex + 1; - - _location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[*( - int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot - + _mappingOffset)][_slotIndex]; - - if (0 < _location) { - - _existingBuildingID = (int)(short)DAT_TileMapState::instance.BuildingLayer[_location]; - - _engineIndex = _incrementsBy5 + _slotIndex; - - _unitID = DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unitID; - - _uid = DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .uid; - - _tile = DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .buildingID; - - if ((_unitID == 0) || (DAT_UnitsState::instance.units[_unitID].uid == _uid)) { - - if ((_tile == 0) || (DAT_BuildingsState::instance.buildings[_tile].uid == _uid)) { - - if (_unitID == 0) { - - if (_tile == 0) { - - if (_existingBuildingID == 0) { - - if (0x1f < _mappingOffset) - goto LAB_004d21d4; - - } - - else if ((_mappingOffset < 0x20) - && ((_existingBuildingType - = DAT_BuildingsState::instance.buildings[_existingBuildingID] - .buildingType, - _existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER4 - || (_existingBuildingType - == OpenSHC::Map::Buildings::BT_TOWER5)))) { - - LAB_004d21d4: - _requiredGold - = DAT_BuildingsState::instance - .buildingCosts[*( - int*)((int)&DAT_SkirmishDefinedData::instance - .DAT_SiegeEngineMetaInfoArray[0] - .buildingType - + _mappingOffset)] - .requiredGold; - - _aicOffset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - - /* - defSiegeEngineGoldThreshold */ - - /* - defSiegeEngineBuildDelay */ - - if ((_requiredGold - <= DAT_GameState::instance.playerDataArray[playerID] - .currentResources[0xf] - + *(int*)((int)this + _aicOffset + 0x118)) - && (_pDelay = &DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay, - *_pDelay = *_pDelay + 1, - *(int*)((int)this + _aicOffset + 0x11c) - <= DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay)) { - - _y = (int)DAT_ViewportRenderState::instance - .DAT_TileTranslationMatrix_YComponent[_location]; - - _tile = _location - - DAT_ViewportRenderState::instance.translationMatrix[_y] - .addXgetTile; - - if (_siegeInfoIndex < 2) { - - _spawnedUnit = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::spawnUnit, - DAT_UnitsState::ptr)(playerID, playerID, _tile * 8 + 4, - _y * 8 + 4, - (int)((int)(DAT_BuildingsState::instance - .buildings[_existingBuildingID] - .terrainHeightUnk)), - _unitType); - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .unitID = _spawnedUnit; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .uid = DAT_UnitsState::instance.units[_spawnedUnit].uid; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .buildingID = 0; - - MACRO_CALL_MEMBER( - OpenSHC::Map::Buildings::BuildingsState_Func:: - processPlacementResourceLossForBuildingType, - DAT_BuildingsState::ptr)(playerID, - (BuildingType)((int)(DAT_SkirmishDefinedData::instance - .DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex] - .buildingType)), - 0); - - } - - else { - - MACRO_CALL_MEMBER( - OpenSHC::Map::TileMapState_Func::placeBuilding, - DAT_TileMapState::ptr)(playerID, _tile, _y, - (CommandBuildingType)((int)((uint)(ushort)(short) - DAT_SkirmishDefinedData::instance - .DAT_SiegeEngineMetaInfoArray - [_siegeInfoIndex] - .commandBuildingType)), - 3, 0xf); - - if (DAT_TileMapState::instance.buildingPlacementFail - == FALSE) { - - _pGold - = DAT_GameState::instance.playerDataArray[playerID] - .currentResources - + 0xf; - - *_pGold = *_pGold - _requiredGold; - - _newBuildingID - = DAT_TileMapState::instance.DAT_PlacedBuildingID; - - _newUID = DAT_BuildingsState::instance - .buildings[DAT_TileMapState::instance - .DAT_PlacedBuildingID] - .uid; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex] - [_slotIndex] - .unitID = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex] - [_slotIndex] - .uid = _newUID; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex] - [_slotIndex] - .buildingID = _newBuildingID; - } - } - - /* - delay = 0 */ - - *(undefined4*)(playerID * 0x39f4 + 0x115f48c + _slotIndex * 20 - + _siegeInfoIndex * 100) = 0; - - return; + if (_doPlace) { + int _requiredGold = DAT_BuildingsState::instance.buildingCosts[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].buildingType + _mappingOffset)].requiredGold; + int _aicOffset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + _pDelay = &DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay; + *_pDelay = *_pDelay + 1; + if ((_requiredGold <= DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] + *(int*)((int)this + _aicOffset + 0x118)) + && (*(int*)((int)this + _aicOffset + 0x11c) <= DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay)) { + int _y = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_location]; + int _placeTile = _location - DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + if (_siegeInfoIndex < 2) { + int _spawnedUnit = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::spawnUnit, DAT_UnitsState::ptr)(playerID, playerID, _placeTile * 8 + 4, _y * 8 + 4, (int)((int)(DAT_BuildingsState::instance.buildings[_existingBuildingID].terrainHeightUnk)), _unitType); + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].unitID = _spawnedUnit; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].uid = DAT_UnitsState::instance.units[_spawnedUnit].uid; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].buildingID = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processPlacementResourceLossForBuildingType, DAT_BuildingsState::ptr)(playerID, (BuildingType)((int)(DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex].buildingType)), 0); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID, _placeTile, _y, (CommandBuildingType)((int)((uint)(ushort)(short)DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex].commandBuildingType)), 3, 0xf); + if (DAT_TileMapState::instance.buildingPlacementFail == FALSE) { + int* _pGold = DAT_GameState::instance.playerDataArray[playerID].currentResources + 0xf; + *_pGold = *_pGold - _requiredGold; + int _newBuildingID = DAT_TileMapState::instance.DAT_PlacedBuildingID; + int _newUID = DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.DAT_PlacedBuildingID].uid; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].uid = _newUID; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].buildingID = _newBuildingID; } } - + *(undefined4*)(playerID * 0x39f4 + 0x115f48c + _slotIndex * 20 + _siegeInfoIndex * 100) = 0; + return; } - - else { - - LAB_004d22d3: - _requiredEngineerCount - = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: - getRequiredEngineerCountForSiegeBuilding, - DAT_BuildingsState::ptr)(_tile); - - if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount - != _requiredEngineerCount) { - - if (_requiredEngineerCount - <= DAT_GameState::instance.playerDataArray[playerID] - .engineerCountRelated) { - - _engineersTribe = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func:: - assignRequiredIdleEngineersToNewTribe, - this)(playerID, _requiredEngineerCount); - - DAT_TribesState::instance.tribes[_engineersTribe].tribeType - = OpenSHC::AI::Tribes::AITT_ENGINEERS; - - DAT_TribesState::instance.tribes[_engineersTribe] - .tribeBehaviorType = OpenSHC::Map::Units:: - STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func:: - giveTribeAnInstruction, - DAT_TribesState::ptr)(_engineersTribe, - OpenSHC::Map::Units:: - UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, - _tile, DAT_BuildingsState::instance.buildings[_tile].uid, - 0); - - return; - } - - DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired - = TRUE; - } + } + } else { + int _requiredEngineerCount = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, DAT_BuildingsState::ptr)(_tile); + if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount != _requiredEngineerCount) { + if (_requiredEngineerCount <= DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { + int _engineersTribe = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _requiredEngineerCount); + DAT_TribesState::instance.tribes[_engineersTribe].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_engineersTribe].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(_engineersTribe, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); + return; } - + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; } - - else { - - if (_tile != 0) - goto LAB_004d22d3; - - _remainingRequiredEngineers = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, - DAT_UnitsState::ptr)(_unitID); - - if (0 < _remainingRequiredEngineers) { - - if (DAT_GameState::instance.playerDataArray[playerID] - .engineerCountRelated - < _remainingRequiredEngineers) { - - DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired - = TRUE; - - } - - else { - - _tribeID - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func:: - assignRequiredIdleEngineersToNewTribe, - this)(playerID, _remainingRequiredEngineers); - - _targetUnitID = (int)DAT_TribesState::instance.tribes[_tribeID] - .selectionTargetUnitID; - - if ((_targetUnitID != 0) - && (_area = MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func:: - calculateCanPlayerUnitsNavigateToAreaFromArea, - DAT_PathFindingState::ptr)(playerID, - (dword)((int)((int)(short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_UnitsState::instance - .units[_unitID] - .tile])), - (dword)((int)((int)(short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_UnitsState::instance - .units[_targetUnitID] - .tile])), - 0), - _area != 0)) { - - DAT_TribesState::instance.tribes[_tribeID].tribeType - = OpenSHC::AI::Tribes::AITT_ENGINEERS; - - DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType - = OpenSHC::Map::Units::STBT_0x41c; - - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, - DAT_UnitsState::ptr)(_tribeID, - OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, _unitID, - DAT_UnitsState::instance.units[_unitID].uid, 0); - - return; - } + } + } else { + if (_tile != 0) { + int _requiredEngineerCount2 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, DAT_BuildingsState::ptr)(_tile); + if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount != _requiredEngineerCount2) { + if (_requiredEngineerCount2 <= DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { + int _engineersTribe2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _requiredEngineerCount2); + DAT_TribesState::instance.tribes[_engineersTribe2].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_engineersTribe2].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(_engineersTribe2, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); + return; + } + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; + } + } else { + int _remainingRequiredEngineers = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, DAT_UnitsState::ptr)(_unitID); + if (0 < _remainingRequiredEngineers) { + if (DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated < _remainingRequiredEngineers) { + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; + } else { + int _tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _remainingRequiredEngineers); + int _targetUnitID = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; + if ((_targetUnitID != 0) + && (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)(playerID, + (dword)((int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[_unitID].tile])), + (dword)((int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[_targetUnitID].tile])), + 0) != 0)) { + DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x41c; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(_tribeID, OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, _unitID, DAT_UnitsState::instance.units[_unitID].uid, 0); + return; } } } - } - - else { - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unitID = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .uid = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unknown = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .buildingID = 0; - } - - } - - else { - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unitID = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .uid = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unknown = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .buildingID = 0; } + } else { + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unknown = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID = 0; } - - _slotIndex = _nextSlotIndex; - - } while (_nextSlotIndex < _tribeSize); + } else { + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unknown = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID = 0; + } } - _siegeInfoIndex = _siegeInfoIndex + 1; - - _incrementsBy5 = _incrementsBy5 + 5; - - _mappingOffset = _mappingOffset + 16; - - if (64 < _mappingOffset) { - - return; - } - - } while (true); + _slotIndex = _nextSlotIndex; + } while (_nextSlotIndex < _tribeSize); } - } - return; + _siegeInfoIndex = _siegeInfoIndex + 1; + _incrementsBy5 = _incrementsBy5 + 5; + _mappingOffset = _mappingOffset + 16; + if (64 < _mappingOffset) + return; + } while (true); } - } } diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp index 55025b43a..a48ad6d5f 100644 --- a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -46,19 +46,22 @@ namespace AI { && ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk <= 0xa && ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk <= 0xa && (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk <= 0xa)))))) { + bool _hasTarget = true; if (((int)this->aics[_aiType - 1].OuterPatrolGroupsMove == 0) || (_buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)( playerID, _index), _buildingID == 0)) { _buildingID2 = MACRO_CALL_MEMBER( AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); - if (_buildingID2 == 0) - goto LAB_004d2a44; - _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID2] - .buildingEntryY] - .addXgetTile; + if (_buildingID2 == 0) { + _hasTarget = false; + } else { + _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID2] + .buildingEntryY] + .addXgetTile; + } } else { _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + DAT_ViewportRenderState::instance @@ -66,7 +69,7 @@ namespace AI { .buildingEntryY] .addXgetTile; } - if (_tile != 0) { + if (_hasTarget && _tile != 0) { sVar2 = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; iVar3 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; _canNavigate = MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( @@ -79,7 +82,6 @@ namespace AI { } } } - LAB_004d2a44: _index = _index + 1; psVar4 = psVar4 + 1; } while (_index < _count); diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp index 3f67ced06..32b7b3685 100644 --- a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -20,287 +20,196 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D2A70 void AICState ::aiGiveRaidInstructions(int playerID) - { + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == 0) + return; - int* piVar1; - - short sVar2; - - int iVar3; - - int _isAlive; - - int _buildingID_2; - - int _buildingID; - - int iVar4; - - int _buildingTile; - - BOOLEnum BVar5; - - int _tribeID3; - - BOOLEnum _indexTo6; - - short* _ptrTribeID3; - - int _aiType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType != 0) { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter; - - *piVar1 = *piVar1 + 1; - - /* - AIC: RaidRetargetDelay */ - - _indexTo6 = FALSE; - - if (*(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x1f0) - <= DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter) { - - DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter = 0; - } - - if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk == 0) { - - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; - - } - - else { - - iVar4 = DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown; - - if (0 < iVar4) { - - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown - = iVar4 + -1; - } - } - - _ptrTribeID3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xb4; - - do { - - _tribeID3 = (int)*_ptrTribeID3; - - DAT_TribesState::instance.tribes[_tribeID3].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - if ((_tribeID3 != 0) - && (DAT_TribesState::instance.tribes[_tribeID3].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_indexTo6 + 0xb4])) { - - if ((DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2) - && (_isAlive = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), - _isAlive != 0)) { - - if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) { - - _buildingID_2 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( - DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk, - (undefined4)((int)(_indexTo6))); - - if (_buildingID_2 == 0) { - - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); - - LAB_004d2d6b: - if (_buildingID != 0) - goto LAB_004d2d6f; - - } - - else { - - LAB_004d2c00: - _buildingTile - = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] - .buildingEntryY] - .addXgetTile; - - LAB_004d2d8d: - if (_buildingTile != 0) { - - sVar2 = DAT_ViewportRenderState::instance - .DAT_TileTranslationMatrix_YComponent[_buildingTile]; - - iVar4 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; - - BVar5 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( - _tribeID3, _buildingTile); - - if (BVar5 == FALSE) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID3, playerID); + int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter; + *piVar1 = *piVar1 + 1; - } + BOOLEnum _indexTo6 = FALSE; - else { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, - DAT_TribesState::ptr)(_tribeID3, (uint)((int)(_buildingTile - iVar4)), - (uint)((int)((int)sVar2)), 0); - } - } - } - } - - } - - else if ((DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown - == 0) - && (iVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, - this)(_aiType + -1, playerID), - DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk < iVar4)) { + if (*(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x1f0) + <= DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter) { + DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter = 0; + } - if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) - && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, TRUE), - BVar5 == FALSE)) { + if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk == 0) { + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; + } else { + int iVar4 = DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown; + if (0 < iVar4) + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = iVar4 + -1; + } + // Helper: do the movement command given a tile + // (was shared LAB_004d2d8d block) + #define DO_MOVE_TO_TILE(_tile, _tribeID3) \ + do { \ + if ((_tile) != 0) { \ + short sVar2_ = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[(_tile)]; \ + int iVar4_ = DAT_ViewportRenderState::instance.translationMatrix[sVar2_].addXgetTile; \ + BOOLEnum BVar5_ = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)((_tribeID3), (_tile)); \ + if (BVar5_ == FALSE) { \ + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)((_tribeID3), playerID); \ + } else { \ + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)((_tribeID3), (uint)((int)((_tile) - iVar4_)), (uint)((int)((int)sVar2_)), 0); \ + } \ + } \ + } while(0) + + short* _ptrTribeID3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xb4; + + do { + int _tribeID3 = (int)*_ptrTribeID3; + DAT_TribesState::instance.tribes[_tribeID3].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + if ((_tribeID3 != 0) + && (DAT_TribesState::instance.tribes[_tribeID3].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_indexTo6 + 0xb4])) { + + int iVar4; + BOOLEnum BVar5; + int _buildingID, _buildingID_2, _buildingTile; + + if ((DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2) + && (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) != 0)) { + + if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) { + _buildingID_2 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk, + (undefined4)((int)(_indexTo6))); + if (_buildingID_2 == 0) { _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( - playerID, (undefined4)((int)(_indexTo6))); - + OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); if (_buildingID != 0) { - - LAB_004d2d6f: _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + DAT_ViewportRenderState::instance .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] .buildingEntryY] .addXgetTile; - - goto LAB_004d2d8d; + DO_MOVE_TO_TILE(_buildingTile, _tribeID3); } + } else { + _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] + .buildingEntryY] + .addXgetTile; + DO_MOVE_TO_TILE(_buildingTile, _tribeID3); + } + } + } else if ((DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown == 0) + && (iVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, + this)(_aiType + -1, playerID), + DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk < iVar4)) { + + if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) + && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, TRUE), + BVar5 == FALSE)) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + playerID, (undefined4)((int)(_indexTo6))); + + if (_buildingID != 0) { + _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] + .buildingEntryY] + .addXgetTile; + DO_MOVE_TO_TILE(_buildingTile, _tribeID3); + } else { _buildingID_2 = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); - - if (_buildingID_2 != 0) - goto LAB_004d2c00; + if (_buildingID_2 != 0) { + _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] + .buildingEntryY] + .addXgetTile; + DO_MOVE_TO_TILE(_buildingTile, _tribeID3); + } } - } - else if ((DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb6) - || (DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb5)) { + } else if ((DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb6) + || (DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb5)) { - if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) - && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, FALSE), - BVar5 == FALSE)) { - - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk, - (undefined4)((int)(_indexTo6))); - - if (_buildingID == 0) { + if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) + && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, FALSE), + BVar5 == FALSE)) { - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, - this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk, + (undefined4)((int)(_indexTo6))); - goto LAB_004d2d6b; - } - - goto LAB_004d2d6f; + if (_buildingID == 0) { + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, + this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); } + if (_buildingID != 0) { + _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] + .buildingEntryY] + .addXgetTile; + DO_MOVE_TO_TILE(_buildingTile, _tribeID3); + } } - else { - - BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, FALSE); - - if (BVar5 == FALSE) { - - iVar4 = (int)DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID; - - if ((((iVar4 == 0) - || (DAT_BuildingsState::instance.buildings[iVar4].uid - != DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID)) - || (DAT_BuildingsState::instance.buildings[iVar4].fireDuration != 0)) - || (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, TRUE), - BVar5 == FALSE)) { - - iVar4 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, - this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); - - if (iVar4 == 0) { - - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .someTotalDefenseTroopsRelatedCountdown = 0; - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, - DAT_UnitsState::ptr)(_tribeID3, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, iVar4, - DAT_BuildingsState::instance.buildings[iVar4].uid, 0); - - iVar3 = DAT_BuildingsState::instance.buildings[iVar4].uid; - - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = (short)iVar4; - - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID = iVar3; - - DAT_GameState::instance.playerDataArray[playerID] - .someTotalDefenseTroopsRelatedCountdown = 100; - } - - } - - else { - - if (DAT_GameState::instance.mapAndTime.yearChanged != 0) { - - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; - } - - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown - = 100; + } else { + BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, FALSE); + if (BVar5 == FALSE) { + iVar4 = (int)DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID; + if ((((iVar4 == 0) + || (DAT_BuildingsState::instance.buildings[iVar4].uid + != DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID)) + || (DAT_BuildingsState::instance.buildings[iVar4].fireDuration != 0)) + || (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, TRUE), + BVar5 == FALSE)) { + iVar4 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, + this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + if (iVar4 == 0) { + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, + DAT_UnitsState::ptr)(_tribeID3, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, iVar4, + DAT_BuildingsState::instance.buildings[iVar4].uid, 0); + int iVar3 = DAT_BuildingsState::instance.buildings[iVar4].uid; + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = (short)iVar4; + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID = iVar3; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 100; } + } else { + if (DAT_GameState::instance.mapAndTime.yearChanged != 0) + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 100; } } } + } - _ptrTribeID3 = _ptrTribeID3 + 1; - - _indexTo6 = _indexTo6 + TRUE; - - } while ((int)_indexTo6 < 6); - } + _ptrTribeID3 = _ptrTribeID3 + 1; + _indexTo6 = _indexTo6 + TRUE; + } while ((int)_indexTo6 < 6); - return; + #undef DO_MOVE_TO_TILE } - } } diff --git a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp index 50877b900..22307f6a7 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp @@ -37,451 +37,202 @@ namespace AI { using OpenSHC::Map::Units::UnitType; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D3AE0 void AICState ::aiRecruitUnits(int playerID) - { - - int* piVar1; - - AIRecruitUnitChoiceInt AVar2; - - bool bVar3; - - int iVar4; - - int iVar5; - + int _playerID2 = playerID; + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + UnitType _unitType = ((UnitType)0); + AICState* _pAICState = this; int _tribeID_defDiggingUnitMax; - int _unitID; - - UnitType _unitType; - - int iVar6; - - AICState* _pAICState; - - int local_8; - - int _aicRecruitInterval; - - int _nervousActionTracker; - - int _buildingID; - - int _unitChoiceIndex; - - AIRecruitUnitChoiceInt _unitTypeChoice; - - int _defTotal; - - AITypeInt _aiType; - - int _playerID2; - - bool _recruitDefDiggingUnit; - - _playerID2 = playerID; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - _unitType = ((UnitType)0); - - _pAICState = this; - - if (_aiType != OpenSHC::AI::AIT_NULL) { - - bVar3 = false; - - _recruitDefDiggingUnit = false; - - iVar6 = _aiType + ~OpenSHC::AI::AIT_NULL; - - if (((DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) - && (DAT_GameCore::instance.isSkirmishTrail == TRUE)) - && (DAT_GameCore::instance.currentTrailType == OpenSHC::Game::TT_EXTREME)) { - - bVar3 = true; - } - - iVar4 = iVar6 * 0xa9; - - _aicRecruitInterval = *(int*)((int)this - + (DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + iVar4) * 4 + 0x164); - - local_8 = -(uint)(_aicRecruitInterval != 0) + 2; - - if (bVar3) { - - local_8 = -(uint)(_aicRecruitInterval != 0) + 3; - } - - _nervousActionTracker = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; - - if (_nervousActionTracker < 1) { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker; + if (_aiType == OpenSHC::AI::AIT_NULL) + return; + + bool bVar3 = false; + bool _recruitDefDiggingUnit = false; + int iVar6 = _aiType + ~OpenSHC::AI::AIT_NULL; + + if (((DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) + && (DAT_GameCore::instance.isSkirmishTrail == TRUE)) + && (DAT_GameCore::instance.currentTrailType == OpenSHC::Game::TT_EXTREME)) + bVar3 = true; + + int iVar4 = iVar6 * 0xa9; + int _aicRecruitInterval = *(int*)((int)this + + (DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + iVar4) * 4 + 0x164); + int local_8 = -(uint)(_aicRecruitInterval != 0) + 2; + if (bVar3) + local_8 = -(uint)(_aicRecruitInterval != 0) + 3; + + int _nervousActionTracker = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + if (_nervousActionTracker < 1) { + int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker; + *piVar1 = *piVar1 + 1; + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker < _aicRecruitInterval) + return; + } else { + local_8 = 4; + } - *piVar1 = *piVar1 + 1; + int iVar5 = DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount; + DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker = 0; - if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker < _aicRecruitInterval) { + if ((0 < iVar5) && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) { + AIRecruitUnitChoiceInt AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState; + if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { + int _defTotal = *(int*)((int)this + iVar6 * 0x2a4 + 0x170); + if (bVar3) _defTotal = (_defTotal * 4) / 3; + if (0 < _nervousActionTracker) _defTotal = _defTotal * 4; + if (_defTotal <= DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk) return; - } - - } - - else { - - local_8 = 4; + } else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( + iVar6, playerID); + if (iVar5 <= DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk) + return; + } else if ((AVar2 == OpenSHC::AI::AIRUC_ATTACKING) + && (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState != 0)) + return; + + iVar6 = iVar6 * 0x2a4; + + if (((*(int*)((int)this + iVar6 + 0x15c) != 0) + && (iVar5 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, + DAT_TileMapState::ptr)(playerID), iVar5 != 0)) + && ((_tribeID_defDiggingUnitMax = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10], + _tribeID_defDiggingUnitMax == 0 + || ((DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10] + != DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].uid + || ((int)DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].size + < *(int*)((int)this + iVar6 + 0x15c))))))) { + _recruitDefDiggingUnit = true; } - iVar5 = DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount; - - DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker = 0; - - if ((0 < iVar5) && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) { - - AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState; + playerID = 0; + if (0 < local_8) { + do { + // If we should recruit a digging unit but RNG says no, fall through to normal recruit + if (_recruitDefDiggingUnit && ((byte)SEC_RNG::instance.currentNumber2 & 1) != 0) + _recruitDefDiggingUnit = false; - if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { - - _defTotal = *(int*)((int)this + iVar6 * 0x2a4 + 0x170); - - if (bVar3) { - - _defTotal = (_defTotal * 4) / 3; - } - - if (0 < _nervousActionTracker) { - - _defTotal = _defTotal * 4; + if (_recruitDefDiggingUnit) { + if (DAT_GameState::instance.playerDataArray[_playerID2].barracks.id == 0) { + if (DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id == 0) + return; + } + _unitType = *(UnitType*)((int)this + iVar6 + 0x160); + } else { + AIRecruitUnitChoiceInt _unitTypeChoice = + DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; + + if (_unitTypeChoice == OpenSHC::AI::AIRUC_DEFENSIVE) { + if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex) + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; + if (*(int*)((int)this + + (DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex + iVar4) + * 4 + 0x184) == 0) + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; + int _unitChoiceIndex = + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex; + _unitType = *(UnitType*)((int)this + (iVar4 + _unitChoiceIndex) * 4 + 0x184); + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = + _unitChoiceIndex + 1; + } else if (_unitTypeChoice == OpenSHC::AI::AIRUC_RAIDING) { + if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex) + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; + if (*(int*)((int)this + + (DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex + iVar4) + * 4 + 0x1ac) == 0) + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; + iVar5 = DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex; + _unitType = *(UnitType*)((int)this + (iVar4 + iVar5) * 4 + 0x1ac); + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = iVar5 + 1; + } else if (_unitTypeChoice == OpenSHC::AI::AIRUC_ATTACKING) { + _pAICState = (AICState*)MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::randomlySelectAttackUnitTypeToRecruit, this)(_playerID2); + _unitType = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::getUnitTypeForUnitBehaviourType, this)( + _playerID2, (AIUnitBehaviourType)((int)(_pAICState))); + } } - if (_defTotal <= DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk) { - + if (_unitType == ((UnitType)0)) return; - } - - } - - else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { - - iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( - iVar6, playerID); - - if (iVar5 <= DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk) { + int _buildingID; + if (_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; + else if (_unitType == OpenSHC::Map::Units::UT_E_LADDER) + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; + else if (_unitType == OpenSHC::Map::Units::UT_TUNNELER) + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].tunnelersGuild.id; + else if (_unitType == OpenSHC::Map::Units::UT_E_MONK) + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(_playerID2, OpenSHC::Map::Buildings::BT_CATHEDRAL); + else if ((int)_unitType < 0x46) + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].barracks.id; + else + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id; + + if (_buildingID == 0) return; - } - - } - - else if ((AVar2 == OpenSHC::AI::AIRUC_ATTACKING) - && (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState != 0)) { - - return; - } - - iVar6 = iVar6 * 0x2a4; - - /* - DefDiggingUnitMax */ - - /* - DefDiggingUnitMax */ - - if (((*(int*)((int)this + iVar6 + 0x15c) != 0) - && (iVar5 - = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, - DAT_TileMapState::ptr)(playerID), - iVar5 != 0)) - && ((_tribeID_defDiggingUnitMax - = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10], - _tribeID_defDiggingUnitMax == 0 - || ((DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10] - != DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].uid - || ((int)DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].size - < *(int*)((int)this + iVar6 + 0x15c))))))) { - - _recruitDefDiggingUnit = true; - } - - playerID = 0; - - if (0 < local_8) { - - do { - - if (_recruitDefDiggingUnit) { - - if (((byte)SEC_RNG::instance.currentNumber2 & 1) != 0) { - - _recruitDefDiggingUnit = false; - - goto LAB_004d3cc1; - } - - if (DAT_GameState::instance.playerDataArray[_playerID2].barracks.id == 0) { - - if (DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id == 0) { - - return; - } - - /* - DefDiggingUnit */ - - _unitType = *(UnitType*)((int)this + iVar6 + 0x160); - - } - - else { - - /* - DefDiggingUnit */ - - _unitType = *(UnitType*)((int)this + iVar6 + 0x160); - } - - } - - else { - - LAB_004d3cc1: - _unitTypeChoice - = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; - - if (_unitTypeChoice == OpenSHC::AI::AIRUC_DEFENSIVE) { - - if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex) { - - DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; - } - - /* - DefUnit 1 up to 8 */ - - if (*(int*)((int)this - + (DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex - + iVar4) - * 4 - + 0x184) - == 0) { - DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; - } - - _unitChoiceIndex - = DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex; - - /* - DefUnit 1 up to 8 */ - - _unitType = *(UnitType*)((int)this + (iVar4 + _unitChoiceIndex) * 4 + 0x184); - - DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex - = _unitChoiceIndex + 1; - - } - - else if (_unitTypeChoice == OpenSHC::AI::AIRUC_RAIDING) { - - if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex) { - - DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; - } - - if (*(int*)((int)this - + (DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex - + iVar4) - * 4 - + 0x1ac) - == 0) { - - DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; - } - - iVar5 = DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex; - - _unitType = *(UnitType*)((int)this + (iVar4 + iVar5) * 4 + 0x1ac); - - DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = iVar5 + 1; - - } - - else if (_unitTypeChoice == OpenSHC::AI::AIRUC_ATTACKING) { - - _pAICState = (AICState*)MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::randomlySelectAttackUnitTypeToRecruit, this)( - _playerID2); - - _unitType - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getUnitTypeForUnitBehaviourType, - this)(_playerID2, (AIUnitBehaviourType)((int)(_pAICState))); - } - } - - if (_unitType == ((UnitType)0)) { + int _unitID; + if (((_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) + || (_unitType == OpenSHC::Map::Units::UT_E_LADDER) + || (_unitType == OpenSHC::Map::Units::UT_TUNNELER)) + || ((_unitType == OpenSHC::Map::Units::UT_E_MONK || (0x45 < (int)_unitType)))) { + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); + } else { + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); + } + if (_unitID == 0) { + iVar6 = *(int*)((int)this + iVar6 + 0x9c); + if (iVar6 < 1) return; - } - - if (_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) { - - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; - - } - - else if (_unitType == OpenSHC::Map::Units::UT_E_LADDER) { - - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; - - } - - else if (_unitType == OpenSHC::Map::Units::UT_TUNNELER) { - - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].tunnelersGuild.id; - - } - - else if (_unitType == OpenSHC::Map::Units::UT_E_MONK) { - - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, - DAT_BuildingsState::ptr)(_playerID2, OpenSHC::Map::Buildings::BT_CATHEDRAL); - - } - - else if ((int)_unitType < 0x46) { - - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].barracks.id; - - } - - else { - - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id; - } - - if (_buildingID == 0) { - + if (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason != 2) return; - } - - if ((((_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) - || (_unitType == OpenSHC::Map::Units::UT_E_LADDER)) - || (_unitType == OpenSHC::Map::Units::UT_TUNNELER)) - || ((_unitType == OpenSHC::Map::Units::UT_E_MONK || (0x45 < (int)_unitType)))) { - - _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, - DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); - - } - - else { - - _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, - DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); - } - - if (_unitID == 0) { - - /* - tradeAmountEquipment */ - - iVar6 = *(int*)((int)this + iVar6 + 0x9c); - - if (iVar6 < 1) { - - return; - } - - if (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason != 2) { - - return; - } - - if (DAT_GameState::instance.playerDataArray[_playerID2].aiNervousActionsTracker < 1) { - - DAT_GameState::instance.playerDataArray[_playerID2] - .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] - = iVar6; - - return; - } - + if (DAT_GameState::instance.playerDataArray[_playerID2].aiNervousActionsTracker < 1) { DAT_GameState::instance.playerDataArray[_playerID2] - .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = 5; - + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = iVar6; return; } + DAT_GameState::instance.playerDataArray[_playerID2] + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = 5; + return; + } - if (_recruitDefDiggingUnit) { - - /* - digging units? */ - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); - - } - - else { - - AVar2 = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; - - /* - 0 = defensive, 1 = raid, 2 = army */ - - if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { - - if (DAT_GameState::instance.playerDataArray[_playerID2].totalDefensiveTroopsUnk - < *(int*)((int)this + iVar6 + 0x180)) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignUnitToATribe, this)(_unitID); - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToSmallestPatrolTribe, this)( - _unitID); - } - - } - - else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignUnitToDefensiveTribe, this)( - _unitID); - - } - - else if (AVar2 == OpenSHC::AI::AIRUC_ATTACKING) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToItsTribe, this)( - _unitID, (int)((int)(_pAICState))); - } - } - - playerID = playerID + 1; - - if (local_8 <= playerID) { - - return; + if (_recruitDefDiggingUnit) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); + } else { + AVar2 = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; + if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { + if (DAT_GameState::instance.playerDataArray[_playerID2].totalDefensiveTroopsUnk + < *(int*)((int)this + iVar6 + 0x180)) + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignUnitToATribe, this)(_unitID); + else + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToSmallestPatrolTribe, this)(_unitID); + } else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignUnitToDefensiveTribe, this)(_unitID); + } else if (AVar2 == OpenSHC::AI::AIRUC_ATTACKING) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToItsTribe, this)( + _unitID, (int)((int)(_pAICState))); } + } - } while (true); - } + playerID = playerID + 1; + if (local_8 <= playerID) + return; + } while (true); } } - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp index a1c8bb331..8ccc1c4da 100644 --- a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp +++ b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp @@ -10,117 +10,72 @@ namespace AI { using OpenSHC::Map::Buildings::BuildingType; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CB3A0 undefined4 AICState ::aiRequiresExtraOxtethers(int playerID) { + int _playerID = playerID; - int* piVar1; - - int _buildingID; - - int _oxTetherCount; - - int _linkedTetherID; - - short* _linkedTetherIDs; - - int _linkedTetherCount; - - int _oxTetherLoopIndex; - - int _quarryID; - - int _stoneWaiting; - - int _playerID; - - _playerID = playerID; - - _buildingID + int _buildingID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_QUARRY); - _quarryID = 0; + // _stoneWaiting declared first so it gets lower stack slot + int _stoneWaiting = 0; + int _quarryID = 0; - /* - reuse of playerID!! */ - - playerID = 0; - - _oxTetherCount = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + int _oxTetherCount = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)(_playerID, OpenSHC::Map::Buildings::BT_OXTETHER, 1); - if (9 < _oxTetherCount) { - + if (_oxTetherCount >= 0xa) { return (undefined4)(0); } - piVar1 = &DAT_GameState::instance.playerDataArray[_playerID].highestLoadedQuarryUnk; + int* piVar1 = &DAT_GameState::instance.playerDataArray[_playerID].highestLoadedQuarryUnk; *piVar1 = 0; if (_buildingID != 0) { do { - - _stoneWaiting + int _localStone = DAT_BuildingsState::instance .buildings[(short)DAT_BuildingsState::instance.buildings[_buildingID].quarryStockpileID] .resourceStone; - _linkedTetherCount = 0; + int _linkedTetherCount = 0; - _linkedTetherIDs = DAT_BuildingsState::instance.buildings[_buildingID].quarryLinkedOxTethers; + short* _linkedTetherIDs = DAT_BuildingsState::instance.buildings[_buildingID].quarryLinkedOxTethers; - _oxTetherLoopIndex = 3; + int _oxTetherLoopIndex = 3; do { - - _linkedTetherID = (int)*_linkedTetherIDs; + int _linkedTetherID = (int)*_linkedTetherIDs; if (_linkedTetherID != 0) { - if ((DAT_BuildingsState::instance.buildings[_linkedTetherID].buildingType == OpenSHC::Map::Buildings::BT_OXTETHER) && (DAT_BuildingsState::instance.buildings[_linkedTetherID].oxtetherLinkedQuarryID == _buildingID)) { - _linkedTetherCount = _linkedTetherCount + 1; - - } - - else { - + } else { *_linkedTetherIDs = 0; } } _linkedTetherIDs = _linkedTetherIDs + 1; - _oxTetherLoopIndex = _oxTetherLoopIndex + -1; } while (_oxTetherLoopIndex != 0); - if (_linkedTetherCount < 1) { - + if (_linkedTetherCount <= 0) { *piVar1 = _buildingID; - return (undefined4)(1); } - /* - store the highest ratio of stone in quarry stockpile divided by linked ox - tethers */ - - if (playerID < _stoneWaiting / _linkedTetherCount) { - - playerID = _stoneWaiting / _linkedTetherCount; - + if (_stoneWaiting < _localStone / _linkedTetherCount) { _quarryID = _buildingID; + _stoneWaiting = _localStone / _linkedTetherCount; } _buildingID @@ -129,13 +84,8 @@ namespace AI { } while (_buildingID != 0); - /* - if the highest ratio is larger than 20, return true */ - - if (20 < playerID) { - + if (0x14 < _stoneWaiting) { *piVar1 = _quarryID; - return (undefined4)(1); } } diff --git a/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp index 173aa0643..1f3a4f198 100644 --- a/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp @@ -35,74 +35,71 @@ namespace AI { return FALSE; } - if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 1) { - return TRUE; - } - - int _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; - if (DAT_GameState::instance.playerDataArray[_attackedPlayerID].totalTroopValue < 100) { - DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 0; - } + if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk != 1) { + int _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + if (DAT_GameState::instance.playerDataArray[_attackedPlayerID].totalTroopValue < 100) { + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 0; + } - int _attForceBase = *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 500); - int _currentWaveStrength = DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; - int _totalAttack = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops - - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops; + int _attForceBase = *(int*)((int)this + (_aiType - 1) * 0x2a4 + 0x1f4); + int _currentWaveStrength = DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; + int _totalAttack = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops; - if (_totalAttack < _attForceBase + _currentWaveStrength) { - return FALSE; - } + if (_totalAttack < _attForceBase + _currentWaveStrength) { + return FALSE; + } - if (DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel == 0) { - return TRUE; - } + if (DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel == 0) { + return TRUE; + } - int _readyTeamMembers = 0; - int _unreadyTeamMembers = 0; - int _iPlayer = 1; - PlayerData* _pPlayerData = &DAT_GameState::instance.playerDataArray[1]; - - do { - if (_iPlayer != playerID) { - int _isAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_iPlayer); - if (_isAlive != 0) { - BOOLEnum _isAI = MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, - DAT_GameSynchronyState::ptr)(_iPlayer); - if (_isAI != FALSE) { - if (DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] - == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { - if (_pPlayerData->aiPlayerState != 0) { - return TRUE; - } - if (_pPlayerData->totalAttackTroops - _pPlayerData->totalAttackingEngineerTroops - < *(int*)((int)DAT_EntityState::instance.seagullArray + _pPlayerData->aiType * 0x2a4 - + 0x2664) - + _pPlayerData->currentWaveRandomAttackingStrength) { - _unreadyTeamMembers = _unreadyTeamMembers + 1; - } - else { - _readyTeamMembers = _readyTeamMembers + 1; + int _readyTeamMembers = 0; + int _unreadyTeamMembers = 0; + int _iPlayer = 1; + PlayerData* _pPlayerData = &DAT_GameState::instance.playerDataArray[1]; + + do { + if (_iPlayer != playerID) { + int _isAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_iPlayer); + if (_isAlive != 0) { + BOOLEnum _isAI = MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, + DAT_GameSynchronyState::ptr)(_iPlayer); + if (_isAI != FALSE) { + if (DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + if (_pPlayerData->aiPlayerState != 0) { + return TRUE; + } + if (_pPlayerData->totalAttackTroops - _pPlayerData->totalAttackingEngineerTroops + >= *(int*)((int)this + (_pPlayerData->aiType - 1) * 0x2a4 + 0x1f4) + + _pPlayerData->currentWaveRandomAttackingStrength) { + _readyTeamMembers = _readyTeamMembers + 1; + } + else { + _unreadyTeamMembers = _unreadyTeamMembers + 1; + } } } } } - } - _iPlayer = _iPlayer + 1; - _pPlayerData = _pPlayerData + 1; - } while (_iPlayer < 9); + _iPlayer = _iPlayer + 1; + _pPlayerData = _pPlayerData + 1; + } while (_iPlayer < 9); - if (_readyTeamMembers >= DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel) { - return TRUE; - } - if (_unreadyTeamMembers == 0) { - return TRUE; - } - DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience = - DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience + 1; - if (DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience <= 0x30 - || (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CAMPAIGN_MISSION)) { - return FALSE; + if (_readyTeamMembers >= DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel) { + return TRUE; + } + if (_unreadyTeamMembers == 0) { + return TRUE; + } + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience = + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience + 1; + if (DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience <= 0x30 + || (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CAMPAIGN_MISSION)) { + return FALSE; + } } return TRUE; diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp index 29132eb9c..8f0775778 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp @@ -11,22 +11,21 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB220 BOOLEnum AICState::aiShouldBuildFarm(int playerID) { - int const _playerID = playerID; - unsigned int aiType = DAT_GameState::instance.playerDataArray[_playerID].aiType; + unsigned int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (aiType == AITA_NULL) { - return aiType; // return 0 => return + return (BOOLEnum)aiType; } aiType -= 1; int const _farmCount - = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countFarms, DAT_BuildingsState::ptr)(_playerID, 1); + = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countFarms, DAT_BuildingsState::ptr)(playerID, 1); if (_farmCount <= 0) { return TRUE; } - if (_farmCount >= (int)this->aics[aiType].maxFarms) { - return FALSE; + if (_farmCount < (int)this->aics[aiType].maxFarms) { + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / _farmCount + >= (int)this->aics[aiType].populationPerFarm; } - return DAT_GameState::instance.playerDataArray[_playerID].currentPopulation / _farmCount - >= (int)this->aics[aiType].populationPerFarm; + return FALSE; } } } diff --git a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp index 8bf86d291..7bd2e0f18 100644 --- a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp +++ b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp @@ -11,147 +11,95 @@ namespace AI { using OpenSHC::AI::AITypeInt; // FUNCTION: STRONGHOLDCRUSADER 0x004CAEA0 - void AICState ::aiUpdateTaxesAndRations(int playerID) + void AICState::aiUpdateTaxesAndRations(int playerID) { - int _offset; - int _newTaxesVal; - int _newTaxes; - int _popularity; - int _currentTaxes; - int _taxesMin; - int _taxesMax; - int _peasants; - int _decision; - int _totalFood_2; - int _totalFood_1; - int _taxes; - AITypeInt _aiType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType == OpenSHC::AI::AIT_NULL) { + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == OpenSHC::AI::AIT_NULL) return; - } - _offset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + _aiType = _aiType - 1; + int const _popularity = DAT_GameState::instance.playerDataArray[playerID].popularity; - _popularity = DAT_GameState::instance.playerDataArray[playerID].popularity; - - // criticalPopularity - comparison order matches original: first jg sets decision=2 (critical) - if (*(int*)((int)this + _offset + 0x18) >= _popularity) { + if (_popularity <= (int)this->aics[_aiType].criticalPopularity) { DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 2; - } else if (*(int*)((int)this + _offset + 0x1c) < _popularity) { - // highestPopularity - if (*(int*)((int)this + _offset + 0x20) >= _popularity) { - DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 0; - } - } else { + } else if (_popularity <= (int)this->aics[_aiType].lowestPopularity) { DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 1; + } else if (_popularity >= (int)this->aics[_aiType].highestPopularity) { + DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 0; } - _decision = DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue; + int const _decision = DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue; if (_decision == 2) { - _totalFood_2 = DAT_GameState::instance.playerDataArray[playerID].totalFood; + int const _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 2; - - if (_totalFood_2 <= 0) { + if (_totalFood <= 0) { DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; - } else if (_totalFood_2 < 5) { + } else if (_totalFood <= 4) { DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; } else { - int _r = 0; - if (_totalFood_2 > 8) _r = 1; - DAT_GameState::instance.playerDataArray[playerID].rationsSetting = _r + 3; + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = (_totalFood > 8) + 3; } - - goto LAB_004cb010; - } - - if (_decision == 1) { - _currentTaxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; - _taxesMin = *(int*)((int)this + _offset + 0x24); - - if (_taxesMin < _currentTaxes) { + } else if (_decision == 1) { + int const _currentTaxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; + int const _taxesMin = (int)this->aics[_aiType].taxesMin; + if (_currentTaxes > _taxesMin) { DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _currentTaxes - 1; } else { DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxesMin; } - - _totalFood_1 = DAT_GameState::instance.playerDataArray[playerID].totalFood; - - if (_totalFood_1 <= 0) { + int const _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; + if (_totalFood <= 0) { DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; + } else if (_totalFood <= 10) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; } else { - if (_totalFood_1 <= 0xa) - goto LAB_004caff1; DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 3; } - } else { - if (_decision != 0) - goto LAB_004cb010; - - _taxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; - _taxesMax = *(int*)((int)this + _offset + 0x28); + int const _rationsMod = (int)this->aics[_aiType].doubleRationsFoodThreshold; + if (_rationsMod != 0 && _totalFood >= _rationsMod) + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; + } else if (_decision == 0) { + int const _taxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; + int const _taxesMax = (int)this->aics[_aiType].taxesMax; if (_taxes < _taxesMax) { - _peasants = DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants; - int _r2 = 0; - if (_peasants < 0xf) { - if (_peasants >= 0xa) _r2 = 1; - _newTaxesVal = _r2 + 4; - } else { + int const _peasants = DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants; + int _newTaxesVal; + if (_peasants >= 0xf) { _newTaxesVal = 6; + } else { + _newTaxesVal = (_peasants >= 0xa) + 4; } - if (DAT_GameState::instance.playerDataArray[playerID].storedPopularityPercent > _popularity) { - if (_taxes <= _newTaxesVal) - goto LAB_004cafcd; - _newTaxes = _taxes - 1; - } else { - _newTaxes = _taxes + 1; + if (!(DAT_GameState::instance.playerDataArray[playerID].storedPopularityPercent > _popularity)) { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxes + 1; + } else if (_taxes > _newTaxesVal) { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxes - 1; } - DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _newTaxes; } else { DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxesMax; } - LAB_004cafcd: - _totalFood_1 = DAT_GameState::instance.playerDataArray[playerID].totalFood; - - if (_totalFood_1 < 0xb) { + int const _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; + if (_totalFood <= 10) { DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; - goto LAB_004cb010; + } else { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; + int const _rationsMod = (int)this->aics[_aiType].doubleRationsFoodThreshold; + if (_rationsMod != 0 && _totalFood >= _rationsMod) + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; } - - LAB_004caff1: - DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; - } - - _newTaxes = *(int*)((int)this + _offset + 0xa8); - - if ((_newTaxes != 0) && (_newTaxes <= _totalFood_1)) { - DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; } - LAB_004cb010: - if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting < 0) { + if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting < 0) DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 0; - } - - if (11 < DAT_GameState::instance.playerDataArray[playerID].taxesSetting) { + if (11 < DAT_GameState::instance.playerDataArray[playerID].taxesSetting) DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 11; - } - - if (DAT_GameState::instance.playerDataArray[playerID].rationsSetting < 0) { + if (DAT_GameState::instance.playerDataArray[playerID].rationsSetting < 0) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; - } - - if (4 < DAT_GameState::instance.playerDataArray[playerID].rationsSetting) { + if (4 < DAT_GameState::instance.playerDataArray[playerID].rationsSetting) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; - } - - return; } } } diff --git a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp index 595a02e11..b180166d0 100644 --- a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp +++ b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp @@ -11,91 +11,64 @@ namespace AI { using OpenSHC::Map::Buildings::BuildingTypeInt; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CDB20 int AICState ::chooseRandomBuildingIDFromPlayersArrayOfBuildings(int playerID) { - int _chosenBuilding; - - int _selectionIndex; - - int _chosenBuildingTypeIndex; - - short* _ptr_buildingIDArray; - - int _buildingID; - - BuildingTypeInt _buildingType; - - bool bVar1; - - _selectionIndex = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + int _count = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; - _chosenBuilding = 0; + int _chosenBuilding = 0; - _chosenBuildingTypeIndex = 46; + int _chosenBuildingTypeIndex = 46; - if (0 < _selectionIndex) { + if (0 < _count) { - _ptr_buildingIDArray = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings; + int _rng = (int)(unsigned char)SEC_RNG::instance.currentNumber2 & 7; - playerID = _selectionIndex; + short* _ptr = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings; do { - _buildingID = (int)*_ptr_buildingIDArray; - - if ((_buildingID != 0) && (_selectionIndex = 0, 0 < _chosenBuildingTypeIndex)) { - - _buildingType - = (BuildingTypeInt)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType; - - do { - - if (((byte)SEC_RNG::instance.currentNumber2 & 7) < 2) { - - bVar1 = _buildingType - == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet3[_selectionIndex]; - - } - - else if (((byte)SEC_RNG::instance.currentNumber2 & 7) < 4) { + int _buildingID = (int)*_ptr; - bVar1 = _buildingType - == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet2[_selectionIndex]; + if (_buildingID != 0) { - } + int _selectionIndex = 0; - else { + if (0 < _chosenBuildingTypeIndex) { - bVar1 = _buildingType - == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_selectionIndex]; - } + BuildingTypeInt _buildingType = + (BuildingTypeInt)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType; - if (bVar1) { + do { - /* - very unique way to break from a loop ;) */ + BuildingTypeInt _cmpType; - _chosenBuilding = _buildingID; + if (_rng < 2) { + _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet3[_selectionIndex]; + } else if (_rng < 4) { + _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet2[_selectionIndex]; + } else { + _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_selectionIndex]; + } - _chosenBuildingTypeIndex = _selectionIndex; - } + if (_buildingType == _cmpType) { + _chosenBuilding = _buildingID; + _chosenBuildingTypeIndex = _selectionIndex; + } - _selectionIndex = _selectionIndex + 1; + _selectionIndex = _selectionIndex + 1; - } while (_selectionIndex < _chosenBuildingTypeIndex); + } while (_selectionIndex < _chosenBuildingTypeIndex); + } } - _ptr_buildingIDArray = _ptr_buildingIDArray + 1; + _ptr = _ptr + 1; - playerID = playerID + -1; + _count = _count - 1; - } while (playerID != 0); + } while (_count != 0); } return _chosenBuilding; diff --git a/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp index ca0fa349b..5d3637d4c 100644 --- a/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp +++ b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp @@ -10,40 +10,24 @@ namespace AI { using OpenSHC::Synchrony::GameSynchronyState; - /* - 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 0x004CAC70 void AICState ::clearPlayerDataInformationChunk() { - - GameSynchronyState* piVar1; - - int* _Dst; - - _Dst = &DAT_GameState::instance.playerDataArray[0].aiFarmIndex; - - piVar1 = (GameSynchronyState*)DAT_GameSynchronyState::instance.currentAIArray; + int* _Dst = &DAT_GameState::instance.playerDataArray[0].aiFarmIndex; + int* _pAI = DAT_GameSynchronyState::instance.currentAIArray; + int* _pFullID = DAT_GameSynchronyState::instance.currentPlayerFullIDArray; do { - - if ((piVar1->currentPlayerFullIDArray[0] != -1) || (piVar1->currentAIArray[0] == 0)) { - + if (*_pFullID != -1 || *_pAI == 0) { MACRO_CALL(OpenSHC::OS_Func::_memset)(_Dst, 0, (size_t)((int)(3748))); } - piVar1 = (GameSynchronyState*)(piVar1->currentAIArray + 1); - + _pAI = _pAI + 1; + _pFullID = _pFullID + 1; _Dst = _Dst + 3709; - } while ((int)piVar1 < 0x191dea0); + } while ((int)_pAI < 0x191dea0); return; } diff --git a/src/OpenSHC/AI/AICState/computeNervousness.cpp b/src/OpenSHC/AI/AICState/computeNervousness.cpp index 2d0d9f26e..ca79afa7c 100644 --- a/src/OpenSHC/AI/AICState/computeNervousness.cpp +++ b/src/OpenSHC/AI/AICState/computeNervousness.cpp @@ -11,75 +11,43 @@ namespace AI { void AICState ::computeNervousness(int playerID) { + int _one = 1; - int iVar1; - - int _someCutoff; - - int _totalTroopValueOfEnemy; - - iVar1 = DAT_TroopValueState::instance.attackInfo.playerTotalTroopValueOfTroopsNearKeep[playerID]; + int iVar1 = DAT_TroopValueState::instance.attackInfo.playerTotalTroopValueOfTroopsNearKeep[playerID]; - _totalTroopValueOfEnemy = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; + int _totalTroopValueOfEnemy = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; - int _one = 1; + int _someCutoff; if (_totalTroopValueOfEnemy < 50) { - _someCutoff = _one - 0x15; - - } - - else if (_totalTroopValueOfEnemy < 100) { - + } else if (_totalTroopValueOfEnemy < 100) { _someCutoff = 0; - - } - - else if (_totalTroopValueOfEnemy < 200) { - + } else if (_totalTroopValueOfEnemy < 200) { _someCutoff = 20; - - } - - else if (_totalTroopValueOfEnemy < 400) { - + } else if (_totalTroopValueOfEnemy < 400) { _someCutoff = 100; - - } - - else if (_totalTroopValueOfEnemy < 600) { - + } else if (_totalTroopValueOfEnemy < 600) { _someCutoff = 200; - - } - - else { - + } else { _someCutoff = ((_totalTroopValueOfEnemy >= 800) - _one & 0xffffff38) + 500; } if (iVar1 > _someCutoff + _totalTroopValueOfEnemy) { - DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue = 0; - return; } if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue == 0) { - - if (iVar1 < DAT_GameState::instance.playerDataArray[playerID] - .totalEnemyTroopValueByPlayerID[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { - + if (DAT_GameState::instance.playerDataArray[playerID] + .totalEnemyTroopValueByPlayerID[DAT_GameSynchronyState::instance.currentPlayerSlotID] + > iVar1) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playNervous1BikFromPlayer, this)(playerID); } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playRequestHelpBikFromPlayer, this)(playerID); } DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue = _one; - - return; } } diff --git a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp index 59f8a77c5..5e71e48dc 100644 --- a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp +++ b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp @@ -23,265 +23,147 @@ namespace AI { using OpenSHC::Map::Units::UnitInstructionType; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D1A00 void AICState ::decideOnTribeAttackLocation(uint tribeID_OR_moatWasHit) - { + uint _tribeID = tribeID_OR_moatWasHit; - short* psVar1; - - short sVar2; - - bool bVar3; - - BOOLEnum _canHaveActivity; - - int _unitID; - - BOOLEnum BVar4; - - int _targetBuilding; - - int _buildingID; - - int _buildingID_2; - - int iVar5; - - int _destinationX; - - int _targetPlayer; - - int _destinationY; - - int _y; - - int _x; - - int _buildingUID; - - int _rng; - - int _destinationTile; - - uint _tribeID; - - _tribeID = tribeID_OR_moatWasHit; - - _canHaveActivity + BOOLEnum _canHaveActivity = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(tribeID_OR_moatWasHit, FALSE, TRUE); - if (_canHaveActivity != FALSE) { - DAT_TribesState::instance.tribes[_tribeID].counter = 0; - return; } - _targetPlayer = (int)DAT_TribesState::instance.tribes[_tribeID].targetPlayer_outpost; + int _targetPlayer = (int)DAT_TribesState::instance.tribes[_tribeID].targetPlayer_outpost; if (DAT_TribesState::instance.tribes[_tribeID].randomNumber == 0) { - DAT_TribesState::instance.tribes[_tribeID].randomNumber = (int)SEC_RNG::instance.currentNumber2; - MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); } - _rng = DAT_TribesState::instance.tribes[_tribeID].randomNumber; - - psVar1 = &DAT_TribesState::instance.tribes[_tribeID].counter; - + int _rng = DAT_TribesState::instance.tribes[_tribeID].randomNumber; + short* psVar1 = &DAT_TribesState::instance.tribes[_tribeID].counter; *psVar1 = *psVar1 + 1; if ((int)DAT_TribesState::instance.tribes[_tribeID].counter == _rng % 6 + 7) { - DAT_TribesState::instance.tribes[_tribeID].counter = 0; - - /* - WARNING: tribeID has a new purpose */ - tribeID_OR_moatWasHit = tribeID_OR_moatWasHit & 0xffffff00; - - _x = 0; - - _y = 0; - - _unitID = MACRO_CALL_MEMBER( + int _x = 0; + int _y = 0; + int _unitID = MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::getUnitIDForIndexInTribe, DAT_TribesState::ptr)(_tribeID, 0); - if ((_unitID != 0) - && (bVar3 = MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, - DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[_tribeID].owner, _targetPlayer, - (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), - (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), (byte*)&tribeID_OR_moatWasHit, - &_x, &_y), - bVar3)) { - + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, + DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[_tribeID].owner, _targetPlayer, + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), (byte*)&tribeID_OR_moatWasHit, + &_x, &_y)) { if ((char)tribeID_OR_moatWasHit != '\0') { - - /* - moat was not hit */ - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( _tribeID, ((UnitInstructionType)0x23), DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile + _x, 0, 0); - return; } - - /* - moat was hit */ - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( _tribeID, OpenSHC::Map::Units::UIT_FILL_MOAT, _x, _y, 1000); - return; } } - sVar2 = DAT_TribesState::instance.tribes[_tribeID].tribeSubtype1; + short sVar2 = DAT_TribesState::instance.tribes[_tribeID].tribeSubtype1; if ((sVar2 != 0xb6) && (sVar2 != 0xb9)) { - - BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, FALSE); - - if (BVar4 != FALSE) { - + BOOLEnum BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, FALSE); + if (BVar4 != FALSE) return; - } - - _targetBuilding = (int)DAT_TribesState::instance.tribes[_tribeID].targetBuildingID; + int _targetBuilding = (int)DAT_TribesState::instance.tribes[_tribeID].targetBuildingID; if ((((_targetBuilding != 0) && (DAT_BuildingsState::instance.buildings[_targetBuilding].uid == DAT_TribesState::instance.tribes[_tribeID].targetBuildingUID)) && (DAT_BuildingsState::instance.buildings[_targetBuilding].fireDuration == 0)) && (BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, TRUE), BVar4 != FALSE)) { - - if (DAT_GameState::instance.mapAndTime.yearChanged == 0) { - + if (DAT_GameState::instance.mapAndTime.yearChanged == 0) return; - } - DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = 0; - return; } - _buildingID = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + int _buildingID = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, DAT_GameState::ptr)(_targetPlayer); - if (_buildingID != 0) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( _tribeID, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, _buildingID, DAT_BuildingsState::instance.buildings[_buildingID].uid, 0); - - _buildingUID = DAT_BuildingsState::instance.buildings[_buildingID].uid; - + int _buildingUID = DAT_BuildingsState::instance.buildings[_buildingID].uid; DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = (short)_buildingID; - DAT_TribesState::instance.tribes[_tribeID].targetBuildingUID = _buildingUID; - return; } - _destinationX = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; - + int _destinationX = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = 0; - - _destinationY = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry; - + int _destinationY = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry; BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(_tribeID, DAT_ViewportRenderState::instance.translationMatrix[_destinationY].addXgetTile + _destinationX); - - if (BVar4 == FALSE) { - + if (BVar4 == FALSE) return; - } - - goto LAB_004d1c59; + // was LAB_004d1c59 + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + _tribeID, (uint)((int)(_destinationX)), (uint)((int)(_destinationY)), 1); + return; } - _buildingID_2 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + int _buildingID_2 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, DAT_GameState::ptr)(_targetPlayer); - if (_buildingID_2 == 0) { + int _destinationTile; + int _destinationX2; + int _destinationY2; - iVar5 = DAT_ViewportRenderState::instance + if (_buildingID_2 == 0) { + int iVar5 = DAT_ViewportRenderState::instance .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] .addXgetTile; - - LAB_004d1d11: _destinationTile = iVar5 + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; - - } - - else { - - iVar5 = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; - + } else { + int iVar5 = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; if (iVar5 == 0) { - _destinationTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + DAT_ViewportRenderState::instance .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryY] .addXgetTile; - - } - - else { - + } else { MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathfindingForAttacksUnk, DAT_PathFindingState::ptr)(_tribeID, _buildingID_2, 1, (dword)((int)((int)(short)DAT_TileMapState::instance .PathConnectionLayer[DAT_UnitsState::instance.units[iVar5].tile])), _targetPlayer); - _destinationTile = DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile1; - if (DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper == 0) { - - iVar5 = DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer] - .campground.yEntry] + // was LAB_004d1d11 + int iVar5b = DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] .addXgetTile; - - goto LAB_004d1d11; + _destinationTile = iVar5b + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; } } } if (_destinationTile != 0) { - - _destinationY - = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_destinationTile]; - - _destinationX - = _destinationTile - DAT_ViewportRenderState::instance.translationMatrix[_destinationY].addXgetTile; - - BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( + _destinationY2 = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_destinationTile]; + _destinationX2 = _destinationTile - DAT_ViewportRenderState::instance.translationMatrix[_destinationY2].addXgetTile; + BOOLEnum BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( _tribeID, _destinationTile); - if (BVar4 != FALSE) { - - LAB_004d1c59: MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( - _tribeID, (uint)((int)(_destinationX)), (uint)((int)(_destinationY)), 1); - + _tribeID, (uint)((int)(_destinationX2)), (uint)((int)(_destinationY2)), 1); return; } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(_tribeID, _targetPlayer); } - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp index 55622a561..42b5dde68 100644 --- a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp +++ b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp @@ -11,98 +11,61 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0280 void AICState::destroyAnyBuildingInCategory(int playerID, AINervousDestroyBuildingCategory buildingCategory) { - Map::Buildings::BuildingTypeShort BVar1; - int _buildingID; - bool bVar2; - - _buildingID = 1; + int _buildingID = 1; if (1 < DAT_BuildingsState::instance.maxBuildingsCount) { Map::Buildings::Building* pBVar2 = &DAT_BuildingsState::instance.buildings[1]; do { if (((pBVar2->logicalState != 0) && (pBVar2->logicalState != Map::Buildings::BLS_REMOVE)) && (pBVar2->owner == playerID)) { + + bool _matches = false; + Map::Buildings::BuildingTypeShort BVar1 = pBVar2->buildingType; + if (buildingCategory == AINDBC_FEAR_FACTOR_BUILDINGS) { - BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_CESSPIT) && (BVar1 != Map::Buildings::BT_BURNINGSTAKE)) - && (((BVar1 != Map::Buildings::BT_GIBBET - && (((BVar1 != Map::Buildings::BT_DUNGEON - && (BVar1 != Map::Buildings::BT_STRETCHINGRACK)) - && (BVar1 != Map::Buildings::BT_RACKFLOGGING)))) - && (((BVar1 != Map::Buildings::BT_CHOPPINGBLOCK - && (BVar1 != Map::Buildings::BT_DUNKINGSTOOL)) - && ((BVar1 != Map::Buildings::BT_DOGCAGE - && (( - (BVar1 != Map::Buildings::BT_STATUE && (BVar1 != Map::Buildings::BT_SHRINE)) - && ((BVar1 != Map::Buildings::BT_DANCINGBEAR - && ((((BVar1 != Map::Buildings::BT_POND - && (BVar1 != Map::Buildings::BT_GALLOWS)) - && (BVar1 != Map::Buildings::BT_STOCKS)) - && ((BVar1 != Map::Buildings::BT_WITCHHOIST - && (BVar1 != Map::Buildings::BT_MAYPOLE)))))))))))))))) { - bVar2 = BVar1 == Map::Buildings::BT_GARDEN; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_CESSPIT || BVar1 == Map::Buildings::BT_BURNINGSTAKE + || BVar1 == Map::Buildings::BT_GIBBET || BVar1 == Map::Buildings::BT_DUNGEON + || BVar1 == Map::Buildings::BT_STRETCHINGRACK || BVar1 == Map::Buildings::BT_RACKFLOGGING + || BVar1 == Map::Buildings::BT_CHOPPINGBLOCK || BVar1 == Map::Buildings::BT_DUNKINGSTOOL + || BVar1 == Map::Buildings::BT_DOGCAGE || BVar1 == Map::Buildings::BT_STATUE + || BVar1 == Map::Buildings::BT_SHRINE || BVar1 == Map::Buildings::BT_DANCINGBEAR + || BVar1 == Map::Buildings::BT_POND || BVar1 == Map::Buildings::BT_GALLOWS + || BVar1 == Map::Buildings::BT_STOCKS || BVar1 == Map::Buildings::BT_WITCHHOIST + || BVar1 == Map::Buildings::BT_MAYPOLE || BVar1 == Map::Buildings::BT_GARDEN); } else if (buildingCategory == AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS) { - BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_FLETCHER) && (BVar1 != Map::Buildings::BT_BLACKSMITH)) - && (((BVar1 != Map::Buildings::BT_POLETURNER - && (((BVar1 != Map::Buildings::BT_ARMOURER && (BVar1 != Map::Buildings::BT_TANNER)) - && (BVar1 != Map::Buildings::BT_INN)))) - && (((BVar1 != Map::Buildings::BT_APOTHECARY && (BVar1 != Map::Buildings::BT_CHAPEL)) - && (BVar1 != Map::Buildings::BT_CHURCH)))))) { - bVar2 = BVar1 == Map::Buildings::BT_CATHEDRAL; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_FLETCHER || BVar1 == Map::Buildings::BT_BLACKSMITH + || BVar1 == Map::Buildings::BT_POLETURNER || BVar1 == Map::Buildings::BT_ARMOURER + || BVar1 == Map::Buildings::BT_TANNER || BVar1 == Map::Buildings::BT_INN + || BVar1 == Map::Buildings::BT_APOTHECARY || BVar1 == Map::Buildings::BT_CHAPEL + || BVar1 == Map::Buildings::BT_CHURCH || BVar1 == Map::Buildings::BT_CATHEDRAL); } else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) { - BVar1 = pBVar2->buildingType; - if (((((BVar1 != Map::Buildings::BT_GATEHOUSELARGE) - && (BVar1 != Map::Buildings::BT_GATEHOUSESMALL)) - && ((BVar1 != Map::Buildings::BT_DRAWBRIDGE - && ((((BVar1 != Map::Buildings::BT_TOWER1 && (BVar1 != Map::Buildings::BT_TOWER2)) - && (BVar1 != Map::Buildings::BT_TOWER3)) - && ((BVar1 != Map::Buildings::BT_TOWER4 - && (BVar1 != Map::Buildings::BT_TOWER5)))))))) - && (BVar1 != Map::Buildings::BT_ENGINEERSGUILD)) - && (BVar1 != Map::Buildings::BT_TUNNELERSGUILD)) { - bVar2 = BVar1 == Map::Buildings::BT_OILSMELTER; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_GATEHOUSELARGE || BVar1 == Map::Buildings::BT_GATEHOUSESMALL + || BVar1 == Map::Buildings::BT_DRAWBRIDGE || BVar1 == Map::Buildings::BT_TOWER1 + || BVar1 == Map::Buildings::BT_TOWER2 || BVar1 == Map::Buildings::BT_TOWER3 + || BVar1 == Map::Buildings::BT_TOWER4 || BVar1 == Map::Buildings::BT_TOWER5 + || BVar1 == Map::Buildings::BT_ENGINEERSGUILD || BVar1 == Map::Buildings::BT_TUNNELERSGUILD + || BVar1 == Map::Buildings::BT_OILSMELTER); } else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) { - BVar1 = pBVar2->buildingType; - if ((BVar1 != Map::Buildings::BT_MERCENARYPOST) && (BVar1 != Map::Buildings::BT_BARRACKS)) { - bVar2 = BVar1 == Map::Buildings::BT_STABLES; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_MERCENARYPOST || BVar1 == Map::Buildings::BT_BARRACKS + || BVar1 == Map::Buildings::BT_STABLES); } else if (buildingCategory == AINDBC_WATER_BUILDINGS) { - if (pBVar2->buildingType != Map::Buildings::BT_WELL) { - bVar2 = pBVar2->buildingType == Map::Buildings::BT_WATERPOT; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_WELL || BVar1 == Map::Buildings::BT_WATERPOT); } else if (buildingCategory == AINDBC_RESOURCE_BUILDINGS) { - BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_OXTETHER) && (BVar1 != Map::Buildings::BT_IRONMINE)) - && ((BVar1 != Map::Buildings::BT_PITCHRIG - && (((BVar1 != Map::Buildings::BT_BAKERY && (BVar1 != Map::Buildings::BT_BREWERY)) - && (BVar1 != Map::Buildings::BT_QUARRY)))))) { - bVar2 = BVar1 == Map::Buildings::BT_MILL; - LAB_004d04de: - if (!bVar2) - goto LAB_004d04f9; - } - } else { - if (((buildingCategory == AINDBC_FARMS) - && (BVar1 = pBVar2->buildingType, BVar1 != Map::Buildings::BT_WHEATFARM)) - && ((BVar1 != Map::Buildings::BT_HOPFARM && (BVar1 != Map::Buildings::BT_APPLEFARM)))) { - bVar2 = BVar1 == Map::Buildings::BT_DAIRYFARM; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_OXTETHER || BVar1 == Map::Buildings::BT_IRONMINE + || BVar1 == Map::Buildings::BT_PITCHRIG || BVar1 == Map::Buildings::BT_BAKERY + || BVar1 == Map::Buildings::BT_BREWERY || BVar1 == Map::Buildings::BT_QUARRY + || BVar1 == Map::Buildings::BT_MILL); + } else if (buildingCategory == AINDBC_FARMS) { + _matches = (BVar1 == Map::Buildings::BT_WHEATFARM || BVar1 == Map::Buildings::BT_HOPFARM + || BVar1 == Map::Buildings::BT_APPLEFARM || BVar1 == Map::Buildings::BT_DAIRYFARM); + } + + if (_matches) { + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( + _buildingID); } - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( - _buildingID); } - LAB_004d04f9: _buildingID = _buildingID + 1; pBVar2 = pBVar2 + 1; } while (_buildingID < DAT_BuildingsState::instance.maxBuildingsCount); diff --git a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp index e34daac0d..29895258e 100644 --- a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp +++ b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp @@ -14,31 +14,32 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB940 undefined4 AICState::destroyBuildingIfNoWorker(int buildingID) { - short _value; - int _owner; - _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; - _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; - if ((((0 < _value) && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1)) - && (DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0)) - && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY)) { + short _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; + int _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; + + if (0 < _value && DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1 + && DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0 + && DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY) { + if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] != 0) { -LAB_CHECK_MONTH: - if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { + if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = _value + -1; - } - } else { - if (!((short)0x14 <= _value)) { - goto LAB_CHECK_MONTH; - } - MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( - (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, - (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( - buildingID); - return 1; + return 0; } + + // workers == 0: check if old enough + if ((short)_value < (short)0x14) + return 0; + + // old enough: destroy + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( + buildingID); + return 1; } return 0; } diff --git a/src/OpenSHC/AI/AICState/destroyHouse.cpp b/src/OpenSHC/AI/AICState/destroyHouse.cpp index e04f4d87f..108bf6d85 100644 --- a/src/OpenSHC/AI/AICState/destroyHouse.cpp +++ b/src/OpenSHC/AI/AICState/destroyHouse.cpp @@ -13,22 +13,31 @@ namespace AI { BOOLEnum AICState::destroyHouse(int playerID) { int _hovelID; - if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) - && (_hovelID = DAT_GameState::instance.playerDataArray[playerID].currentPopulation, - _hovelID <= DAT_GameState::instance.playerDataArray[playerID].populationCap)) - && (8 < _hovelID)) - && (0x14 < DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk)) { - _hovelID = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, - DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_HOVEL); - if (_hovelID == 0) { - return FALSE; - } - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(_hovelID, playerID, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hovelID); - return TRUE; - } - return FALSE; + + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) + return FALSE; + + _hovelID = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; + + if (_hovelID > DAT_GameState::instance.playerDataArray[playerID].populationCap) + return FALSE; + + if (_hovelID <= 8) + return FALSE; + + if (DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk <= 0x14) + return FALSE; + + _hovelID = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_HOVEL); + + if (_hovelID == 0) + return FALSE; + + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(_hovelID, playerID, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hovelID); + return TRUE; } } } diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp index 68b449749..2420b23f2 100644 --- a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -11,107 +11,57 @@ namespace OpenSHC { namespace AI { - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000This function finds the first active AI - attack tribe for a player (validating it's still alive via UID matching), then traces a path from - that tribe's position toward the player's own defenses, storing the resulting tile coordinates in - the player's game state. It's likely used by the AI to rally or redirect attacking forces — - perhaps pulling them back toward defensive structures when needed, or seeding a waypoint for a - retreat/regroup maneuver. */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CE930 void AICState ::findAttackTribePositionAndPathToDefenses(int playerID) - { + uint local_8 = 0; + uint local_4 = 0; + int* local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; - int iVar1; - - int _tile; - - int iVar2; - - short* psVar3; - - int* local_c; - - uint local_8; - - uint local_4; - - short _y; - - local_8 = 0; - - local_4 = 0; - - local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; - + bool _found = false; do { - - iVar2 = 0; - + int iVar2 = 0; if (0 < *local_c) { - - psVar3 - = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + (*(int (*)[2])(local_c + -1))[0]; - + short* psVar3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + + (*(int (*)[2])(local_c + -1))[0]; do { - - iVar1 = (int)*psVar3; - + int iVar1 = (int)*psVar3; if ((iVar1 != 0) && (DAT_TribesState::instance.tribes[iVar1].uid == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[iVar2 + (*(int (*)[2])(local_c + -1))[0]])) { - + .aiTribeUIDs[iVar2 + (*(int (*)[2])(local_c + -1))[0]])) { iVar2 = (int)DAT_TribesState::instance.tribes[iVar1].selectionTargetUnitID; - local_8 = (uint)DAT_UnitsState::instance.units[iVar2].x; - local_4 = (uint)DAT_UnitsState::instance.units[iVar2].y; - - if (iVar2 != 0) - goto LAB_004ce9f1; - + if (iVar2 != 0) { + _found = true; + break; + } break; } - iVar2 = iVar2 + 1; - psVar3 = psVar3 + 1; - } while (iVar2 < *local_c); } - + if (_found) + break; local_c = local_c + 2; - - if (0xb42a2b < (int)local_c) { - - LAB_004ce9f1: - DAT_GameState::instance.playerDataArray[playerID].someTile = 0; - - if ((local_8 != 0) - && (_tile = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: - tracePathToFriendlyDefensesAndReturnTileUnk, - DAT_PathFindingState::ptr)(playerID, local_8, local_4), - 0 < _tile)) { - - _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; - - DAT_GameState::instance.playerDataArray[playerID].someTile = _tile; - - iVar2 = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; - - DAT_GameState::instance.playerDataArray[playerID].someY = (int)_y; - - DAT_GameState::instance.playerDataArray[playerID].someX = _tile - iVar2; - } - - return; + } while ((int)local_c <= 0xb42a2b); + + DAT_GameState::instance.playerDataArray[playerID].someTile = 0; + + if (local_8 != 0) { + int _tile = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::tracePathToFriendlyDefensesAndReturnTileUnk, + DAT_PathFindingState::ptr)(playerID, local_8, local_4); + if (0 < _tile) { + short _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + DAT_GameState::instance.playerDataArray[playerID].someTile = _tile; + int iVar2 = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + DAT_GameState::instance.playerDataArray[playerID].someY = (int)_y; + DAT_GameState::instance.playerDataArray[playerID].someX = _tile - iVar2; } - - } while (true); + } } - } } diff --git a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp index 0007cf995..24934a4df 100644 --- a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp +++ b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp @@ -23,26 +23,23 @@ namespace AI { break; if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1]) || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1])) { - _index = _index + 1; - break; + _index = _index + 1; break; } if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2]) || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2])) { - _index = _index + 2; - break; + _index = _index + 2; break; } if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3]) || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3])) { - _index = _index + 3; - break; + _index = _index + 3; break; } if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4]) || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4])) { - _index = _index + 4; - break; + _index = _index + 4; break; } _index = _index + 5; } while (_index < 0x14); + int _tribeIndex; if (_index < 1) { _tribeIndex = 0xb4; @@ -54,19 +51,16 @@ namespace AI { _tribeIndex = 0xb7; } else if (_index < 0xf) { _tribeIndex = 0xb8; - } else { - if (19 < _index) { - return 0; - } + } else if (_index < 0x14) { _tribeIndex = 0xb9; + } else { + return 0; } + short* _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeIndex; int _tribeID = (int)*_pTribeID; - if ((_tribeID == 0) - || (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex])) { - _tribeID - = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + if ((_tribeID == 0) || (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex])) { + _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; *_pTribeID = (short)_tribeID; DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex] = _tribeUID; diff --git a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp index 3b82b7d3d..daeffb4e5 100644 --- a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp +++ b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp @@ -7,94 +7,49 @@ namespace OpenSHC { namespace AI { - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CCAF0 int AICState ::getSmallestPatrolTribe(int playerID, int tribeCount) - { - - int _selectedTribeID; - - int _tribeID; - - int _tribeNumber; - - short* _pTribeID; - - int _selectedTribeNumber; - - short _lowestTribeUnitCount; - - short _tribeSize; - - _selectedTribeID = 0; - - _tribeNumber = 0; - - _selectedTribeNumber = 0; - - _lowestTribeUnitCount = 1000; + int _selectedTribeID = 0; + int _tribeNumber = 0; + int _selectedTribeNumber = 0; + short _lowestTribeUnitCount = 1000; if (0 < tribeCount) { - - _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; - + short* _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; do { - - _tribeID = (int)*_pTribeID; - + int _tribeID = (int)*_pTribeID; if ((_tribeID == 0) || (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeNumber + 0xaa])) { - _selectedTribeID = MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - _selectedTribeNumber = _tribeNumber; - - goto LAB_004ccb9d; + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_selectedTribeNumber + 0xaa] + = (short)_selectedTribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_selectedTribeNumber + 0xaa] + = DAT_TribesState::instance.tribes[_selectedTribeID].uid; + return _selectedTribeID; } - - _tribeSize = DAT_TribesState::instance.tribes[_tribeID].size; - + short _tribeSize = DAT_TribesState::instance.tribes[_tribeID].size; if (_tribeSize < _lowestTribeUnitCount) { - _selectedTribeID = _tribeID; - _selectedTribeNumber = _tribeNumber; - _lowestTribeUnitCount = _tribeSize; } - _tribeNumber = _tribeNumber + 1; - _pTribeID = _pTribeID + 1; - } while (_tribeNumber < tribeCount); if (_selectedTribeID != 0) { - - LAB_004ccb9d: - /* - pTribeID = selectedTribeID */ - DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_selectedTribeNumber + 0xaa] = (short)_selectedTribeID; - - /* - pTribeUID = selectedTribeUID */ - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_selectedTribeNumber + 0xaa] = DAT_TribesState::instance.tribes[_selectedTribeID].uid; - return _selectedTribeID; } } - return 0; } - } } diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp index 6c36b0a2e..a46324383 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp @@ -18,88 +18,64 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CD8F0 void AICState ::giveMoveCommandToSortieUnits(int playerID) - { - - int iVar1; - - int _tribeID; - - int _aiType; - - int _unitID; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType == 0) { + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == 0) return; - } - - _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa7]; - if (_tribeID == 0) { + int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa7]; + if (_tribeID == 0) return; - } - if (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa7]) { + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa7]) return; - } if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 + -1) { + < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 + -1) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::syncBehaviourType7UnitTribes, this)(playerID); - } if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { - goto LAB_sendToKeep; + // nervous: send to keep then set stance + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + return; } - /* - SortieUnitMeleeMin */ - if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x154)) - goto LAB_004cda3c; - - _unitID = DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitID; + < *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x154)) { + // tribe too small: just set stance + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + return; + } + int _unitID = DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitID; + int iVar1; if (((_unitID != 0) && (DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitUID == DAT_UnitsState::instance.units[_unitID].uid)) && (iVar1 = MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)(playerID, - (dword)(( - int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance - .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID] - .tile])), + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID].tile])), (dword)((int)((int)(short)DAT_TileMapState::instance .PathConnectionLayer[DAT_UnitsState::instance.units[_unitID].tile])), 0), iVar1 != 0)) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)(_tribeID); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(_tribeID, (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), + DAT_TribesState::ptr)(_tribeID, + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - return; } - LAB_sendToKeep: MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); - - LAB_004cda3c: DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp index 0228ab5f7..eb6658bc8 100644 --- a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp +++ b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp @@ -12,39 +12,29 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CF920 undefined4 AICState ::giveSomeRaidCommand(int tribeIndex, int tribeType) { + int _tribeOffset = tribeIndex * 0x334; + int _attacked = DAT_TribesState::instance.tribes[tribeIndex].owner; + int _targetBuildingID = (int)DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID; - int _chosenBuildingID; - - int _targetBuildingID; - - int _attacked; - - _targetBuildingID = (int)DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID; - - if ((((tribeType != 0xba) && (tribeType != 0x12)) && (tribeType != 0xe)) && (tribeType != 0xd)) { - - if (((_targetBuildingID != 0) - && (DAT_BuildingsState::instance.buildings[_targetBuildingID].uid - == DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID)) - && (DAT_BuildingsState::instance.buildings[_targetBuildingID].fireDuration == 0)) { + if (tribeType != 0xba && tribeType != 0x12 && tribeType != 0xe && tribeType != 0xd) { + if (_targetBuildingID != 0 + && DAT_BuildingsState::instance.buildings[_targetBuildingID].uid + == DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID + && DAT_BuildingsState::instance.buildings[_targetBuildingID].fireDuration == 0) { return (undefined4)(1); } - _attacked = DAT_GameState::instance.playerDataArray[DAT_TribesState::instance.tribes[tribeIndex].owner] - .attackedPlayerID; + int _attackedPlayerID = DAT_GameState::instance.playerDataArray[_attacked].attackedPlayerID; DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = 0; - _chosenBuildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)(_attacked); + int _chosenBuildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)(_attackedPlayerID); if (_chosenBuildingID != 0) { @@ -52,13 +42,14 @@ namespace AI { DAT_UnitsState::ptr)(tribeIndex, 9, (undefined4)((int)(_chosenBuildingID)), (undefined4)((int)(DAT_BuildingsState::instance.buildings[_chosenBuildingID].uid))); + // Store UID before targetBuildingID (matching orig order) DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID = DAT_BuildingsState::instance.buildings[_chosenBuildingID].uid; - DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = (short)_chosenBuildingID; - DAT_TribesState::instance.tribes[tribeIndex].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = (short)_chosenBuildingID; + return (undefined4)(1); } } diff --git a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp index 5862623d0..fe3050b27 100644 --- a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp +++ b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp @@ -8,14 +8,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CFFD0 BOOLEnum AICState::hasNoTroopsOrAllAreDiggers(int playerID) { - int _totalTroops; - int _halfOfDiggingTroops; - - // reversed order to match orig int _totalMisc = DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops; - _halfOfDiggingTroops = 0; + int _halfOfDiggingTroops = 0; + int _totalTroops; + if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState == 6) { _totalMisc += DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops; int _attackTicker = DAT_GameState::instance.playerDataArray[playerID].attackTicker; @@ -48,8 +46,11 @@ namespace AI { + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops; } - if ((1 < _totalTroops) && ((4 < _totalTroops) || (_halfOfDiggingTroops <= _totalTroops + _totalTroops))) { - return FALSE; + + if (1 < _totalTroops) { + if (4 < _totalTroops || _halfOfDiggingTroops <= _totalTroops + _totalTroops) { + return FALSE; + } } return TRUE; } diff --git a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp index 8a56546ea..28dffd267 100644 --- a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp +++ b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp @@ -10,20 +10,24 @@ namespace AI { BOOLEnum AICState::hasNotEnoughSupplies(int playerID) { BOOLEnum BVar1 = TRUE; - if (((((DAT_GameState::instance.playerDataArray[playerID].marketplace.id != 0) - || (DAT_BuildingsState::instance.buildingCosts[0x1a].requiredWood - <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) - || (0 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)) - && (((DAT_GameState::instance.playerDataArray[playerID].granary.id != 0 - || (DAT_BuildingsState::instance.buildingCosts[0x13].requiredWood - <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) - || (1 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)))) - && (((0 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] - || (25 < DAT_GameState::instance.playerDataArray[playerID].popularity)) - || (0 < DAT_GameState::instance.playerDataArray[playerID].totalFood)))) { - BVar1 = FALSE; + if (DAT_GameState::instance.playerDataArray[playerID].marketplace.id == 0 + && DAT_GameState::instance.playerDataArray[playerID].currentResources[2] + < DAT_BuildingsState::instance.buildingCosts[0x1a].requiredWood + && DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 1) { + return BVar1; } - return BVar1; + if (DAT_GameState::instance.playerDataArray[playerID].granary.id == 0 + && DAT_GameState::instance.playerDataArray[playerID].currentResources[2] + < DAT_BuildingsState::instance.buildingCosts[0x13].requiredWood + && DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount <= 1) { + return BVar1; + } + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] <= 0 + && DAT_GameState::instance.playerDataArray[playerID].popularity <= 25 + && DAT_GameState::instance.playerDataArray[playerID].totalFood <= 0) { + return BVar1; + } + return FALSE; } } } diff --git a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp index 414d34b99..620439b22 100644 --- a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp +++ b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp @@ -19,98 +19,59 @@ namespace AI { using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CD7B0 void AICState ::instructTribe166ToMove(int playerID) - { - - BOOLEnum _keepEnclosed; - - int _tribeID; - - int _counter; - - AITypeInt _aiType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType == OpenSHC::AI::AIT_NULL) { - + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == OpenSHC::AI::AIT_NULL) return; - } - - _counter = DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01; - - if (0 < _counter) { + int _counter = DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01; + if (0 < _counter) DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 = _counter + -1; - } - - if (50 < DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01) { - + if (50 < DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01) DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 = 50; - } - _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; - - _keepEnclosed = MACRO_CALL_MEMBER( + int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; + BOOLEnum _keepEnclosed = MACRO_CALL_MEMBER( OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); - if (_tribeID == 0) { - + if (_tribeID == 0) return; - } - if (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa6]) { - + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa6]) return; - } if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 + -5) { - + < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 + -5) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitsToTribe166, this)(playerID); - } if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) || (_keepEnclosed != FALSE)) { - /* - SortieUnitRangedMin */ - if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x14c)) - goto LAB_004cd86b; + < *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x14c)) { + // tribe too small: just set stance + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + return; + } if ((0 < DAT_GameState::instance.playerDataArray[playerID].someXPosition) && (0 < DAT_GameState::instance.playerDataArray[playerID].someYPosition)) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)(_tribeID); - - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(_tribeID, (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someXPosition)), (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someYPosition)), 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - return; } } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); - - LAB_004cd86b: DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp index 7eaedffbb..a6a3f9d47 100644 --- a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp @@ -16,79 +16,51 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CEEA0 BOOLEnum AICState ::processAttForceRallyPercentage(int playerID) { + AITypeInt AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - AITypeInt AVar1; - - int iVar2; - - int iVar3; - - int _tribeID; - - short* psVar4; - - int iVar5; - - int _tribeTotal; - - int _notReallyMoving; - - int* local_c; - - AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) { - + if (AVar1 == OpenSHC::AI::AIT_NULL) return FALSE; - } - - _tribeTotal = 0; - _notReallyMoving = 0; + AITypeInt _aiTypeMinus1 = AVar1 - 1; + int _tribeTotal = 0; + int _notReallyMoving = 0; - local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + int* local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; do { + int iVar2 = (*(int (*)[2])(local_c + -1))[0]; + int iVar3 = *local_c; - iVar2 = (*(int (*)[2])(local_c + -1))[0]; - - iVar3 = *local_c; - - if ((((iVar2 != 0x12) && (iVar2 != 0xbe)) && (iVar2 != 0xf)) && (iVar5 = 0, 0 < iVar3)) { - - psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar2; + if (iVar2 != 0x12 && iVar2 != 0xbe && iVar2 != 0xf) { + int iVar5 = 0; + if (0 < iVar3) { + short* psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar2; - do { + do { + int _tribeID = (int)*psVar4; - _tribeID = (int)*psVar4; + if (_tribeID != 0 + && DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar5 + iVar2]) { - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar5 + iVar2])) { + _tribeTotal = _tribeTotal + 1; - _tribeTotal = _tribeTotal + 1; + if (DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0x14) + _notReallyMoving = _notReallyMoving + 1; - if (DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0x14) { - - _notReallyMoving = _notReallyMoving + 1; + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; } - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; - } - - iVar5 = iVar5 + 1; - - psVar4 = psVar4 + 1; + iVar5 = iVar5 + 1; + psVar4 = psVar4 + 1; - } while (iVar5 < iVar3); + } while (iVar5 < iVar3); + } } local_c = local_c + 2; @@ -96,12 +68,8 @@ namespace AI { } while ((int)local_c < 0xb42a2c); if (0 < _tribeTotal) { - - /* - AttForceRallyPercentage */ - - return (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x200) - <= (_notReallyMoving * 100) / _tribeTotal); + return (BOOLEnum)((_notReallyMoving * 100) / _tribeTotal + >= *(int*)((int)this + _aiTypeMinus1 * 0x2a4 + 0x200)); } return FALSE; diff --git a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp index b9af53ac5..be79bfac5 100644 --- a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp +++ b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp @@ -21,234 +21,127 @@ namespace AI { using OpenSHC::AI::AIC::AITargetChoiceInt; using OpenSHC::Game::Player::PlayerData; - /* - 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 0x004D4680 void AICState ::selectAttackTarget(int playerID) - { - - int fromXPosition; - - int fromYPosition; - - int iVar1; - - int _alive1; - - int _isLordAlive; - - int _lord; - - int _selectedPlayer; - - PlayerData* _pPlayerData2; - - int _iPlayer2; - - int _iPlayer; - - PlayerData* _ptrPlayerData; - - int _lowestDistance; - - int _highestGold; - - int _lowestPoints; - - int _currentGoldValue; - - int _points; - - int _reqState; - - int _reqState2; - - AITypeInt _aiType; - - AITargetChoiceInt _targetChoiceType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - _selectedPlayer = 0; + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + int _selectedPlayer = 0; if (_aiType != OpenSHC::AI::AIT_NULL) { - - fromXPosition = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; - - fromYPosition = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; - - _lowestDistance = 10000; - - _highestGold = 0; - - _lowestPoints = 1000000; + int fromXPosition = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; + int fromYPosition = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; + int _lowestDistance = 10000; + int _highestGold = 0; + int _lowestPoints = 1000000; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeNervousness, this)(playerID); - _reqState = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; - + int _reqState = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; if (((_reqState == 2) || (_reqState == 1)) - && (iVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), - iVar1 == 0)) { - + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) == 0) { DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; } - _reqState2 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; - + int _reqState2 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; if (_reqState2 == 2) { - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = 0; - return; } - if (_reqState2 == 1) { - - _alive1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk); - - if (_alive1 != 0) { - + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk) != 0) { DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk; - return; } - DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; } - _pPlayerData2 = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); - - _iPlayer = 1; + PlayerData* _pPlayerData2 = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); + int _iPlayer = 1; do { - if ((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) - && (_isLordAlive = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_iPlayer), - _isLordAlive != 0)) { - - /* - fixme:improve: use pythagoras */ + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_iPlayer) != 0) { MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, DAT_DirectionAlgorithmState::ptr)((_pPlayerData2->campground).xEntry, (_pPlayerData2->campground).yEntry, fromXPosition, fromYPosition); - _targetChoiceType = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].TargetChoice; - - _currentGoldValue = _highestGold; - - _points = _lowestPoints; + AITargetChoiceInt _targetChoiceType = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].TargetChoice; + int _currentGoldValue = _highestGold; + int _points = _lowestPoints; if (_targetChoiceType == OpenSHC::AI::AIC::AITC_PLAYER) { - if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_iPlayer] != -1) { - - LAB_004d47c5: if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance) { - _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; - - LAB_004d4845: _lowestPoints = _points; - _highestGold = _currentGoldValue; - _selectedPlayer = _iPlayer; } } - - } - - else { - - if (_targetChoiceType == OpenSHC::AI::AIC::AITC_CLOSEST) - goto LAB_004d47c5; - - if (_targetChoiceType == OpenSHC::AI::AIC::AITC_GOLD) { - - _currentGoldValue = _pPlayerData2->currentResources[0xf]; - - if (_highestGold <= _pPlayerData2->currentResources[0xf]) - goto LAB_004d4845; - + } else if (_targetChoiceType == OpenSHC::AI::AIC::AITC_CLOSEST) { + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance) { + _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + _lowestPoints = _points; + _highestGold = _currentGoldValue; + _selectedPlayer = _iPlayer; + } + } else if (_targetChoiceType == OpenSHC::AI::AIC::AITC_GOLD) { + _currentGoldValue = _pPlayerData2->currentResources[0xf]; + if (_highestGold <= _pPlayerData2->currentResources[0xf]) { + _lowestPoints = _points; + _highestGold = _currentGoldValue; + _selectedPlayer = _iPlayer; + } + } else if (_targetChoiceType == OpenSHC::AI::AIC::AITC_BALANCED) { + _points = _pPlayerData2->currentPopulation * 5 + _pPlayerData2->totalTroopValue + + _pPlayerData2->currentResources[0xf] / 100 + + DAT_DirectionAlgorithmState::instance.distanceHigh * 2; + if (_points <= _lowestPoints) { + _lowestPoints = _points; + _highestGold = _currentGoldValue; + _selectedPlayer = _iPlayer; } - - else if ((_targetChoiceType == OpenSHC::AI::AIC::AITC_BALANCED) - && (_points = _pPlayerData2->currentPopulation * 5 + _pPlayerData2->totalTroopValue - + _pPlayerData2->currentResources[0xf] / 100 - + DAT_DirectionAlgorithmState::instance.distanceHigh * 2, - _points <= _lowestPoints)) - goto LAB_004d4845; } } _iPlayer = _iPlayer + 1; - - _pPlayerData2 = _pPlayerData2 + 0x39f4; - + _pPlayerData2 = _pPlayerData2 + 0xe7d; } while (_iPlayer < 9); if (_selectedPlayer == 0) { - - _iPlayer2 = 1; - - _ptrPlayerData = &DAT_GameState::instance.playerDataArray[1]; - + int _iPlayer2 = 1; + PlayerData* _ptrPlayerData = &DAT_GameState::instance.playerDataArray[1]; do { - if (((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer2] != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) - && (_lord = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_iPlayer2), - _lord != 0)) + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_iPlayer2) != 0) && (MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, (_ptrPlayerData->campground).yEntry, fromXPosition, fromYPosition), DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance)) { - _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; - _selectedPlayer = _iPlayer2; } - _iPlayer2 = _iPlayer2 + 1; - - /* - next player */ - _ptrPlayerData = _ptrPlayerData + 0xe7d; - } while (_iPlayer2 < 9); - if (_selectedPlayer == 0) { - + if (_selectedPlayer == 0) return; - } } DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk = _selectedPlayer; - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = _selectedPlayer; } - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp index 412497ce2..f4283f86e 100644 --- a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -21,46 +21,21 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D1D60 void AICState ::sellExcessGoods(int param_1) - { - - AITypeInt AVar1; - - ResourceType resourceType; - - AIResourceTradeCategoryInt AVar2; - - int iVar3; - - uint uVar4; - - int iVar5; - - int iVar6; - - ResourceType* pRVar7; - - AIResourceTradeCategoryInt* local_18; - - AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) { + AITypeInt AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; + if (AVar1 == OpenSHC::AI::AIT_NULL) return; - } - iVar3 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - - local_18 = &DAT_SkirmishDefinedData::instance.DAT_AIResourceTradeAICMapping[0].aic; + int iVar3 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + AIResourceTradeCategoryInt* local_18 = &DAT_SkirmishDefinedData::instance.DAT_AIResourceTradeAICMapping[0].aic; do { - - resourceType + ResourceType resourceType = (OpenSHC::Game::Resources::ResourceType)((ResourceAICResourceMappingEntry*)(local_18 + -1))->game; + AIResourceTradeCategoryInt AVar2 = *local_18; - AVar2 = *local_18; - - iVar6 = *(int*)((int)this + iVar3 + 0xc0); - + int iVar6 = *(int*)((int)this + iVar3 + 0xc0); + int iVar5; if (AVar2 == OpenSHC::AI::Trading::AIRTC_WOOD) { iVar5 = *(int*)((int)this + iVar3 + 0xac); } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { @@ -75,73 +50,62 @@ namespace AI { iVar5 = *(int*)((int)this + iVar3 + 0xb4); } - uVar4 = iVar5 + iVar6; + uint uVar4 = iVar5 + iVar6; if ((DAT_GameState::instance.playerDataArray[param_1].aiNervousActionsTracker <= 0) || (DAT_GameState::instance.playerDataArray[param_1].currentResources[0xf] >= 0x1f4)) { if (DAT_GameState::instance.playerDataArray[param_1].popularity < *(int*)((int)this + iVar3 + 0x18)) { - if (AVar2 != OpenSHC::AI::Trading::AIRTC_FOOD) { - if (AVar2 == OpenSHC::AI::Trading::AIRTC_WEAPONS) { uVar4 = 0; iVar6 = 0; - goto LAB_004d1e81; + } else { + uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; + iVar6 = 0; } - - uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; + } else { + iVar6 = 0; } - - iVar6 = 0; - } else { uVar4 = uVar4 + DAT_GameState::instance.playerDataArray[param_1].resourcesToAcquireArray[resourceType]; } } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { - uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; iVar6 = 0; - } else { - uVar4 = (AVar2 != OpenSHC::AI::Trading::AIRTC_WEAPONS) - 1 & 10000; iVar6 = 0; } - LAB_004d1e81: - iVar5 = 0; - - pRVar7 = (ResourceType*)((int)this + iVar3 + 0xd4); - - do { - if (resourceType == *pRVar7) { - uVar4 = 0; - iVar6 = 0; - break; - } - iVar5 = iVar5 + 1; - pRVar7 = pRVar7 + 1; - } while (iVar5 < 0xf); + // Check no-sell list (was LAB_004d1e81) + { + int iVar5_2 = 0; + ResourceType* pRVar7 = (ResourceType*)((int)this + iVar3 + 0xd4); + do { + if (resourceType == *pRVar7) { + uVar4 = 0; + iVar6 = 0; + break; + } + iVar5_2 = iVar5_2 + 1; + pRVar7 = pRVar7 + 1; + } while (iVar5_2 < 0xf); + } if ((int)uVar4 < DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType]) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellGoods, this)(param_1, resourceType, (DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType] - uVar4) + iVar6); - return; } local_18 = local_18 + 2; - - if (0xb4252b < (int)local_18) { + if (0xb4252b < (int)local_18) return; - } } while (true); } - } } diff --git a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp index 3cd363930..73e501ba0 100644 --- a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp @@ -13,78 +13,38 @@ namespace AI { using OpenSHC::AI::AIVUnitType; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - [doc] - @param slotIndex int slotIndex to browse to - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D2E00 void AICState ::sendTribeToAIVLocationSlot(int tribeID, AIVUnitType aivUnitType, int slotIndex) - { + int _owner = DAT_TribesState::instance.tribes[tribeID].owner; + int _tile = 0; + int _slotIndex = 0; + int* _ptrSlot = (int*)(_owner * 0x39f4 + 0x115eb14 + aivUnitType * 0x28); - int _slotIndex; - - BOOLEnum _canNavigate; - - int* _ptrSlot; - - int _tile; - - int _x; - - int _owner; - - short _y; - - /* - all experimental, heavy local reuse... */ - - _owner = DAT_TribesState::instance.tribes[tribeID].owner; - - _tile = 0; - - _slotIndex = 0; - - /* - aivUnitLocationSlots */ - - _ptrSlot = (int*)(_owner * 0x39f4 + 0x115eb14 + aivUnitType * 0x28); - - while ((*_ptrSlot == 0 || (slotIndex = slotIndex + -1, -1 < slotIndex))) { - + // Find the slot at slotIndex, skipping empty entries + while (*_ptrSlot == 0 || (slotIndex = slotIndex + -1, -1 < slotIndex)) { _slotIndex = _slotIndex + 1; - _ptrSlot = _ptrSlot + 1; + if (9 < _slotIndex) + break; + } - if (9 < _slotIndex) { - - LAB_004d2e6d: - _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; - - _x = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; - - _canNavigate = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, _tile); - - if (_canNavigate == FALSE) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, _owner); + if (_slotIndex <= 9) + _tile = DAT_GameState::instance.playerDataArray[_owner].aivUnitLocationSlots[aivUnitType][_slotIndex]; - return; - } + short _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + int _x = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( - tribeID, (uint)((int)(_tile - _x)), (uint)((int)((int)_y)), 0); + BOOLEnum _canNavigate = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, _tile); - return; - } + if (_canNavigate == FALSE) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, _owner); + return; } - _tile = DAT_GameState::instance.playerDataArray[_owner].aivUnitLocationSlots[aivUnitType][_slotIndex]; - - goto LAB_004d2e6d; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + tribeID, (uint)((int)(_tile - _x)), (uint)((int)((int)_y)), 0); } - } } diff --git a/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp index 080fa0a94..3c35fb36f 100644 --- a/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp +++ b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp @@ -23,165 +23,121 @@ namespace AI { { - int _lord; + int _aiType = DAT_GameState::instance.playerDataArray[owner].aiType; - int _lordBackup; - - int _minDistance; - - int _distance; - - int _targetPlayer; - - PlayerData* _ptrPlayerData; - - int _playerID_backup; - - int _player; - - PlayerData* _ptrPlayerData_backup; - - int _maxGold; - - int _minPoints; - - int _aiType; - - int _gold; - - int _points; - - int _ownerKeepX; - - int _ownerKeepY; - - AITargetChoiceInt _targetChoice; - - _aiType = DAT_GameState::instance.playerDataArray[owner].aiType; - - _targetPlayer = 0; + int _targetPlayer = 0; if (_aiType != 0) { - _ownerKeepY = DAT_GameState::instance.playerDataArray[owner].campground.yEntry; - - _ownerKeepX = DAT_GameState::instance.playerDataArray[owner].campground.xEntry; - - _minDistance = 10000; - - _maxGold = 0; + int _ownerKeepY = DAT_GameState::instance.playerDataArray[owner].campground.yEntry; + int _ownerKeepX = DAT_GameState::instance.playerDataArray[owner].campground.xEntry; - _minPoints = 1000000; + int _minDistance = 10000; + int _maxGold = 0; + int _minPoints = 1000000; - _player = 1; - - _ptrPlayerData = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); + int _player = 1; + PlayerData* _ptrPlayerData = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); do { if ((DAT_GameState::instance.mapAndTime.playerTeams[_player] - != DAT_GameState::instance.mapAndTime.playerTeams[owner]) - && (_lord = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_player), - _lord != 0)) { - - MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, - DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, - (_ptrPlayerData->campground).yEntry, _ownerKeepX, _ownerKeepY); - - _targetChoice = this->aics[_aiType + -1].TargetChoice; + != DAT_GameState::instance.mapAndTime.playerTeams[owner])) { - _gold = _maxGold; + int _lord = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_player); - _points = _minPoints; + if (_lord != 0) { - if (_targetChoice == OpenSHC::AI::AIC::AITC_PLAYER) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, + (_ptrPlayerData->campground).yEntry, _ownerKeepX, _ownerKeepY); - if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_player] != -1) { + AITargetChoiceInt _targetChoice = this->aics[_aiType - 1].TargetChoice; - joined_r0x004cad9a: - _distance = DAT_DirectionAlgorithmState::instance.distanceHigh; + if (_targetChoice == OpenSHC::AI::AIC::AITC_PLAYER) { - if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _minDistance) { + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_player] != -1) { - LAB_004cadf6: - _minPoints = _points; + int _distance = DAT_DirectionAlgorithmState::instance.distanceHigh; + if (_distance <= _minDistance) { + _minDistance = _distance; + _targetPlayer = _player; + } + } - _maxGold = _gold; + } else if (_targetChoice == OpenSHC::AI::AIC::AITC_CLOSEST) { + int _distance = DAT_DirectionAlgorithmState::instance.distanceHigh; + if (_distance <= _minDistance) { _minDistance = _distance; - _targetPlayer = _player; } - } - - } - - else { - - if (_targetChoice == OpenSHC::AI::AIC::AITC_CLOSEST) - goto joined_r0x004cad9a; - _distance = _minDistance; + } else if (_targetChoice == OpenSHC::AI::AIC::AITC_GOLD) { - if (_targetChoice == OpenSHC::AI::AIC::AITC_GOLD) { - - _gold = _ptrPlayerData->currentResources[0xf]; + int _gold = _ptrPlayerData->currentResources[0xf]; + if (_maxGold <= _gold) { + _minDistance = _minDistance; + _maxGold = _gold; + _minPoints = _minPoints; + _targetPlayer = _player; + } - if (_maxGold <= _ptrPlayerData->currentResources[0xf]) - goto LAB_004cadf6; + } else if (_targetChoice == OpenSHC::AI::AIC::AITC_BALANCED) { + int _points = _ptrPlayerData->currentPopulation * 5 + + _ptrPlayerData->totalTroopValue + + _ptrPlayerData->currentResources[0xf] / 100 + + DAT_DirectionAlgorithmState::instance.distanceHigh * 2; + if (_points <= _minPoints) { + _minDistance = _minDistance; + _maxGold = _maxGold; + _minPoints = _points; + _targetPlayer = _player; + } } - - else if ((_targetChoice == OpenSHC::AI::AIC::AITC_BALANCED) - && (_points = _ptrPlayerData->currentPopulation * 5 + _ptrPlayerData->totalTroopValue - + _ptrPlayerData->currentResources[0xf] / 100 - + DAT_DirectionAlgorithmState::instance.distanceHigh * 2, - _points <= _minPoints)) - goto LAB_004cadf6; } } _player = _player + 1; - _ptrPlayerData = _ptrPlayerData + 1; } while (_player < 9); if (_targetPlayer == 0) { - _playerID_backup = 1; - - _ptrPlayerData_backup = &DAT_GameState::instance.playerDataArray[1]; + int _playerID_backup = 1; + PlayerData* _ptrPlayerData_backup = &DAT_GameState::instance.playerDataArray[1]; do { - if (((DAT_GameState::instance.mapAndTime.playerTeams[_playerID_backup] - != DAT_GameState::instance.mapAndTime.playerTeams[owner]) - && (_lordBackup - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_playerID_backup), - _lordBackup != 0)) - && (MACRO_CALL_MEMBER( + if ((DAT_GameState::instance.mapAndTime.playerTeams[_playerID_backup] + != DAT_GameState::instance.mapAndTime.playerTeams[owner])) { + + int _lordBackup = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_playerID_backup); + + if (_lordBackup != 0) { + + MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData_backup->campground).xEntry, - (_ptrPlayerData_backup->campground).yEntry, _ownerKeepX, _ownerKeepY), - DAT_DirectionAlgorithmState::instance.distanceHigh <= _minDistance)) { + (_ptrPlayerData_backup->campground).yEntry, _ownerKeepX, _ownerKeepY); - _minDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; - - _targetPlayer = _playerID_backup; + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _minDistance) { + _minDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + _targetPlayer = _playerID_backup; + } + } } _playerID_backup = _playerID_backup + 1; - _ptrPlayerData_backup = _ptrPlayerData_backup + 1; } while (_playerID_backup < 9); if (_targetPlayer == 0) { - return; } } diff --git a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp index f7b90a16b..2ce935755 100644 --- a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp +++ b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp @@ -22,130 +22,74 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CBE30 void AICState ::setupWorkshopProductionType(int playerID, int buildingID) - { + AITypeInt AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - AITypeInt AVar1; - - int _aiTypeMin1; - - ResourceTypeShort RVar2; - - BuildingTypeShort _buildingType; - - AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) { + if (AVar1 == OpenSHC::AI::AIT_NULL) return; - } - _buildingType = DAT_BuildingsState::instance.buildings[buildingID].buildingType; - - _aiTypeMin1 = AVar1 + ~OpenSHC::AI::AIT_NULL; - RVar2 = OpenSHC::Game::Resources::RT_SWORD; + BuildingTypeShort _buildingType = DAT_BuildingsState::instance.buildings[buildingID].buildingType; + int _aiTypeMin1 = AVar1 + ~OpenSHC::AI::AIT_NULL; if (_buildingType == OpenSHC::Map::Buildings::BT_BLACKSMITH) { - _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 200); - if (_aiTypeMin1 == -999) { - _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, OpenSHC::Map::Buildings::BT_BLACKSMITH); - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = (ResourceTypeShort)_aiTypeMin1; - + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)_aiTypeMin1; return; } - - RVar2 = OpenSHC::Game::Resources::RT_SWORD; - - if (_aiTypeMin1 == 0x16) - goto LAB_004cbf6a; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_MACE; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = OpenSHC::Game::Resources::RT_MACE; - + if (_aiTypeMin1 == 0x16) { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_SWORD; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_SWORD; + } else { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_MACE; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_MACE; + } return; } - // orig: cmp dx, 0xe; jne 0x5a (skip poleturner block to fletcher/end) - // poleturner falls through, fletcher and end are jumped to if (_buildingType == OpenSHC::Map::Buildings::BT_POLETURNER) { - _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 0xd0); - if (_aiTypeMin1 == -999) { - _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, OpenSHC::Map::Buildings::BT_POLETURNER); - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = (ResourceTypeShort)_aiTypeMin1; - + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)_aiTypeMin1; return; } - - RVar2 = OpenSHC::Game::Resources::RT_SPEAR; - - if (_aiTypeMin1 == 0x13) - goto LAB_004cbf6a; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_PIKE; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_PIKE; - + if (_aiTypeMin1 == 0x13) { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_SPEAR; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_SPEAR; + } else { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_PIKE; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_PIKE; + } return; } if (_buildingType == OpenSHC::Map::Buildings::BT_FLETCHER) { - _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 0xcc); - if (_aiTypeMin1 == -999) { - - _aiTypeMin1 - = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, - DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, - OpenSHC::Map::Buildings::BT_FLETCHER); - - DAT_BuildingsState::instance.buildings[buildingID].producedItemType - = (ResourceTypeShort)_aiTypeMin1; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = (ResourceTypeShort)_aiTypeMin1; - + _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, + DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, + OpenSHC::Map::Buildings::BT_FLETCHER); + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)_aiTypeMin1; return; } - - RVar2 = OpenSHC::Game::Resources::RT_BOW; - - if (_aiTypeMin1 == 0x11) - goto LAB_004cbf6a; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemType - = OpenSHC::Game::Resources::RT_CROSSBOW; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = OpenSHC::Game::Resources::RT_CROSSBOW; + if (_aiTypeMin1 == 0x11) { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_BOW; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_BOW; + } else { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_CROSSBOW; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_CROSSBOW; + } } - return; - - LAB_004cbf6a: - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = RVar2; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = RVar2; - return; } } diff --git a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp index d374436ea..c0e9f4f2a 100644 --- a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp +++ b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp @@ -15,27 +15,25 @@ namespace AI { BOOLEnum AICState::shouldDestroyWoodCutterUnk(int playerID) { int _hut; - if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) return FALSE; - } - if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 1) { + + if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0) { _hut = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT); } else { - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] < 0x15) { + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] <= 0x14) return FALSE; - } - if (DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 2) { + if (DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 2) return FALSE; - } - if (DAT_GameState::instance.playerDataArray[playerID].someCount10 < 25) { + if (DAT_GameState::instance.playerDataArray[playerID].someCount10 < 25) return FALSE; - } _hut = DAT_GameState::instance.playerDataArray[playerID].someCount11; } - if (_hut == 0) { + + if (_hut == 0) return FALSE; - } + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( (int)(short)DAT_BuildingsState::instance.buildings[_hut].x, (int)(short)DAT_BuildingsState::instance.buildings[_hut].y); diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp index 43483ef0a..4ba346293 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp @@ -9,18 +9,28 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB5B0 BOOLEnum AICState::shouldNotBeBuildingHovel(PlayerID playerID, Commands::CommandBuildingType param_2) { - if (param_2 == Commands::CBT_HOVEL) { - int const populationCap = DAT_GameState::instance.playerDataArray[playerID].populationCap; - if (12 < populationCap) { - if (((populationCap <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation) - && (DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants < 5)) - && (DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk < 5)) { - return DAT_GameState::instance.playerDataArray[playerID].popularity < 5000; - } - return TRUE; - } + if (param_2 != Commands::CBT_HOVEL) { + return FALSE; } - return FALSE; + + int const populationCap = DAT_GameState::instance.playerDataArray[playerID].populationCap; + if (populationCap <= 12) { + return FALSE; + } + + if (populationCap <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation) { + return TRUE; + } + + if (DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants >= 5) { + return TRUE; + } + + if (DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk >= 5) { + return TRUE; + } + + return DAT_GameState::instance.playerDataArray[playerID].popularity < 5000; } } } diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp index 52613f2ef..544c8e381 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp @@ -10,15 +10,20 @@ namespace AI { BOOLEnum AICState::shouldNotBuildMarketArmoryGranaryBarracksMercenarypost( int playerID, Commands::CommandBuildingType param_2) { - if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) { - if ((0 < DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker) - && (param_2 != Commands::CBT_MARKETPLACE)) { + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { + // nervous: reject market/mercenarypost/barracks/armory types + if (param_2 != Commands::CBT_MARKETPLACE + && param_2 != Commands::CBT_MERCENARYPOST + && param_2 != Commands::CBT_BARRACKS + && param_2 != Commands::CBT_ARMORY) { + return param_2 != Commands::CBT_GRANARY; + } + } else { + // not nervous: only reject if destroy tracker > 0 and not marketplace + if (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker > 0 + && param_2 != Commands::CBT_MARKETPLACE) { return param_2 != Commands::CBT_GRANARY; } - } else if ((((param_2 != Commands::CBT_MARKETPLACE) && (param_2 != Commands::CBT_MERCENARYPOST)) - && (param_2 != Commands::CBT_BARRACKS)) - && (param_2 != Commands::CBT_ARMORY)) { - return param_2 != Commands::CBT_GRANARY; } return FALSE; } diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp index e4b8ffcd5..086bf9485 100644 --- a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -35,7 +35,10 @@ namespace AI { != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7])) { _tribeID = MACRO_CALL_MEMBER( Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - goto LAB_004ccaae; + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[iVar3 + iVar7] = (short)_tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] + = DAT_TribesState::instance.tribes[_tribeID].uid; + return _tribeID; } short sVar1 = DAT_TribesState::instance.tribes[iVar5].size; if (sVar1 < sVar4) { @@ -48,7 +51,6 @@ namespace AI { } while (iVar7 < iVar6); iVar7 = local_c; if (_tribeID != 0) { - LAB_004ccaae: DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[iVar3 + iVar7] = (short)_tribeID; DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] = DAT_TribesState::instance.tribes[_tribeID].uid; diff --git a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp index 258a3215f..eda86856b 100644 --- a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp +++ b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp @@ -9,25 +9,17 @@ namespace AI { using OpenSHC::Game::Skirmish::SkirmishDefinedData; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CC8D0 undefined4 AICState ::unitIDIsRangedOrArmored(int unitID) { + int _unitType = (int)(short)DAT_UnitsState::instance.units[unitID].unitType; - SkirmishDefinedData* pSVar1; - - pSVar1 = DAT_SkirmishDefinedData::ptr; + SkirmishDefinedData* pSVar1 = DAT_SkirmishDefinedData::ptr; do { - - if (pSVar1->DAT_UnitTypes_RangedAndArmored[0] - == (int)(short)DAT_UnitsState::instance.units[unitID].unitType) { - + if (pSVar1->DAT_UnitTypes_RangedAndArmored[0] == _unitType) return (undefined4)(1); - } pSVar1 = (SkirmishDefinedData*)(pSVar1->DAT_UnitTypes_RangedAndArmored + 1); diff --git a/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp index 6946450dd..094883871 100644 --- a/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp +++ b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp @@ -16,149 +16,89 @@ namespace AI { using OpenSHC::AI::AITypeInt; using OpenSHC::Game::Player::PlayerData; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D53E0 - void AICState ::updateAIBehaviour() - + void AICState::updateAIBehaviour() { - - AITypeInt AVar1; - - PlayerData* _aiType; - - int _playerID; - if (DAT_GameState::instance.mapAndTime.dayTicks == 10) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeOutpostTribesAttack, this)(); } - _aiType = &DAT_GameState::instance.playerDataArray[1]; - - _playerID = 1; - - do { - - AVar1 = _aiType->aiType; - - if (((AVar1 != OpenSHC::AI::AIT_NULL) && (_aiType->playerDeathRelated == 0)) - && (_aiType->lordKilledByPlayerID == 0)) { - - if (DAT_GameState::instance.mapAndTime.dayTicks == _playerID) { - - if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieRangedUnits, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieMeleeUnits, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitUnits, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recruitHarrassingSiegeEngines, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignMoatDiggers, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCreateSiegeUnits, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineers, this)(_playerID); - } - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiBuyAndSellGoods, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiGiveRaidInstructions, this)(_playerID); + for (int _playerID = 1; _playerID < 9; _playerID++) { + // Compiler doesn't optimize it with ADJ() like it should, not sure why it doesn't do it. + PlayerData* const _pPlayerData = &DAT_GameState::instance.playerDataArray[_playerID]; + AITypeInt const _aiType = _pPlayerData->aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) + continue; + if (_pPlayerData->playerDeathRelated != 0) + continue; + if (_pPlayerData->lordKilledByPlayerID != 0) + continue; + + if (DAT_GameState::instance.mapAndTime.dayTicks == _playerID) { + if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieRangedUnits, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieMeleeUnits, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitUnits, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recruitHarrassingSiegeEngines, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignMoatDiggers, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCreateSiegeUnits, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineers, this)(_playerID); } + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiBuyAndSellGoods, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiGiveRaidInstructions, this)(_playerID); + } - if (DAT_GameState::instance.mapAndTime.weekTicks == _playerID) { - - if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineerForOilDuty, this)(_playerID); - } - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateTribeLocations, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIPlayerState, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiUpdateTaxesAndRations, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setFoodBuyPlan, this)(_playerID); - - if (DAT_GameState::instance.mapAndTime.monthTicks != _playerID) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 0); - } - - if (_aiType->aiRequestDelay != 0) { - - _aiType->aiRequestDelay = _aiType->aiRequestDelay + -1; - } - - if (_aiType->nervousBikCountdown != 0) { - - _aiType->nervousBikCountdown = _aiType->nervousBikCountdown + -1; - } - - if (_aiType->someAiCountdown3 != 0) { - - _aiType->someAiCountdown3 = _aiType->someAiCountdown3 + -1; - } - - if (_aiType->someAiCountdown4 != 0) { - - _aiType->someAiCountdown4 = _aiType->someAiCountdown4 + -1; - } - - if (_aiType->someAiCountdown5 != 0) { - - _aiType->someAiCountdown5 = _aiType->someAiCountdown5 + -1; - } - - if (_aiType->someAiCountdown6 != 0) { - - _aiType->someAiCountdown6 = _aiType->someAiCountdown6 + -1; - } + if (DAT_GameState::instance.mapAndTime.weekTicks == _playerID) { + if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineerForOilDuty, this)(_playerID); } + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateTribeLocations, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIPlayerState, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiUpdateTaxesAndRations, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setFoodBuyPlan, this)(_playerID); - if (DAT_GameState::instance.mapAndTime.monthTicks == _playerID) { - - MACRO_CALL_MEMBER( - OpenSHC::Map::TileMapState_Func::countMoatsOwnedByEachPlayer, DAT_TileMapState::ptr)(); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::instructTribe166ToMove, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToSortieUnits, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 1); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectAttackTarget, this)(_playerID); - - if (_aiType->aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_RAIDING) { - - _aiType->canStartSpending = 1; - - } - - else { - - /* - shouldSpend = recruitGoldTreshold < currentGold */ + if (DAT_GameState::instance.mapAndTime.monthTicks != _playerID) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 0); + } - _aiType->canStartSpending - = (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0xc4) - < _aiType->currentResources[0xf]); - } + if (_pPlayerData->aiRequestDelay != 0) { + _pPlayerData->aiRequestDelay -= 1; + } + if (_pPlayerData->nervousBikCountdown != 0) { + _pPlayerData->nervousBikCountdown -= 1; + } + if (_pPlayerData->someAiCountdown3 != 0) { + _pPlayerData->someAiCountdown3 -= 1; + } + if (_pPlayerData->someAiCountdown4 != 0) { + _pPlayerData->someAiCountdown4 -= 1; + } + if (_pPlayerData->someAiCountdown5 != 0) { + _pPlayerData->someAiCountdown5 -= 1; + } + if (_pPlayerData->someAiCountdown6 != 0) { + _pPlayerData->someAiCountdown6 -= 1; } } - _aiType = _aiType + 0xe7d; - - _playerID = _playerID + 1; - - } while ((int)_aiType < 0x117ea8c); - - return; + if (DAT_GameState::instance.mapAndTime.monthTicks == _playerID) { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::countMoatsOwnedByEachPlayer, DAT_TileMapState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::instructTribe166ToMove, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToSortieUnits, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 1); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectAttackTarget, this)(_playerID); + + if (_pPlayerData->aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_RAIDING) { + _pPlayerData->canStartSpending = 1; + } else { + // shouldSpend = recruitGoldThreshold < currentGold + _pPlayerData->canStartSpending = (uint)(((int)this->aics[_aiType - 1].recruitGoldThreshold) + < _pPlayerData->currentResources[0xf]); + } + } + } } } diff --git a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp index b864cfc3e..88a716c36 100644 --- a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp @@ -19,549 +19,285 @@ namespace AI { using OpenSHC::AI::AITypeInt; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + // Helper shared by state 4 (canNavigate==FALSE) and state 6 (canUnitsNavigate==FALSE) + static void recomputeAndReset(OpenSHC::AI::AICState* pThis, int playerID) + { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, pThis)(playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, pThis)(playerID); + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; + } // FUNCTION: STRONGHOLDCRUSADER 0x004D49E0 void AICState ::updateAIPlayerState(int playerID) - { - - short* psVar1; - - int* piVar2; - - short sVar3; - - AITypeInt AVar4; - - int _aiType; - - int iVar5; - - BOOLEnum _shouldAttack; - - int _attackedPlayerAlive; - - uint _rallyReady; - - BOOLEnum BVar6; - - int _aiPlayerState_2; - - int _aiPlayerState; - - int _playerID; - - AVar4 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar4 == OpenSHC::AI::AIT_NULL) { - + AITypeInt AVar4 = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (AVar4 == OpenSHC::AI::AIT_NULL) return; - } - _aiType = AVar4 + ~OpenSHC::AI::AIT_NULL; - - iVar5 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; + int _aiType = AVar4 + ~OpenSHC::AI::AIT_NULL; + int iVar5 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; if (((iVar5 != 1) && (iVar5 == 2)) && (iVar5 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), iVar5 != 0)) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToPlayerIDsKeepIfPossible, this)( playerID, (short*)((int)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk))); - return; } - _aiPlayerState = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; + int _aiPlayerState = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; if (_aiPlayerState == 0) { - - _shouldAttack = MACRO_CALL_MEMBER( + BOOLEnum _shouldAttack = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::aiShouldAttackOrWaitForTeamCoordination, this)(playerID); - if (_shouldAttack == FALSE) { - - /* - Send own units back to keep or campfire */ - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRetreatUnits, this)((short*)playerID); - return; } - - /* - proceedwithattack */ - DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 1; - DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue = 0; - DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience = 0; - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackCoordinationLevel, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackStrength, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackRaidParameter, this)(playerID); - - piVar2 = (int*)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID * 0x39f4 + 0x115e9d4 - + playerID * 0x20); - + int* piVar2 = (int*)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID * 0x39f4 + + 0x115e9d4 + playerID * 0x20); *piVar2 = *piVar2 + 1; - - } - - else { - - BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID); - + } else { + BOOLEnum BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID); if ((((BVar6 != FALSE) && (_aiPlayerState != 9)) || ((0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker && (_aiPlayerState < 6)))) - || (199 < DAT_GameState::instance.playerDataArray[playerID].attackTicker)) { - + || (199 < DAT_GameState::instance.playerDataArray[playerID].attackTicker)) DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 8; - } } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); - _attackedPlayerAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + int _attackedPlayerAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); if (_attackedPlayerAlive == 0) { - - /* - attacked player is dead */ - iVar5 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; - if (iVar5 < 4) { - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - - MACRO_CALL_MEMBER( - OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)( DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( - playerID); - - } - - else if (iVar5 < 7) { - + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)(playerID); + } else if (iVar5 < 7) { DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 7; } } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearOutdatedAITribes, this)(playerID); - _aiPlayerState_2 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; - - if (_aiPlayerState_2 != 1) { - - if (_aiPlayerState_2 == 2) { - - /* - the general state means to be attacking */ - - _rallyReady - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID); - - if (_rallyReady == 0) { - - return; - } - - /* - send the attacking units to move closer */ - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 3; - - MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setNextMoveLocationForUnits, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToAttackTribes, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0xe_toPlaceTunnels, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)( - playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playTauntToAttackedPlayerBikFromPlayer, this)(playerID); + int _aiPlayerState_2 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; + BOOLEnum BVar6; + int* piVar2; + if (_aiPlayerState_2 == 1) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recreateEngineersTribe, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::initializeGatePathfindingForOwner, + DAT_BuildingsState::ptr)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeEnemyKeepApproachTile, this)(playerID); + if (0 < DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackTribesToLocations, this)((short*)playerID); return; } + // state 1 with no path: reset to 0 + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + return; + } - if (_aiPlayerState_2 == 3) { - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - - /* - send the attacking units closer to the castle */ - - *piVar2 = *piVar2 + 1; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); - - BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::processAttForceRallyPercentage, this)(playerID); - - if (BVar6 == FALSE) { - - return; - } - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 4; + if (_aiPlayerState_2 == 2) { + uint _rallyReady = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID); + if (_rallyReady == 0) + return; + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 3; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers, + this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setNextMoveLocationForUnits, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToAttackTribes, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0xe_toPlaceTunnels, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playTauntToAttackedPlayerBikFromPlayer, this)(playerID); + return; + } - DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 0; + if (_aiPlayerState_2 == 3) { + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + *piVar2 = *piVar2 + 1; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::processAttForceRallyPercentage, this)(playerID); + if (BVar6 == FALSE) + return; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 4; + DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 0; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); + return; + } + if (_aiPlayerState_2 == 4) { + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + *piVar2 = *piVar2 + 1; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::countSiegeEngineUnits, this)(playerID); + if (iVar5 < 1) + DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 100; + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue; + *piVar2 = *piVar2 + 1; + if (DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue + <= *(int*)((int)this + _aiType * 0x2a4 + 0x208)) + return; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocationFullVolume, DAT_SFXState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, 0x14); + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + if (BVar6 == FALSE) { + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); - + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe11StandGroundToGate, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe13DefensiveWave, this)(playerID); + recomputeAndReset(this, playerID); return; } + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; + return; + } - if (_aiPlayerState_2 == 4) { - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - - *piVar2 = *piVar2 + 1; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); - - iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::countSiegeEngineUnits, this)(playerID); - - if (iVar5 < 1) { - - DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 100; - } - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue; - - *piVar2 = *piVar2 + 1; - - if (DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue - <= *(int*)((int)this + _aiType * 0x2a4 + 0x208)) { - - return; - } - + if (_aiPlayerState_2 == 5) { + if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + short* psVar1 = &DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; + *psVar1 = *psVar1 + 1; + short sVar3 = DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + *piVar2 = *piVar2 + 1; + DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; + if (3 < sVar3) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocationFullVolume, DAT_SFXState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, - DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, 0x14); - - BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - - if (BVar6 == FALSE) { - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe11StandGroundToGate, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe13DefensiveWave, this)(playerID); - - LAB_004d4ed3: - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); - - DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; - - return; - } - - } - - else { - - if (_aiPlayerState_2 != 5) { - - if (_aiPlayerState_2 == 6) { - - /* - Enemy castle breached! */ - - if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) { - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; - } - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - - *piVar2 = *piVar2 + 1; - - _playerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; - - DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; - - MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::calculateAttackVectorsToCampFireOfPlayer, - DAT_GameState::ptr)(_playerID); - - iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToAttackBreachedCastle, this)( - playerID); - - if (iVar5 != 0) { - - return; - } - - BVar6 = MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - - if (BVar6 != FALSE) { - - return; - } - - BVar6 - = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, - DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - - if (BVar6 != FALSE) { - - return; - } - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; - - goto LAB_004d4ed3; - } - - if (_aiPlayerState_2 == 7) { - - piVar2 - = &DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue; - - *piVar2 = *piVar2 + 1; - - if (DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue - <= *(int*)((int)this + _aiType * 0x2a4 + 0x20c)) { - - return; - } - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)( - playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( - playerID); - - return; - } - - if (_aiPlayerState_2 == 8) { - - /* - Retreat from attack. */ - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; - - DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)( - playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( - playerID); - - if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) { - - return; - } - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playAnger1BikFromPlayer, this)(playerID); - - return; - } - - if (_aiPlayerState_2 != 9) { - - return; - } - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - - *piVar2 = *piVar2 + 1; - - if (((DAT_GameState::instance.playerDataArray[playerID].attackTicker < 20) - && (BVar6 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::percentageNonMovingTribesGTEAICSpecified, this)( - playerID), - BVar6 == FALSE)) - && (BVar6 - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID), - BVar6 == FALSE)) { - - return; - } - - goto LAB_004d4ff7; - } - - /* - _aiPlayerState_2 is 5 (Attack walls) */ - - if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) { - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; - } - - psVar1 = &DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; - - *psVar1 = *psVar1 + 1; - - sVar3 = DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - - *piVar2 = *piVar2 + 1; - - DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; - - if (3 < sVar3) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandWallAssaultTribes, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); - - MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::setTribe0x11ToAggressiveAndAttackIfConditionMet, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setEightTribe0xc0TribesToAggressiveAndAttack, this)( - playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); - - DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)( - playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xCtoAggressiveAndAttack, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xbToAggressiveAndAttack, this)(playerID); - } - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); - - BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - - if ((BVar6 == FALSE) - && (BVar6 - = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, - DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID), - BVar6 == FALSE)) { - - return; - } + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandWallAssaultTribes, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0x11ToAggressiveAndAttackIfConditionMet, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setEightTribe0xc0TribesToAggressiveAndAttack, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xCtoAggressiveAndAttack, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xbToAggressiveAndAttack, this)(playerID); } - + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + if ((BVar6 == FALSE) + && (BVar6 = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID), + BVar6 == FALSE)) + return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; - return; } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recreateEngineersTribe, this)(playerID); - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 2; - - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::initializeGatePathfindingForOwner, - DAT_BuildingsState::ptr)(playerID); - - /* - computes the first siege location for units */ - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeEnemyKeepApproachTile, this)(playerID); - - if (0 < DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackTribesToLocations, this)((short*)playerID); + if (_aiPlayerState_2 == 6) { + if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + *piVar2 = *piVar2 + 1; + int _playerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::calculateAttackVectorsToCampFireOfPlayer, + DAT_GameState::ptr)(_playerID); + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToAttackBreachedCastle, this)(playerID); + if (iVar5 != 0) + return; + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + if (BVar6 != FALSE) + return; + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + if (BVar6 != FALSE) + return; + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; + recomputeAndReset(this, playerID); + return; + } + if (_aiPlayerState_2 == 7) { + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue; + *piVar2 = *piVar2 + 1; + if (DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue + <= *(int*)((int)this + _aiType * 0x2a4 + 0x20c)) + return; + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)(playerID); return; } - LAB_004d4ff7: - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + if (_aiPlayerState_2 == 8) { + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; + DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)(playerID); + if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) + return; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playAnger1BikFromPlayer, this)(playerID); + return; + } - return; + if (_aiPlayerState_2 == 9) { + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + *piVar2 = *piVar2 + 1; + if (((DAT_GameState::instance.playerDataArray[playerID].attackTicker < 20) + && (BVar6 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::percentageNonMovingTribesGTEAICSpecified, this)(playerID), + BVar6 == FALSE)) + && (BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID), + BVar6 == FALSE)) + return; + // was LAB_004d4ff7 + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + } } - } } diff --git a/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp index 22deecfe3..8ff7b1851 100644 --- a/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp @@ -23,561 +23,228 @@ namespace AI { using OpenSHC::Game::TrailType; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - this functions info is based on np123 - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D3320 void AICState ::updateAIStrengthState(int playerID, int aiRecruitUnitChoicePreference) - { - - int* piVar1; - - short* psVar2; - - int _totalTroopCount; - - int _aicOffset; - - int _rng; - - int _raidUnitCount; - - BOOLEnum _teamWeak; - - BOOLEnum _outOfSupplies2; - - BOOLEnum _teamWeak2; - - BOOLEnum _outOfSupplies; - - int _totalRecruitProb; - - bool bVar3; - - int _totalDefenseTroops; - - int _aiType; - - int _currentPopulation; - - int _totalFood; - - int _aiStrengthState; - - int _aiRecruitUnitChoiceState; - - int _subtraction; - - int _aiType_2; - - int _totalRaidTroops; - - int _defTotal; - - int _currentGold_2; - - int _aiNervousActionsTracker; - - AINervousDestroyBuildingCategoryInt _cat; - - int _aiNervousActionsTracker2; - - int _aiBuildingDestroyActionsTracker; - - int _currentGold; - - int _aiTypeMin1; - - AINervousDestroyBuildingCategory _cat2; - - int _recruitProbDefensive; - - int _recruitProbRaid; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - /* - is human */ - - if (_aiType == 0) { - + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == 0) return; - } if ((char)aiRecruitUnitChoicePreference == '\0') { - - if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) { - + if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) return; - } - - if (DAT_GameCore::instance.isSkirmishTrail != TRUE) { - + if (DAT_GameCore::instance.isSkirmishTrail != TRUE) return; - } - - if (DAT_GameCore::instance.currentTrailType != OpenSHC::Game::TT_EXTREME) { - + if (DAT_GameCore::instance.currentTrailType != OpenSHC::Game::TT_EXTREME) return; - } } - _aiTypeMin1 = _aiType + -1; - - _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; - + int _aiTypeMin1 = _aiType + -1; + int _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 0; - /* - check if current gold less than 200 */ - - if (_currentGold < 200) { - - DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 0; - - } - - else { - - /* - 2 if currentGold > 1999 else 1 */ - + if (_currentGold >= 200) DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = (1999 < _currentGold) + 1; - } - - _currentPopulation = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; + int _currentPopulation = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; if (15 < _currentPopulation) { - - /* - if currentPopulation more than 14 */ - - if (_currentPopulation < 40) { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - - /* - if currentPopulation less than 40 */ - + int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + if (_currentPopulation < 40) *piVar1 = *piVar1 + 1; - - } - - else { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - - /* - if current Population more than 40 */ - + else *piVar1 = *piVar1 + 2; - } } - /* - check if total food higher than 20 */ - - _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; - + int _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; if (20 < _totalFood) { - - if (_totalFood < 200) { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - + int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + if (_totalFood < 200) *piVar1 = *piVar1 + 1; - - } - - else { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - + else *piVar1 = *piVar1 + 2; - } } - _totalTroopCount = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + int _totalTroopCount = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk + DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; - - /* - check if troop strength above 7 */ - if (7 < _totalTroopCount) { - - /* - check if troop strength smaller than 40 */ - - if (_totalTroopCount < 40) { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - + int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + if (_totalTroopCount < 40) *piVar1 = *piVar1 + 2; - - } - - else { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - + else *piVar1 = *piVar1 + 4; - } } - _aiStrengthState = DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - - if (_aiStrengthState < 3) { - + int _aiStrengthState = DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + if (_aiStrengthState < 3) DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; - - } - - else if (_aiStrengthState < 8) { - + else if (_aiStrengthState < 8) DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_DEFAULT; - - } - - else { - + else DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_STRONG; - } if ((DAT_GameState::instance.playerDataArray[playerID].aivCurrentPauseIndex == 1) - && (0 < DAT_GameState::instance.playerDataArray[playerID].aivPauses[1])) { - - /* - if pausing at first pause - */ - + && (0 < DAT_GameState::instance.playerDataArray[playerID].aivPauses[1])) DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; - } - - /* - add the aiStrengthFeeling to (aiType * 169). The AI Personality struct is a - 169*4 long element of an array of 16 elements (all ai types, maybe more?) */ - - _aicOffset = DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + _aiTypeMin1 * 169; - - /* - fetch RecruitProbRaid for current aiType */ - _recruitProbRaid = *(int*)((int)this + _aicOffset * 4 + 0x134); + int _aicOffset = DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + _aiTypeMin1 * 169; + int _recruitProbRaid = *(int*)((int)this + _aicOffset * 4 + 0x134); + int _recruitProbDefensive = *(int*)((int)this + _aicOffset * 4 + 0x128); + int _totalRecruitProb = *(int*)((int)this + _aicOffset * 4 + 0x140) + _recruitProbRaid + _recruitProbDefensive; - /* - fetch RecruitProbDefensive */ - - _recruitProbDefensive = *(int*)((int)this + _aicOffset * 4 + 0x128); - - /* - add RecruitProbAttack to the other two probs */ - - _totalRecruitProb = *(int*)((int)this + _aicOffset * 4 + 0x140) + _recruitProbRaid + _recruitProbDefensive; - - /* - check if recruitProb = 0 */ + int _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_ATTACKING; + bool bVar3 = false; + int _subtraction = 0; + bool _needsCheck = false; if (_totalRecruitProb == 0) { - _aiRecruitUnitChoiceState = aiRecruitUnitChoicePreference; - if (aiRecruitUnitChoicePreference == 1) { - - LAB_004d34e9: - /* - WARNING: reused variable _aiType */ - - _raidUnitCount = MACRO_CALL_MEMBER( + int _raidUnitCount = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(_aiTypeMin1, playerID); - - _totalDefenseTroops = DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk; - - bVar3 = (_totalDefenseTroops < _raidUnitCount); - - _subtraction = _totalDefenseTroops - _raidUnitCount; - - goto LAB_004d3515; + int _totalDefTroops = DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk; + bVar3 = (_totalDefTroops < _raidUnitCount); + _subtraction = _totalDefTroops - _raidUnitCount; + _needsCheck = true; + } else if (aiRecruitUnitChoicePreference == 0) { + int _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; + int _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); + bVar3 = (_totalRaidTroops < _defTotal); + _subtraction = _totalRaidTroops - _defTotal; + _needsCheck = true; } - - if (aiRecruitUnitChoicePreference == 0) - goto LAB_004d3502; - - } - - else { - - _rng = (int)SEC_RNG::instance.currentNumber2; - - /* - WARNING: prob is now randomized */ - + } else { + int _rng = (int)SEC_RNG::instance.currentNumber2; MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - /* - if DAT_01fe7da8 < 4800 */ - if ((int)DAT_GameCore::instance.mapTimeInTicks < 4800) { - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - - LAB_004d3502: - _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; - - /* - true if param1 > param0 */ - - _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); - + int _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; + int _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); bVar3 = (_totalRaidTroops < _defTotal); - _subtraction = _totalRaidTroops - _defTotal; - - LAB_004d3515: - if (bVar3 != _subtraction < 0) - goto LAB_004d351c; - - } - - else { - - /* - if RecruitProbDefensive > RandomizedRecruitProb */ - - if (_rng % _totalRecruitProb < _recruitProbDefensive) { - - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - - goto LAB_004d3502; - } - - if (_rng % _totalRecruitProb < _recruitProbRaid + _recruitProbDefensive) { - - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_RAIDING; - - goto LAB_004d34e9; - } + _needsCheck = true; + } else if (_rng % _totalRecruitProb < _recruitProbDefensive) { + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; + int _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; + int _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); + bVar3 = (_totalRaidTroops < _defTotal); + _subtraction = _totalRaidTroops - _defTotal; + _needsCheck = true; + } else if (_rng % _totalRecruitProb < _recruitProbRaid + _recruitProbDefensive) { + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_RAIDING; + int _raidUnitCount = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(_aiTypeMin1, playerID); + int _totalDefTroops = DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk; + bVar3 = (_totalDefTroops < _raidUnitCount); + _subtraction = _totalDefTroops - _raidUnitCount; + _needsCheck = true; } - - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_ATTACKING; } - LAB_004d351c: - if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState != _aiRecruitUnitChoiceState) { + if (!_needsCheck || !(bVar3 == (_subtraction < 0))) + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_ATTACKING; + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState != _aiRecruitUnitChoiceState) DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = _aiRecruitUnitChoiceState; - } - - if ((char)aiRecruitUnitChoicePreference == '\0') { + if ((char)aiRecruitUnitChoicePreference == '\0') return; - } if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) { - - _teamWeak = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, TRUE); - + BOOLEnum _teamWeak = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, TRUE); if (_teamWeak == FALSE) { - DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = 0; - return; } - - /* - WARNING: aiType now means currentGold */ - - _currentGold_2 = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; - + int _currentGold_2 = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; - DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - /* - if gold <= 500 */ - if (_currentGold_2 < 500) { - - _aiNervousActionsTracker = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; - - if (_aiNervousActionsTracker < 8) { - - /* - destroy a good or bad thing */ - + int _aiNervAct = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + if (_aiNervAct < 8) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( playerID, OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS); - - _cat = OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS; - - } - - else { - - if (5 < _aiNervousActionsTracker) - goto LAB_004d35fb; - - /* - fixme: does this line ever happen? */ - - _cat = OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); + } else if (!(5 < _aiNervAct)) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); } - - /* - destroy a workshop (2) or a resource building (iron mine... bakery) (6) */ - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, (AINervousDestroyBuildingCategory)((int)(_cat))); - - } - - else { - - /* - if gold > 2500 and... */ - - if (((2500 < _currentGold_2) - && (psVar2 = &DAT_GameState::instance.playerDataArray[playerID].aiStateCounter, - *psVar2 = *psVar2 + 1, - (DAT_GameState::instance.playerDataArray[playerID].aiStateCounter & 1U) != 0)) + } else { + short* psVar2 = &DAT_GameState::instance.playerDataArray[playerID].aiStateCounter; + *psVar2 = *psVar2 + 1; + if ((2500 < _currentGold_2) + && ((DAT_GameState::instance.playerDataArray[playerID].aiStateCounter & 1U) != 0) && (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 20)) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::shareGoldAmongTeamMembers, this)( playerID, _currentGold_2 / 10); } } - LAB_004d35fb: - _aiNervousActionsTracker2 = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; - - if (_aiNervousActionsTracker2 < 2) { - + int _aiNervAct2 = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + if (_aiNervAct2 < 2) return; - } - - DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = _aiNervousActionsTracker2 + -1; - + DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = _aiNervAct2 + -1; return; } - /* - ********************************************************* - * From here on we process logic for destroying buildings - ********************************************************* */ - - _aiBuildingDestroyActionsTracker - = DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; - - if (_aiBuildingDestroyActionsTracker < 1) { - - _teamWeak2 - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, FALSE); + int _aiBuildDestroyTracker = DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + if (_aiBuildDestroyTracker < 1) { + BOOLEnum _teamWeak2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, FALSE); if (_teamWeak2 != FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playNervous2BikFromPlayer, this)(playerID); - DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = 8; - DAT_GameState::instance.playerDataArray[playerID].aiStateCounter = 0; - return; } - - _outOfSupplies = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); - - if (_outOfSupplies == FALSE) { - + BOOLEnum _outOfSupplies = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); + if (_outOfSupplies == FALSE) return; - } - DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 8; - return; } - _outOfSupplies2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); - + BOOLEnum _outOfSupplies2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); if (_outOfSupplies2 == FALSE) { - DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 0; - return; } DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] = 20; - DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; - DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - if (_aiBuildingDestroyActionsTracker == 8) { - - _cat2 = OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS; - - } - - else { - - if (_aiBuildingDestroyActionsTracker == 7) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; - - *piVar1 = *piVar1 + -1; - - return; - } - - if (_aiBuildingDestroyActionsTracker == 6) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_GATEHOUSES_TOWERS_GUILDS); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_BARRACKS_MERCPOST_STABLES); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_WATER_BUILDINGS); - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; - - *piVar1 = *piVar1 + -1; - - return; - } - - if (_aiBuildingDestroyActionsTracker == 5) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; - - *piVar1 = *piVar1 + -1; - - return; - } - - if (_aiBuildingDestroyActionsTracker != 4) - goto LAB_004d3707; - - _cat2 = OpenSHC::AI::AINDBC_FARMS; + if (_aiBuildDestroyTracker == 8) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS); + } else if (_aiBuildDestroyTracker == 7) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; + return; + } else if (_aiBuildDestroyTracker == 6) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_GATEHOUSES_TOWERS_GUILDS); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_BARRACKS_MERCPOST_STABLES); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WATER_BUILDINGS); + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; + return; + } else if (_aiBuildDestroyTracker == 5) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; + return; + } else if (_aiBuildDestroyTracker == 4) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_FARMS); } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)(playerID, _cat2); - - LAB_004d3707: - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; - - *piVar1 = *piVar1 + -1; - - return; + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; } - } } diff --git a/src/OpenSHC/AI/AICState/updateTribeLocations.cpp b/src/OpenSHC/AI/AICState/updateTribeLocations.cpp index 65cc46e7b..d84f52f91 100644 --- a/src/OpenSHC/AI/AICState/updateTribeLocations.cpp +++ b/src/OpenSHC/AI/AICState/updateTribeLocations.cpp @@ -11,36 +11,25 @@ namespace AI { using OpenSHC::AI::AIType; using OpenSHC::AI::AITypeInt; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D4940 void AICState ::updateTribeLocations(int playerID) { - int* piVar1; - AITypeInt AVar2; AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiType; if (AVar2 != OpenSHC::AI::AIT_NULL) { - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter; - - *piVar1 = *piVar1 + 1; - - /* - defWallPatrolRallyTime - */ - - if (*(int*)((int)DAT_EntityState::instance.seagullArray + AVar2 * 0x2a4 + 0x2580) - <= DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter) { + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter = + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter + 1; - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits; + if (DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter + >= *(int*)((int)this + AVar2 * 0x2a4 - 0x194)) { - *piVar1 = *piVar1 + 1; + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits = + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits + 1; DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter = 0; } From dd6fa4527a6c18b6401f1349e08a2d6035e5d63b Mon Sep 17 00:00:00 2001 From: sourcehold Date: Tue, 28 Jul 2026 22:59:25 +0200 Subject: [PATCH 011/242] param change --- src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 11 ++-- .../AICState/moveAttackTribesToLocations.cpp | 10 ++-- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 11 ++-- .../AI/AICState/updateAIPlayerState.cpp | 56 ++++++++++--------- 4 files changed, 47 insertions(+), 41 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp index d2308602d..68d583f0e 100644 --- a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -21,7 +21,7 @@ namespace AI { decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CE4D0 - void AICState ::aiRetreatUnits(short* playerID) + void AICState ::aiRetreatUnits(int playerID) { @@ -37,7 +37,7 @@ namespace AI { int _groupCount; - short* _playerID; + int _playerID; _playerID = playerID; @@ -55,11 +55,12 @@ namespace AI { if (0 < _groupCount) { - playerID = DAT_GameState::instance.playerDataArray[(int)_playerID].aiTribeIDs + _aiBehaviourType; + short* __playerID + = DAT_GameState::instance.playerDataArray[(int)_playerID].aiTribeIDs + _aiBehaviourType; do { - _tribeID = (int)*playerID; + _tribeID = (int)*__playerID; if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid @@ -104,7 +105,7 @@ namespace AI { } } - playerID = playerID + 1; + __playerID = __playerID + 1; _counter = _counter + 1; diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp index 46999d708..69cfc4111 100644 --- a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -19,7 +19,7 @@ namespace AI { decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CE830 - void AICState ::moveAttackTribesToLocations(short* playerID) + void AICState ::moveAttackTribesToLocations(int playerID) { @@ -27,7 +27,7 @@ namespace AI { int iVar2; - short* psVar3; + int psVar3; int tribeID; @@ -55,11 +55,11 @@ namespace AI { if (0 < iVar1) { - playerID = DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeIDs + iVar2; + short* __playerID = DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeIDs + iVar2; do { - tribeID = (int)*playerID; + tribeID = (int)*__playerID; if ((tribeID != 0) && (DAT_TribesState::instance.tribes[tribeID].uid @@ -85,7 +85,7 @@ namespace AI { iVar4 = iVar4 + 1; } - playerID = playerID + 1; + __playerID = __playerID + 1; iVar5 = iVar5 + 1; diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index db61864a8..50779533e 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -23,7 +23,7 @@ namespace AI { decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CE5F0 - void AICState ::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, short* playerID2) + void AICState ::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, int playerID2) { @@ -49,7 +49,7 @@ namespace AI { uint _p1_keepCampfireY; - short* _playerID2; + int _playerID2; _playerID2 = playerID2; @@ -92,11 +92,12 @@ namespace AI { /* fixme: reused parameter */ - playerID2 = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _aiTribeBehaviourTypeOffset; + short* __playerID2 + = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _aiTribeBehaviourTypeOffset; do { - _tribeID = (int)*playerID2; + _tribeID = (int)*__playerID2; if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid @@ -147,7 +148,7 @@ namespace AI { } } - playerID2 = playerID2 + 1; + __playerID2 = __playerID2 + 1; _counter = _counter + 1; diff --git a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp index 88a716c36..607b9a752 100644 --- a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp @@ -20,7 +20,7 @@ namespace AI { using OpenSHC::WindowsHelper::Enums::BOOLEnum; // Helper shared by state 4 (canNavigate==FALSE) and state 6 (canUnitsNavigate==FALSE) - static void recomputeAndReset(OpenSHC::AI::AICState* pThis, int playerID) + __forceinline static void recomputeAndReset(OpenSHC::AI::AICState* pThis, int playerID) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, pThis)(playerID, 0); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, pThis)(playerID); @@ -63,8 +63,8 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackCoordinationLevel, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackStrength, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackRaidParameter, this)(playerID); - int* piVar2 = (int*)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID * 0x39f4 - + 0x115e9d4 + playerID * 0x20); + int* piVar2 = (int*)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID * 0x39f4 + 0x115e9d4 + + playerID * 0x20); *piVar2 = *piVar2 + 1; } else { BOOLEnum BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID); @@ -85,13 +85,14 @@ namespace AI { if (iVar5 < 4) { DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)( + MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( + playerID); } else if (iVar5 < 7) { DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 7; } @@ -119,13 +120,13 @@ namespace AI { } if (_aiPlayerState_2 == 2) { - uint _rallyReady = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID); + uint _rallyReady + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID); if (_rallyReady == 0) return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 3; - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers, - this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers, this)( + playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setNextMoveLocationForUnits, this)(playerID); @@ -167,7 +168,7 @@ namespace AI { piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue; *piVar2 = *piVar2 + 1; if (DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue - <= *(int*)((int)this + _aiType * 0x2a4 + 0x208)) + <= ((int)this->aics[_aiType].AttAssaultDelay)) return; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); @@ -181,7 +182,9 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe11StandGroundToGate, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe13DefensiveWave, this)(playerID); - recomputeAndReset(this, playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; return; } DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; @@ -202,11 +205,14 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandWallAssaultTribes, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0x11ToAggressiveAndAttackIfConditionMet, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setEightTribe0xc0TribesToAggressiveAndAttack, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0x11ToAggressiveAndAttackIfConditionMet, this)( + playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setEightTribe0xc0TribesToAggressiveAndAttack, this)( + playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)( + playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xCtoAggressiveAndAttack, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xbToAggressiveAndAttack, this)(playerID); @@ -216,9 +222,8 @@ namespace AI { DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); if ((BVar6 == FALSE) && (BVar6 = MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID, - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID), + OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID), BVar6 == FALSE)) return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; @@ -246,7 +251,9 @@ namespace AI { if (BVar6 != FALSE) return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; - recomputeAndReset(this, playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; return; } @@ -254,13 +261,12 @@ namespace AI { piVar2 = &DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue; *piVar2 = *piVar2 + 1; if (DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue - <= *(int*)((int)this + _aiType * 0x2a4 + 0x20c)) + <= ((int)this->aics[_aiType].AttUnitPatrolRecommandDelay)) return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); @@ -273,8 +279,7 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); @@ -286,8 +291,7 @@ namespace AI { } if (_aiPlayerState_2 == 9) { - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - *piVar2 = *piVar2 + 1; + DAT_GameState::instance.playerDataArray[playerID].attackTicker += 1; if (((DAT_GameState::instance.playerDataArray[playerID].attackTicker < 20) && (BVar6 = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::percentageNonMovingTribesGTEAICSpecified, this)(playerID), From 07f71d2c1eecaefdc7d42447c0d6c929d0871fa1 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 00:16:57 +0200 Subject: [PATCH 012/242] improvements --- src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 144 +++++------------ .../AICState/moveAttackTribesToLocations.cpp | 104 ++++-------- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 150 +++++------------- 3 files changed, 121 insertions(+), 277 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp index 68d583f0e..ba171bf29 100644 --- a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -2,7 +2,7 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" @@ -10,115 +10,59 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - doc:| - Retreat units to campfire or keep - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; // FUNCTION: STRONGHOLDCRUSADER 0x004CE4D0 - void AICState ::aiRetreatUnits(int playerID) - + void AICState::aiRetreatUnits(int playerID) { - - BOOLEnum BVar1; - - int _counter; - - int _tribeID; - - int* local_8; - - int _aiBehaviourType; - - int _groupCount; - - int _playerID; - - _playerID = playerID; - - if (DAT_GameState::instance.playerDataArray[(int)playerID].aiType != OpenSHC::AI::AIT_NULL) { - - local_8 = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; - - do { - - _groupCount = *local_8; - - _aiBehaviourType = (*(int (*)[2])(local_8 + -1))[0]; - - _counter = 0; - - if (0 < _groupCount) { - - short* __playerID - = DAT_GameState::instance.playerDataArray[(int)_playerID].aiTribeIDs + _aiBehaviourType; - - do { - - _tribeID = (int)*__playerID; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[(int)_playerID] - .aiTribeUIDs[_counter + _aiBehaviourType])) { - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - if (_aiBehaviourType == 0xbe) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, (int)((int)(_playerID))); - - } - - else if (_aiBehaviourType == 0xd) { - + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; + + for (int _index1 = 0; _index1 < 11; _index1++) { + int* _mappingPtr + = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[_index1] + 1; + int const _maxTribeCount = *_mappingPtr; + int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr - 1))[0]; + int _tribeIndex = 0; + + if (0 < _maxTribeCount) { + + for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { + int const _tribeID + = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart + _tribeIndex]; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + if (_tribeTypeStart == 0xbe) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID); + } else if (_tribeTypeStart == 0xd) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID); + } else { + int const _hasHorses + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + if (_hasHorses != FALSE) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, (int)((int)(_playerID))); - - } - - else { - - BVar1 - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, - DAT_TribesState::ptr)(_tribeID); - - if (BVar1 == FALSE) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( - _tribeID, (int)((int)(_playerID))); - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, (int)((int)(_playerID))); - } + _tribeID, playerID); + } else { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( + _tribeID, playerID); } } - - __playerID = __playerID + 1; - - _counter = _counter + 1; - - } while (_counter < _groupCount); + } } - - local_8 = local_8 + 2; - - } while ((int)local_8 < 0xb42a2c); + } } - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp index 69cfc4111..eaaa3fd90 100644 --- a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -15,89 +15,55 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CE830 - void AICState ::moveAttackTribesToLocations(int playerID) - + void AICState::moveAttackTribesToLocations(int playerID) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; - int iVar1; - - int iVar2; - - int psVar3; - - int tribeID; - - int iVar4; - - int iVar5; - - int* local_c; - - psVar3 = playerID; - - if (DAT_GameState::instance.playerDataArray[(int)playerID].aiType != OpenSHC::AI::AIT_NULL) { - - iVar4 = 0; + int _destIndex = 0; - local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + for (int _index = 0; _index < 11; _index++) { + int* _mappingPtr + = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[_index] + 1; - do { + int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr + -1))[0]; + int _tribeIndex = 0; + int const _maxTribeCount = *_mappingPtr; - iVar1 = *local_c; + if (0 < _maxTribeCount) { + short* _tribeIDPtr = &DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart]; - iVar2 = (*(int (*)[2])(local_c + -1))[0]; + do { + int const _tribeID = (int)*_tribeIDPtr; - iVar5 = 0; + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { - if (0 < iVar1) { + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - short* __playerID = DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeIDs + iVar2; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(_tribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] + .xOffset)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] + .yOffset)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - do { + _destIndex = _destIndex + 1; + } - tribeID = (int)*__playerID; + _tribeIDPtr = _tribeIDPtr + 1; + _tribeIndex = _tribeIndex + 1; - if ((tribeID != 0) - && (DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeUIDs[iVar5 + iVar2])) { - - DAT_TribesState::instance.tribes[tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - - /* - fixme: array too small? - */ - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(tribeID, - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[(int)psVar3 * 5][iVar4] - .xOffset)), - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[(int)psVar3 * 5][iVar4] - .yOffset)), - 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - - iVar4 = iVar4 + 1; - } - - __playerID = __playerID + 1; - - iVar5 = iVar5 + 1; - - } while (iVar5 < iVar1); - } - - local_c = local_c + 2; - - } while ((int)local_c < 0xb42a2c); + } while (_tribeIndex < _maxTribeCount); + } } - - return; } } diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index 50779533e..4c4593028 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -4,7 +4,6 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_PathFindingState.hpp" @@ -14,153 +13,88 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CE5F0 - void AICState ::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, int playerID2) - + void AICState::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, int playerID2) { + uint _p1_campfireX = DAT_GameState::instance.playerDataArray[playerID1].campground.xEntry; + uint _p1_campfireY = DAT_GameState::instance.playerDataArray[playerID1].campground.yEntry; - BOOLEnum BVar1; - - dword _gatehouseTile; - - int _tribeID; - - int _counter; - - int* local_10; - - uint _ghY; + int const _canNavigate = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID1, playerID2); uint _ghX; + uint _ghY; - int _maxTribeCount; - - int _p1_keepCampfireX; - - int _aiTribeBehaviourTypeOffset; - - uint _p1_keepCampfireY; - - int _playerID2; - - _playerID2 = playerID2; - - _p1_keepCampfireY = DAT_GameState::instance.playerDataArray[playerID1].campground.yEntry; - - _p1_keepCampfireX = DAT_GameState::instance.playerDataArray[playerID1].campground.xEntry; - - BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID1, (int)((int)(playerID2))); - - if (BVar1 == FALSE) { - - _gatehouseTile = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findOwnedGatehouse, - DAT_PathFindingState::ptr)((int)playerID2, (uint)((int)(_p1_keepCampfireX)), _p1_keepCampfireY); - + if (_canNavigate == FALSE) { + dword const _gatehouseTile + = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findOwnedGatehouse, + DAT_PathFindingState::ptr)(playerID2, _p1_campfireX, _p1_campfireY); if (_gatehouseTile == 0) { - DAT_GameState::instance.playerDataArray[playerID1].requestStateUnk = 0; - return; } - _ghY = (uint)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_gatehouseTile]; - _ghX = _gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[_ghY].addXgetTile; } - local_10 = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + int* _mappingPtr = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; do { - - _maxTribeCount = *local_10; - - _aiTribeBehaviourTypeOffset = (*(int (*)[2])(local_10 + -1))[0]; - - _counter = 0; + int const _maxTribeCount = *_mappingPtr; + int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr - 1))[0]; + int _tribeIndex = 0; if (0 < _maxTribeCount) { - - /* - fixme: reused parameter */ - - short* __playerID2 - = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _aiTribeBehaviourTypeOffset; + short* _tribeIDPtr = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _tribeTypeStart; do { - - _tribeID = (int)*__playerID2; + int const _tribeID = (int)*_tribeIDPtr; if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID1] - .aiTribeUIDs[_counter + _aiTribeBehaviourTypeOffset])) { + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID1, (int)((int)(_playerID2))); - - if (BVar1 == FALSE) { - - /* - send to enemy gate house */ + int const _canNav2 + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID1, playerID2); + if (_canNav2 != FALSE) { + if (_tribeTypeStart == 0xbe) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID2); + } else { + int const _hasHorses + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + if (_hasHorses != FALSE) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID2); + } else { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( + _tribeID, playerID2); + } + } + } else { MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( _tribeID, _ghX, _ghY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - - } - - else if (_aiTribeBehaviourTypeOffset == 0xbe) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, (int)((int)(_playerID2))); - - } - - else { - - BVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, - DAT_TribesState::ptr)(_tribeID); - - if (BVar1 == FALSE) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( - _tribeID, (int)((int)(_playerID2))); - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, (int)((int)(_playerID2))); - } } } - __playerID2 = __playerID2 + 1; - - _counter = _counter + 1; - - } while (_counter < _maxTribeCount); + _tribeIDPtr = _tribeIDPtr + 1; + _tribeIndex = _tribeIndex + 1; + } while (_tribeIndex < _maxTribeCount); } - local_10 = local_10 + 2; - - } while ((int)local_10 < 0xb42a2c); - - return; + _mappingPtr = _mappingPtr + 2; + } while ((int)_mappingPtr < 0xb42a2c); } - } } From c6d52820aebbb749fff9cc27b40df5371d83333b Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 11:22:09 +0200 Subject: [PATCH 013/242] field name updates --- .../addUnitToSmallestBehaviourTypeTribe.cpp | 2 +- .../aiChoiceAttForceRallyPercentage.cpp | 2 +- .../AI/AICState/aiCreateSiegeUnits.cpp | 267 +++++++++++++----- .../AI/AICState/aiGiveRaidInstructions.cpp | 69 +++-- src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 3 +- src/OpenSHC/AI/AICState/buyRequiredGoods.cpp | 2 +- ...mBuildingIDFromPlayersArrayOfBuildings.cpp | 13 +- .../AI/AICState/clearOutdatedAITribes.cpp | 6 +- .../clearRallyFlagOnAllAIAttackTribes.cpp | 3 +- ...ndAttackTribePositionAndPathToDefenses.cpp | 8 +- .../generateSiegeCreationInformation.cpp | 2 +- .../getTargetableBuildingForPlayerID.cpp | 2 +- .../giveMoveCommandToAttackTribes.cpp | 3 +- ...eUnitsGoDefensiveAndBackToSomeLocation.cpp | 2 +- .../AICState/moveAttackTribesToLocations.cpp | 3 +- ...rcentageNonMovingTribesGTEAICSpecified.cpp | 2 +- .../processAttForceRallyPercentage.cpp | 6 +- .../randomlySelectAttackUnitTypeToRecruit.cpp | 29 +- ...selectBuildingFromAListOfBuildingTypes.cpp | 2 +- src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 2 +- ...oAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp | 2 +- ...gedUnitTribesToAIVSlotsOrKeepIfNervous.cpp | 3 +- .../sendUnitsToAttackBreachedCastle.cpp | 3 +- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 2 +- ...sendWallPatrolUnitTribesToAIVLocations.cpp | 2 +- .../AI/AICState/smallestTribeOfUnitType.cpp | 2 +- .../AI/AICState/someChatMessageSelection.cpp | 12 +- .../AI/AICState/unitIDIsRangedOrArmored.cpp | 4 +- ...12_toPlaceSiegeTentsAndAssignEngineers.cpp | 12 +- 29 files changed, 307 insertions(+), 163 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp index 402f0e208..c26db36f6 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp @@ -19,7 +19,7 @@ namespace AI { return 0; } int _tribeTypeOffset - = DAT_SkirmishDefinedData::instance.DAT_AIUnitBehaviourTypeMapping[(int)aiUnitBehaviourType + -10]; + = DAT_SkirmishDefinedData::instance.AIUnitBehaviourTypeMapping[(int)aiUnitBehaviourType + -10]; int _smallestTribe = 0; int _smallestTribeOffset = 0; short _smallestTribeSize = 1000; diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp index 46b561d3c..165cf2937 100644 --- a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -45,7 +45,7 @@ namespace AI { local_10 = 0; - local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index 704837eaf..c5e339c24 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -58,8 +58,11 @@ namespace AI { int* _pDelay; do { - UnitType _unitType = *(UnitType*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].unitType + _mappingOffset); - int _tribeSize = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + _mappingOffset)]; + UnitType _unitType + = *(UnitType*)((int)&DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[0].unitType + + _mappingOffset); + int _tribeSize = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*( + int*)((int)&DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[0].slot + _mappingOffset)]; int _slotIndex = 0; int _nextSlotIndex; @@ -69,14 +72,22 @@ namespace AI { if (0 < _tribeSize) { do { _nextSlotIndex = _slotIndex + 1; - int _location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + _mappingOffset)][_slotIndex]; + int _location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[*( + int*)((int)&DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[0].slot + + _mappingOffset)][_slotIndex]; if (0 < _location) { int _existingBuildingID = (int)(short)DAT_TileMapState::instance.BuildingLayer[_location]; int _engineIndex = _incrementsBy5 + _slotIndex; - int _unitID = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID; - int _uid = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid; - int _tile = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID; + int _unitID = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID; + int _uid = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid; + int _tile = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID; if ((_unitID == 0) || (DAT_UnitsState::instance.units[_unitID].uid == _uid)) { if ((_tile == 0) || (DAT_BuildingsState::instance.buildings[_tile].uid == _uid)) { @@ -87,52 +98,124 @@ namespace AI { if (0x1f < _mappingOffset) _doPlace = true; } else if ((_mappingOffset < 0x20)) { - BuildingTypeShort _existingBuildingType = DAT_BuildingsState::instance.buildings[_existingBuildingID].buildingType; - if (_existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER4 || _existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER5) + BuildingTypeShort _existingBuildingType + = DAT_BuildingsState::instance.buildings[_existingBuildingID] + .buildingType; + if (_existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER4 + || _existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER5) _doPlace = true; } else { _doPlace = true; } if (_doPlace) { - int _requiredGold = DAT_BuildingsState::instance.buildingCosts[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].buildingType + _mappingOffset)].requiredGold; + int _requiredGold + = DAT_BuildingsState::instance + .buildingCosts[*(int*)((int)&DAT_SkirmishDefinedData::instance + .SiegeEngineMetaInfoArray[0] + .buildingType + + _mappingOffset)] + .requiredGold; int _aicOffset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - _pDelay = &DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay; + _pDelay = &DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay; *_pDelay = *_pDelay + 1; - if ((_requiredGold <= DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] + *(int*)((int)this + _aicOffset + 0x118)) - && (*(int*)((int)this + _aicOffset + 0x11c) <= DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay)) { - int _y = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_location]; - int _placeTile = _location - DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + if ((_requiredGold <= DAT_GameState::instance.playerDataArray[playerID] + .currentResources[0xf] + + *(int*)((int)this + _aicOffset + 0x118)) + && (*(int*)((int)this + _aicOffset + 0x11c) + <= DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay)) { + int _y = (int)DAT_ViewportRenderState::instance + .DAT_TileTranslationMatrix_YComponent[_location]; + int _placeTile = _location + - DAT_ViewportRenderState::instance.translationMatrix[_y] + .addXgetTile; if (_siegeInfoIndex < 2) { - int _spawnedUnit = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::spawnUnit, DAT_UnitsState::ptr)(playerID, playerID, _placeTile * 8 + 4, _y * 8 + 4, (int)((int)(DAT_BuildingsState::instance.buildings[_existingBuildingID].terrainHeightUnk)), _unitType); - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].unitID = _spawnedUnit; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].uid = DAT_UnitsState::instance.units[_spawnedUnit].uid; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].buildingID = 0; - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processPlacementResourceLossForBuildingType, DAT_BuildingsState::ptr)(playerID, (BuildingType)((int)(DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex].buildingType)), 0); + int _spawnedUnit = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::spawnUnit, + DAT_UnitsState::ptr)(playerID, playerID, _placeTile * 8 + 4, + _y * 8 + 4, + (int)((int)(DAT_BuildingsState::instance + .buildings[_existingBuildingID] + .terrainHeightUnk)), + _unitType); + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .unitID = _spawnedUnit; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .uid = DAT_UnitsState::instance.units[_spawnedUnit].uid; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .buildingID = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: + processPlacementResourceLossForBuildingType, + DAT_BuildingsState::ptr)(playerID, + (BuildingType)((int)(DAT_SkirmishDefinedData::instance + .SiegeEngineMetaInfoArray[_siegeInfoIndex] + .buildingType)), + 0); } else { - MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID, _placeTile, _y, (CommandBuildingType)((int)((uint)(ushort)(short)DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex].commandBuildingType)), 3, 0xf); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, + DAT_TileMapState::ptr)(playerID, _placeTile, _y, + (CommandBuildingType)(( + int)((uint)(ushort)(short)DAT_SkirmishDefinedData::instance + .SiegeEngineMetaInfoArray[_siegeInfoIndex] + .commandBuildingType)), + 3, 0xf); if (DAT_TileMapState::instance.buildingPlacementFail == FALSE) { - int* _pGold = DAT_GameState::instance.playerDataArray[playerID].currentResources + 0xf; + int* _pGold = DAT_GameState::instance.playerDataArray[playerID] + .currentResources + + 0xf; *_pGold = *_pGold - _requiredGold; - int _newBuildingID = DAT_TileMapState::instance.DAT_PlacedBuildingID; - int _newUID = DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.DAT_PlacedBuildingID].uid; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].unitID = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].uid = _newUID; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].buildingID = _newBuildingID; + int _newBuildingID + = DAT_TileMapState::instance.DAT_PlacedBuildingID; + int _newUID = DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance + .DAT_PlacedBuildingID] + .uid; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .unitID = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .uid = _newUID; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .buildingID = _newBuildingID; } } - *(undefined4*)(playerID * 0x39f4 + 0x115f48c + _slotIndex * 20 + _siegeInfoIndex * 100) = 0; + *(undefined4*)(playerID * 0x39f4 + 0x115f48c + _slotIndex * 20 + + _siegeInfoIndex * 100) = 0; return; } } } else { - int _requiredEngineerCount = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, DAT_BuildingsState::ptr)(_tile); - if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount != _requiredEngineerCount) { - if (_requiredEngineerCount <= DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { - int _engineersTribe = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _requiredEngineerCount); - DAT_TribesState::instance.tribes[_engineersTribe].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; - DAT_TribesState::instance.tribes[_engineersTribe].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(_engineersTribe, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); + int _requiredEngineerCount + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: + getRequiredEngineerCountForSiegeBuilding, + DAT_BuildingsState::ptr)(_tile); + if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount + != _requiredEngineerCount) { + if (_requiredEngineerCount + <= DAT_GameState::instance.playerDataArray[playerID] + .engineerCountRelated) { + int _engineersTribe = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, + this)(playerID, _requiredEngineerCount); + DAT_TribesState::instance.tribes[_engineersTribe].tribeType + = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_engineersTribe].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, + DAT_TribesState::ptr)(_engineersTribe, + OpenSHC::Map::Units:: + UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, + _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); return; } DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; @@ -140,33 +223,71 @@ namespace AI { } } else { if (_tile != 0) { - int _requiredEngineerCount2 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, DAT_BuildingsState::ptr)(_tile); - if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount != _requiredEngineerCount2) { - if (_requiredEngineerCount2 <= DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { - int _engineersTribe2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _requiredEngineerCount2); - DAT_TribesState::instance.tribes[_engineersTribe2].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; - DAT_TribesState::instance.tribes[_engineersTribe2].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(_engineersTribe2, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); + int _requiredEngineerCount2 + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: + getRequiredEngineerCountForSiegeBuilding, + DAT_BuildingsState::ptr)(_tile); + if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount + != _requiredEngineerCount2) { + if (_requiredEngineerCount2 + <= DAT_GameState::instance.playerDataArray[playerID] + .engineerCountRelated) { + int _engineersTribe2 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, + this)(playerID, _requiredEngineerCount2); + DAT_TribesState::instance.tribes[_engineersTribe2].tribeType + = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_engineersTribe2].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, + DAT_TribesState::ptr)(_engineersTribe2, + OpenSHC::Map::Units:: + UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, + _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); return; } DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; } } else { - int _remainingRequiredEngineers = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, DAT_UnitsState::ptr)(_unitID); + int _remainingRequiredEngineers = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, + DAT_UnitsState::ptr)(_unitID); if (0 < _remainingRequiredEngineers) { - if (DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated < _remainingRequiredEngineers) { - DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; + if (DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated + < _remainingRequiredEngineers) { + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired + = TRUE; } else { - int _tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _remainingRequiredEngineers); - int _targetUnitID = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; + int _tribeID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, + this)(playerID, _remainingRequiredEngineers); + int _targetUnitID = (int)DAT_TribesState::instance.tribes[_tribeID] + .selectionTargetUnitID; if ((_targetUnitID != 0) - && (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)(playerID, - (dword)((int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[_unitID].tile])), - (dword)((int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[_targetUnitID].tile])), - 0) != 0)) { - DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; - DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x41c; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(_tribeID, OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, _unitID, DAT_UnitsState::instance.units[_unitID].uid, 0); + && (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func:: + calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance + .units[_unitID] + .tile])), + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance + .units[_targetUnitID] + .tile])), + 0) + != 0)) { + DAT_TribesState::instance.tribes[_tribeID].tribeType + = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x41c; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, + DAT_UnitsState::ptr)(_tribeID, + OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, _unitID, + DAT_UnitsState::instance.units[_unitID].uid, 0); return; } } @@ -174,18 +295,38 @@ namespace AI { } } } else { - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unknown = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unknown = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID = 0; } } else { - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unknown = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unknown = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID = 0; } } diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp index 32b7b3685..f1a374dc6 100644 --- a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -45,21 +45,24 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = iVar4 + -1; } - // Helper: do the movement command given a tile - // (was shared LAB_004d2d8d block) - #define DO_MOVE_TO_TILE(_tile, _tribeID3) \ - do { \ - if ((_tile) != 0) { \ - short sVar2_ = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[(_tile)]; \ - int iVar4_ = DAT_ViewportRenderState::instance.translationMatrix[sVar2_].addXgetTile; \ - BOOLEnum BVar5_ = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)((_tribeID3), (_tile)); \ - if (BVar5_ == FALSE) { \ - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)((_tribeID3), playerID); \ - } else { \ - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)((_tribeID3), (uint)((int)((_tile) - iVar4_)), (uint)((int)((int)sVar2_)), 0); \ - } \ - } \ - } while(0) +// Helper: do the movement command given a tile +// (was shared LAB_004d2d8d block) +#define DO_MOVE_TO_TILE(_tile, _tribeID3) \ + do { \ + if ((_tile) != 0) { \ + short sVar2_ = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[(_tile)]; \ + int iVar4_ = DAT_ViewportRenderState::instance.translationMatrix[sVar2_].addXgetTile; \ + BOOLEnum BVar5_ = MACRO_CALL_MEMBER( \ + OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)((_tribeID3), (_tile)); \ + if (BVar5_ == FALSE) { \ + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)((_tribeID3), playerID); \ + } else { \ + MACRO_CALL_MEMBER( \ + OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( \ + (_tribeID3), (uint)((int)((_tile) - iVar4_)), (uint)((int)((int)sVar2_)), 0); \ + } \ + } \ + } while (0) short* _ptrTribeID3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xb4; @@ -77,7 +80,8 @@ namespace AI { if ((DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2) && (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) != 0)) { + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) + != 0)) { if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) { _buildingID_2 = MACRO_CALL_MEMBER( @@ -105,7 +109,8 @@ namespace AI { } } - } else if ((DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown == 0) + } else if ((DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + == 0) && (iVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(_aiType + -1, playerID), DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk < iVar4)) { @@ -130,7 +135,8 @@ namespace AI { _buildingID_2 = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); if (_buildingID_2 != 0) { - _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + _buildingTile + = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + DAT_ViewportRenderState::instance .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] .buildingEntryY] @@ -140,8 +146,8 @@ namespace AI { } } - } else if ((DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb6) - || (DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb5)) { + } else if ((DAT_SkirmishDefinedData::instance.TribeTypeID[_indexTo6] == 0xb6) + || (DAT_SkirmishDefinedData::instance.TribeTypeID[_indexTo6] == 0xb5)) { if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( @@ -155,8 +161,8 @@ namespace AI { if (_buildingID == 0) { _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, - this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); } if (_buildingID != 0) { @@ -170,8 +176,8 @@ namespace AI { } } else { - BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, FALSE); + BVar5 + = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID3, _indexTo6, FALSE); if (BVar5 == FALSE) { iVar4 = (int)DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID; if ((((iVar4 == 0) @@ -182,11 +188,12 @@ namespace AI { _tribeID3, _indexTo6, TRUE), BVar5 == FALSE)) { iVar4 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, - this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); if (iVar4 == 0) { DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + = 0; } else { MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(_tribeID3, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, iVar4, @@ -194,12 +201,14 @@ namespace AI { int iVar3 = DAT_BuildingsState::instance.buildings[iVar4].uid; DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = (short)iVar4; DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID = iVar3; - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 100; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + = 100; } } else { if (DAT_GameState::instance.mapAndTime.yearChanged != 0) DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 100; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + = 100; } } } @@ -209,7 +218,7 @@ namespace AI { _indexTo6 = _indexTo6 + TRUE; } while ((int)_indexTo6 < 6); - #undef DO_MOVE_TO_TILE +#undef DO_MOVE_TO_TILE } } } diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp index ba171bf29..810c29fce 100644 --- a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -21,8 +21,7 @@ namespace AI { return; for (int _index1 = 0; _index1 < 11; _index1++) { - int* _mappingPtr - = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[_index1] + 1; + int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index1] + 1; int const _maxTribeCount = *_mappingPtr; int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr - 1))[0]; int _tribeIndex = 0; diff --git a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp index 9a0ea9e4e..900f0e7ad 100644 --- a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp +++ b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp @@ -48,7 +48,7 @@ namespace AI { do { - resourceType = DAT_SkirmishDefinedData::instance.DAT_ResourceAcqusitionPreferenceOrder[param_1]; + resourceType = DAT_SkirmishDefinedData::instance.ResourceAcquisitionPreferenceOrder[param_1]; if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0) || (0xb < param_1)) { diff --git a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp index b180166d0..73e758d0c 100644 --- a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp +++ b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp @@ -38,19 +38,22 @@ namespace AI { if (0 < _chosenBuildingTypeIndex) { - BuildingTypeInt _buildingType = - (BuildingTypeInt)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType; + BuildingTypeInt _buildingType + = (BuildingTypeInt)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType; do { BuildingTypeInt _cmpType; if (_rng < 2) { - _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet3[_selectionIndex]; + _cmpType + = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet3[_selectionIndex]; } else if (_rng < 4) { - _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet2[_selectionIndex]; + _cmpType + = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet2[_selectionIndex]; } else { - _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_selectionIndex]; + _cmpType + = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1[_selectionIndex]; } if (_buildingType == _cmpType) { diff --git a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp index 91ef8a70c..86ca327e0 100644 --- a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp +++ b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp @@ -23,11 +23,9 @@ namespace AI { if (_index != 8) { - int _groupCount - = DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[_index][1]; + int _groupCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index][1]; - int _tribeType - = DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[_index][0]; + int _tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index][0]; int _offset = 0; diff --git a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp index 548106804..2cdeef7f8 100644 --- a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp @@ -33,8 +33,7 @@ namespace AI { if (DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) { - _ptrTribeCount - = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + _ptrTribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp index 2420b23f2..7059f8a9f 100644 --- a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -16,20 +16,20 @@ namespace AI { { uint local_8 = 0; uint local_4 = 0; - int* local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + int* local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; bool _found = false; do { int iVar2 = 0; if (0 < *local_c) { - short* psVar3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs - + (*(int (*)[2])(local_c + -1))[0]; + short* psVar3 + = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + (*(int (*)[2])(local_c + -1))[0]; do { int iVar1 = (int)*psVar3; if ((iVar1 != 0) && (DAT_TribesState::instance.tribes[iVar1].uid == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[iVar2 + (*(int (*)[2])(local_c + -1))[0]])) { + .aiTribeUIDs[iVar2 + (*(int (*)[2])(local_c + -1))[0]])) { iVar2 = (int)DAT_TribesState::instance.tribes[iVar1].selectionTargetUnitID; local_8 = (uint)DAT_UnitsState::instance.units[iVar2].x; local_4 = (uint)DAT_UnitsState::instance.units[iVar2].y; diff --git a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp index bc11333dd..1fddcaf46 100644 --- a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp +++ b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp @@ -55,7 +55,7 @@ namespace AI { _siegeIndex = 3; } - iVar2 = DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeIndex].slot; + iVar2 = DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[_siegeIndex].slot; _goal = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[iVar2]; diff --git a/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp index 5cb3f087a..cd9b3b5e1 100644 --- a/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp +++ b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp @@ -81,7 +81,7 @@ namespace AI { if (_candidateBuilding != 0) { - _pTargets = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1; + _pTargets = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1; do { diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp index b9bce3061..4e463ac1d 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp @@ -42,8 +42,7 @@ namespace AI { _counter = 0; - _ptrGroupCount - = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + _ptrGroupCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { diff --git a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp index 4c1c47ab2..7d2f22ddc 100644 --- a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp +++ b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp @@ -42,7 +42,7 @@ namespace AI { if ((DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) && (DAT_GameState::instance.playerDataArray[param_1].someTile != 0)) { - local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp index eaaa3fd90..4e4a6a0e2 100644 --- a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -24,8 +24,7 @@ namespace AI { int _destIndex = 0; for (int _index = 0; _index < 11; _index++) { - int* _mappingPtr - = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[_index] + 1; + int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index] + 1; int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr + -1))[0]; int _tribeIndex = 0; diff --git a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp index 8d942cd2a..e98776b56 100644 --- a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp +++ b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp @@ -47,7 +47,7 @@ namespace AI { _movingFewerThan20Percent = 0; - _ptrSize = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + _ptrSize = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { diff --git a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp index a6a3f9d47..2ecd26042 100644 --- a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp @@ -29,7 +29,7 @@ namespace AI { int _tribeTotal = 0; int _notReallyMoving = 0; - int* local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + int* local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { int iVar2 = (*(int (*)[2])(local_c + -1))[0]; @@ -68,8 +68,8 @@ namespace AI { } while ((int)local_c < 0xb42a2c); if (0 < _tribeTotal) { - return (BOOLEnum)((_notReallyMoving * 100) / _tribeTotal - >= *(int*)((int)this + _aiTypeMinus1 * 0x2a4 + 0x200)); + return ( + BOOLEnum)((_notReallyMoving * 100) / _tribeTotal >= *(int*)((int)this + _aiTypeMinus1 * 0x2a4 + 0x200)); } return FALSE; diff --git a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp index c9ffdb38b..24deba5fb 100644 --- a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp +++ b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp @@ -72,7 +72,7 @@ namespace AI { /* clear out flags */ - piVar1 = DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[0] + 1; + piVar1 = DAT_SkirmishDefinedData::instance.attackUnitRequired[0] + 1; do { @@ -97,7 +97,7 @@ namespace AI { _index = 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[0][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[0][1] = 1; } _maxDiggingUnits = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttDiggingUnitMax; @@ -108,7 +108,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[1][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[1][1] = 1; } _maxAssassins = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxAssassins; @@ -118,7 +118,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[2][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[2][1] = 1; } _maxUnit2 = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnit2Max; @@ -127,7 +127,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[3][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[3][1] = 1; } _maxLaddermen = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxLaddermen; @@ -137,7 +137,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[4][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[4][1] = 1; } _maxTunnelers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxTunnelers; @@ -147,7 +147,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[5][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[5][1] = 1; } _maxUnitPatrol = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitPatrolMax; @@ -157,7 +157,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[6][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[6][1] = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitBackupMax; @@ -167,7 +167,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[7][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[7][1] = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitEngageMax; @@ -177,7 +177,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[8][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[8][1] = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitSiegeDefMax; @@ -187,7 +187,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[9][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[9][1] = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxDefault; @@ -197,7 +197,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[10][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[10][1] = 1; } if (_index != 0) { @@ -210,12 +210,11 @@ namespace AI { do { - if (DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[_index2][1] != 0) { + if (DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2][1] != 0) { if (_rng == 0) { - return (AIUnitBehaviourType)(DAT_SkirmishDefinedData::instance - .DAT_AIBehaviourTypeUnitRequired[_index2][0]); + return (AIUnitBehaviourType)(DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2][0]); } _rng = _rng + -1; diff --git a/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp index 1b1c2239a..75b65a9ec 100644 --- a/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp +++ b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp @@ -46,7 +46,7 @@ namespace AI { do { if ((int)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType - == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_loopCounter]) { + == DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1[_loopCounter]) { /* fancy break statement? */ diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp index f4283f86e..f0ef6d940 100644 --- a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -27,7 +27,7 @@ namespace AI { return; int iVar3 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - AIResourceTradeCategoryInt* local_18 = &DAT_SkirmishDefinedData::instance.DAT_AIResourceTradeAICMapping[0].aic; + AIResourceTradeCategoryInt* local_18 = &DAT_SkirmishDefinedData::instance.AIResourceTradeAICMapping[0].aic; do { ResourceType resourceType diff --git a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp index 83b899711..7b01dc9c3 100644 --- a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp +++ b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp @@ -42,7 +42,7 @@ namespace AI { _enclosed = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)( playerID); - _ptr = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_GroundUnits[0].aivUnitType; + _ptr = &DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[0].aivUnitType; do { diff --git a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp index 429bb500b..5e202cb21 100644 --- a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp +++ b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp @@ -21,8 +21,7 @@ namespace AI { { - AIVUnitTypeInt* _ptr - = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_RangedUnits[0].aivUnitType; + AIVUnitTypeInt* _ptr = &DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[0].aivUnitType; do { diff --git a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp index 6870e8369..66d46dc78 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp @@ -67,8 +67,7 @@ namespace AI { _defendingLordIndex = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID); - _ptrGroupCount - = (int (*)[2])(DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[0] + 1); + _ptrGroupCount = (int (*)[2])(DAT_SkirmishDefinedData::instance.MaxBreachTribes[0] + 1); do { diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index 4c4593028..3413b2634 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -40,7 +40,7 @@ namespace AI { _ghX = _gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[_ghY].addXgetTile; } - int* _mappingPtr = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { int const _maxTribeCount = *_mappingPtr; diff --git a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp index b5d4cdd8e..6683a5696 100644 --- a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp +++ b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp @@ -61,7 +61,7 @@ namespace AI { /* defWallPatrolGroups */ - _ptr = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_PatrolUnits[0].aivUnitType; + _ptr = &DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[0].aivUnitType; do { diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp index 086bf9485..02619dda4 100644 --- a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -25,7 +25,7 @@ namespace AI { if ((iVar3 < iVar6) && (((unitType == 0x8 || (unitType == 0xa)) || (unitType == 0x11)))) { iVar6 = iVar3; } - iVar3 = DAT_SkirmishDefinedData::instance.DAT_AiTribeIDOffsetForUnitType[(int)unitType]; + iVar3 = DAT_SkirmishDefinedData::instance.AITribeIDOffsetForUnitType[(int)unitType]; if (0 < iVar6) { short* _aiTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar3; do { diff --git a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp index 7a9a56b30..43f52c12f 100644 --- a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp +++ b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp @@ -133,8 +133,8 @@ namespace AI { do { iVar3 = iVar3 - + DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping - [DAT_GameState::instance.playerDataArray[aiStack_24[iVar4]].aiType + + DAT_SkirmishDefinedData::instance + .MaxBreachTribes[DAT_GameState::instance.playerDataArray[aiStack_24[iVar4]].aiType + OpenSHC::AI::AIT_FREDERICK][0]; iVar4 = iVar4 + 1; @@ -156,15 +156,15 @@ namespace AI { iVar3 = aiStack_24[iVar4]; iVar5 = iVar5 - - DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping - [DAT_GameState::instance.playerDataArray[iVar3].aiType + - DAT_SkirmishDefinedData::instance + .MaxBreachTribes[DAT_GameState::instance.playerDataArray[iVar3].aiType + OpenSHC::AI::AIT_FREDERICK][0]; if (iVar5 < 0) { DAT_GameSynchronyState::instance.DAT_ChatTauntOrMessage = -2 - - DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping - [DAT_GameState::instance.playerDataArray[iVar3].aiType + - DAT_SkirmishDefinedData::instance + .MaxBreachTribes[DAT_GameState::instance.playerDataArray[iVar3].aiType + OpenSHC::AI::AIT_FREDERICK][1]; DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[1] = 1; diff --git a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp index eda86856b..ff18d5cb7 100644 --- a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp +++ b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp @@ -18,10 +18,10 @@ namespace AI { SkirmishDefinedData* pSVar1 = DAT_SkirmishDefinedData::ptr; do { - if (pSVar1->DAT_UnitTypes_RangedAndArmored[0] == _unitType) + if (pSVar1->RangedAndArmoredUnits[0] == _unitType) return (undefined4)(1); - pSVar1 = (SkirmishDefinedData*)(pSVar1->DAT_UnitTypes_RangedAndArmored + 1); + pSVar1 = (SkirmishDefinedData*)(pSVar1->RangedAndArmoredUnits + 1); } while ((int)pSVar1 < 0xb3eb50); diff --git a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp index 8011403c9..b5ec39df2 100644 --- a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp +++ b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp @@ -92,10 +92,10 @@ namespace AI { do { - if (*piVar4 == DAT_SkirmishDefinedData::instance.DAT_SiegeEngineUnitType[iVar2]) { + if (*piVar4 == DAT_SkirmishDefinedData::instance.SiegeEngineUnitType[iVar2]) { _requiredEngineers - = DAT_SkirmishDefinedData::instance.DAT_SiegeEngineTypeRequiredEngineers[iVar2]; + = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[iVar2]; break; } @@ -146,13 +146,13 @@ namespace AI { do { if (*_siegeEngineUnitType - == DAT_SkirmishDefinedData::instance.DAT_SiegeEngineUnitType[_counterTill6]) { + == DAT_SkirmishDefinedData::instance.SiegeEngineUnitType[_counterTill6]) { - _requiredEngineers = DAT_SkirmishDefinedData::instance - .DAT_SiegeEngineTypeRequiredEngineers[_counterTill6]; + _requiredEngineers + = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[_counterTill6]; _siegeEngineType = (CommandBuildingType)DAT_SkirmishDefinedData::instance - .DAT_SiegeEngineCommandBuildingTypes[_counterTill6]; + .SiegeEngineCommandBuildingTypes[_counterTill6]; break; } From 80d83ca2b8cd9e0c599dade5b584564161c3fa9b Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 12:12:34 +0200 Subject: [PATCH 014/242] improve readability and fit --- .../AICState/aiCommandSiegeEngineTribes.cpp | 2 +- .../AI/AICState/aiCreateSiegeUnits.cpp | 2 +- .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 2 +- .../AI/AICState/aiGiveRaidInstructions.cpp | 2 +- src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 57 +++++++------- .../AICState/computeEnemyKeepApproachTile.cpp | 6 +- .../AICState/decideOnTribeAttackLocation.cpp | 34 +++++---- ...ndAttackTribePositionAndPathToDefenses.cpp | 2 +- .../AICState/moveAttackTribesToLocations.cpp | 52 ++++++------- .../AICState/sendTribeToAIVLocationSlot.cpp | 6 +- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 75 +++++++++---------- 11 files changed, 112 insertions(+), 128 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp index f4a02fbcf..4d458992a 100644 --- a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp @@ -175,7 +175,7 @@ namespace AI { if (0 < _tile) { - y1 = (uint)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + y1 = (uint)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; x1 = _tile - DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index c5e339c24..fb783db4b 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -129,7 +129,7 @@ namespace AI { .aiSiegeCreationInformation[0][_engineIndex] .delay)) { int _y = (int)DAT_ViewportRenderState::instance - .DAT_TileTranslationMatrix_YComponent[_location]; + .tileTranslationMatrix_YComponent[_location]; int _placeTile = _location - DAT_ViewportRenderState::instance.translationMatrix[_y] .addXgetTile; diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp index a48ad6d5f..90ab12ecd 100644 --- a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -70,7 +70,7 @@ namespace AI { .addXgetTile; } if (_hasTarget && _tile != 0) { - sVar2 = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + sVar2 = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; iVar3 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; _canNavigate = MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( _tribeID, _tile); diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp index f1a374dc6..eaf785544 100644 --- a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -50,7 +50,7 @@ namespace AI { #define DO_MOVE_TO_TILE(_tile, _tribeID3) \ do { \ if ((_tile) != 0) { \ - short sVar2_ = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[(_tile)]; \ + short sVar2_ = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[(_tile)]; \ int iVar4_ = DAT_ViewportRenderState::instance.translationMatrix[sVar2_].addXgetTile; \ BOOLEnum BVar5_ = MACRO_CALL_MEMBER( \ OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)((_tribeID3), (_tile)); \ diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp index 810c29fce..a80d00659 100644 --- a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -21,42 +21,35 @@ namespace AI { return; for (int _index1 = 0; _index1 < 11; _index1++) { - int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index1] + 1; - int const _maxTribeCount = *_mappingPtr; - int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr - 1))[0]; + int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index1].tribeType; int _tribeIndex = 0; - - if (0 < _maxTribeCount) { - - for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { - int const _tribeID - = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - if (_tribeTypeStart == 0xbe) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, playerID); - } else if (_tribeTypeStart == 0xd) { + int const _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index1].tribeCount; + + for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { + int const _tribeID + = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart + _tribeIndex]; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_tribeTypeStart + _tribeIndex])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + if (_tribeTypeStart == 0xbe) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); + } else if (_tribeTypeStart == 0xd) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); + } else { + int const _hasHorses + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + if (_hasHorses != FALSE) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( _tribeID, playerID); } else { - int const _hasHorses - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, - DAT_TribesState::ptr)(_tribeID); - if (_hasHorses != FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, playerID); - } else { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( - _tribeID, playerID); - } + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); } } } diff --git a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp index 3143812d5..e833529d0 100644 --- a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp +++ b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp @@ -76,9 +76,9 @@ namespace AI { _tile - DAT_ViewportRenderState::instance .translationMatrix[DAT_ViewportRenderState::instance - .DAT_TileTranslationMatrix_YComponent[_tile]] + .tileTranslationMatrix_YComponent[_tile]] .addXgetTile, - (int)((int)(DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]))); + (int)((int)(DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]))); /* avoiding unit death areas */ @@ -126,7 +126,7 @@ namespace AI { if (0 < _shortestDistanceTile) { - _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_shortestDistanceTile]; + _y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_shortestDistanceTile]; DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY = (int)_y; diff --git a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp index 5e71e48dc..5d078d371 100644 --- a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp +++ b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp @@ -54,11 +54,12 @@ namespace AI { int _unitID = MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::getUnitIDForIndexInTribe, DAT_TribesState::ptr)(_tribeID, 0); if ((_unitID != 0) - && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, + && MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[_tribeID].owner, _targetPlayer, (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), - (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), (byte*)&tribeID_OR_moatWasHit, - &_x, &_y)) { + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), (byte*)&tribeID_OR_moatWasHit, &_x, + &_y)) { if ((char)tribeID_OR_moatWasHit != '\0') { MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( _tribeID, ((UnitInstructionType)0x23), @@ -91,8 +92,9 @@ namespace AI { return; } - int _buildingID = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, - DAT_GameState::ptr)(_targetPlayer); + int _buildingID + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + DAT_GameState::ptr)(_targetPlayer); if (_buildingID != 0) { MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( _tribeID, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, _buildingID, @@ -116,8 +118,9 @@ namespace AI { return; } - int _buildingID_2 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, - DAT_GameState::ptr)(_targetPlayer); + int _buildingID_2 + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + DAT_GameState::ptr)(_targetPlayer); int _destinationTile; int _destinationX2; @@ -125,8 +128,8 @@ namespace AI { if (_buildingID_2 == 0) { int iVar5 = DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] - .addXgetTile; + .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] + .addXgetTile; _destinationTile = iVar5 + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; } else { int iVar5 = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; @@ -145,16 +148,19 @@ namespace AI { if (DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper == 0) { // was LAB_004d1d11 int iVar5b = DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] - .addXgetTile; - _destinationTile = iVar5b + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; + .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer] + .campground.yEntry] + .addXgetTile; + _destinationTile + = iVar5b + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; } } } if (_destinationTile != 0) { - _destinationY2 = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_destinationTile]; - _destinationX2 = _destinationTile - DAT_ViewportRenderState::instance.translationMatrix[_destinationY2].addXgetTile; + _destinationY2 = (int)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_destinationTile]; + _destinationX2 + = _destinationTile - DAT_ViewportRenderState::instance.translationMatrix[_destinationY2].addXgetTile; BOOLEnum BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( _tribeID, _destinationTile); if (BVar4 != FALSE) { diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp index 7059f8a9f..d8525fab9 100644 --- a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -55,7 +55,7 @@ namespace AI { OpenSHC::Map::Navigation::PathFindingState_Func::tracePathToFriendlyDefensesAndReturnTileUnk, DAT_PathFindingState::ptr)(playerID, local_8, local_4); if (0 < _tile) { - short _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + short _y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; DAT_GameState::instance.playerDataArray[playerID].someTile = _tile; int iVar2 = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; DAT_GameState::instance.playerDataArray[playerID].someY = (int)_y; diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp index 4e4a6a0e2..6de76caf0 100644 --- a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -24,43 +24,35 @@ namespace AI { int _destIndex = 0; for (int _index = 0; _index < 11; _index++) { - int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index] + 1; - - int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr + -1))[0]; + int const _tribeTypeStart = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; int _tribeIndex = 0; - int const _maxTribeCount = *_mappingPtr; - - if (0 < _maxTribeCount) { - short* _tribeIDPtr = &DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart]; - - do { - int const _tribeID = (int)*_tribeIDPtr; + int const _maxTribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { + for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + int const _tribeID + = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(_tribeID, - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] - .xOffset)), - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] - .yOffset)), - 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { - _destIndex = _destIndex + 1; - } + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - _tribeIDPtr = _tribeIDPtr + 1; - _tribeIndex = _tribeIndex + 1; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] + .xOffset)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] + .yOffset)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - } while (_tribeIndex < _maxTribeCount); + _destIndex = _destIndex + 1; + } } } } diff --git a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp index 73e501ba0..2d8aad2b4 100644 --- a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp @@ -32,11 +32,11 @@ namespace AI { if (_slotIndex <= 9) _tile = DAT_GameState::instance.playerDataArray[_owner].aivUnitLocationSlots[aivUnitType][_slotIndex]; - short _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + short _y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; int _x = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; - BOOLEnum _canNavigate = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, _tile); + BOOLEnum _canNavigate + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, _tile); if (_canNavigate == FALSE) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, _owner); diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index 3413b2634..4ad45f3f1 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -36,65 +36,58 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID1].requestStateUnk = 0; return; } - _ghY = (uint)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_gatehouseTile]; + _ghY = (uint)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_gatehouseTile]; _ghX = _gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[_ghY].addXgetTile; } - int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + int* _mappingPtr = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; - do { - int const _maxTribeCount = *_mappingPtr; - int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr - 1))[0]; + for (int _index = 0; _index < 11; _index++) { + int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; int _tribeIndex = 0; + int const _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - if (0 < _maxTribeCount) { - short* _tribeIDPtr = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _tribeTypeStart; + for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { - do { - int const _tribeID = (int)*_tribeIDPtr; + int const _tribeID + = (int)DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID1] - .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID1] + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - int const _canNav2 - = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID1, playerID2); + int const _canNav2 + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID1, playerID2); - if (_canNav2 != FALSE) { - if (_tribeTypeStart == 0xbe) { + if (_canNav2 != FALSE) { + if (_tribeTypeStart == 0xbe) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID2); + } else { + int const _hasHorses + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + if (_hasHorses != FALSE) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( _tribeID, playerID2); } else { - int const _hasHorses - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, - DAT_TribesState::ptr)(_tribeID); - if (_hasHorses != FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, playerID2); - } else { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( - _tribeID, playerID2); - } + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( + _tribeID, playerID2); } - } else { - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - _tribeID, _ghX, _ghY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); } + } else { + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + _tribeID, _ghX, _ghY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); } - - _tribeIDPtr = _tribeIDPtr + 1; - _tribeIndex = _tribeIndex + 1; - } while (_tribeIndex < _maxTribeCount); + } } - - _mappingPtr = _mappingPtr + 2; - } while ((int)_mappingPtr < 0xb42a2c); + } } } } From 62ab83f453de748346aceaca62943ca2a9db025a Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 12:41:00 +0200 Subject: [PATCH 015/242] as best as we can --- .../AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index 4ad45f3f1..00653f14a 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -16,6 +16,11 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + /** + * I seem unable to make this match better than 75.42% even though this function flow is dumb: _ghX and _ghY are + * only specified if not navigatable, which is checked twice for some reason. + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004CE5F0 void AICState::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, int playerID2) { @@ -40,8 +45,6 @@ namespace AI { _ghX = _gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[_ghY].addXgetTile; } - int* _mappingPtr = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; - for (int _index = 0; _index < 11; _index++) { int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; int _tribeIndex = 0; From 3894bd28eca66bcdd3aa27db1c4c883e30ec5afa Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 13:21:15 +0200 Subject: [PATCH 016/242] improve rally percentage --- .../aiChoiceAttForceRallyPercentage.cpp | 73 ++++++------------- 1 file changed, 23 insertions(+), 50 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp index 165cf2937..61e3f3977 100644 --- a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -20,70 +20,43 @@ namespace AI { { - AITypeInt AVar1; + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[param_1].aiType; - int iVar2; - - int iVar3; - - short* psVar4; - - int local_14; - - int local_10; - - int* local_c; - - AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) { + if (_aiType == OpenSHC::AI::AIT_NULL) { return 0; } - local_14 = 0; - - local_10 = 0; - - local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + int _nonMoving = 0; + int _activeTribes = 0; + int _index = 0; + int _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - do { + for (; _index < 11; _index++) { - iVar3 = 0; + int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; + int _tribeIndex = 0; + _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - if (0 < *local_c) { + for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { - psVar4 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + (*(int (*)[2])(local_c + -1))[0]; + int const _tribeID + = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - do { + if (((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1] + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) + && (_activeTribes += 1, DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0x14)) { - iVar2 = (int)*psVar4; - - if (((iVar2 != 0) - && (DAT_TribesState::instance.tribes[iVar2].uid - == DAT_GameState::instance.playerDataArray[param_1] - .aiTribeUIDs[iVar3 + (*(int (*)[2])(local_c + -1))[0]])) - && (local_14 = local_14 + 1, - DAT_TribesState::instance.tribes[iVar2].percentageMovingUnk < 0x14)) { - - local_10 = local_10 + 1; - } - - iVar3 = iVar3 + 1; - - psVar4 = psVar4 + 1; - - } while (iVar3 < *local_c); + _nonMoving += 1; + } } + } - local_c = local_c + 2; - - } while ((int)local_c < 0xb42a2c); - - if (0 < local_14) { + if (0 < _activeTribes) { - return (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x200) - <= (local_10 * 100) / local_14); + return (uint)(((int)this->aics[_aiType - 1].AttForceRallyPercentage) <= (_nonMoving * 100) / _activeTribes); } return 0; From 6f04e8f9199e7962871275d61528df554396308e Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 13:26:25 +0200 Subject: [PATCH 017/242] OpenSHC::AI::AICState::aiChoiceAttForceRallyPercentage 100% --- .../aiChoiceAttForceRallyPercentage.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp index 61e3f3977..1e64d7c93 100644 --- a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -27,18 +27,17 @@ namespace AI { return 0; } - int _nonMoving = 0; + int const _aiIndex = _aiType - 1; int _activeTribes = 0; - int _index = 0; - int _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; + int _nonMoving = 0; - for (; _index < 11; _index++) { + for (int _index = 0; _index < 11; _index++) { int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; - int _tribeIndex = 0; - _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { + int const _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; + + for (int _tribeIndex = 0; _tribeIndex < _maxTribeCount; _tribeIndex++) { int const _tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[_tribeTypeStart + _tribeIndex]; @@ -54,12 +53,12 @@ namespace AI { } } - if (0 < _activeTribes) { + if (_activeTribes <= 0) { - return (uint)(((int)this->aics[_aiType - 1].AttForceRallyPercentage) <= (_nonMoving * 100) / _activeTribes); + return 0; } - return 0; + return (uint)((_nonMoving * 100) / _activeTribes >= (int)this->aics[_aiIndex].AttForceRallyPercentage); } } From dc57850d4582f48f58f158a2e3bcf91da6d8fcb2 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Thu, 30 Jul 2026 00:31:21 +0200 Subject: [PATCH 018/242] slow improvement --- .../AICState/aiCommandSiegeEngineTribes.cpp | 202 +++++------------- 1 file changed, 59 insertions(+), 143 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp index 4d458992a..cee33b455 100644 --- a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp @@ -14,194 +14,110 @@ #include "OpenSHC/Globals/DAT_TroopValueState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" - namespace OpenSHC { namespace AI { - using OpenSHC::Map::Units::SomeTribeBehaviorType; using OpenSHC::Map::Units::Unit; using OpenSHC::Map::Units::UnitLogicState; using OpenSHC::Map::Units::UnitType; using OpenSHC::Map::Units::UnitTypeShort; using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CFCD0 void AICState ::aiCommandSiegeEngineTribes(int playerID) - { - - UnitTypeShort UVar1; - - int iVar2; - - uint x1; - - int _sectionID2; - - int iVar3; - - int iVar4; - - uint y1; - - Unit* local_14; - - int local_c[3]; - - int _tile; - - short _sectionID; - - short _targetUnitID; - - iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xba]; - - iVar4 = 0; - - iVar3 = 0; - - local_c[0] = 0; - - local_c[1] = 0; - - local_c[2] = 0; - - if ((iVar2 != 0) - && (DAT_TribesState::instance.tribes[iVar2].uid + int _targetTribeIDs[3]; + _targetTribeIDs[0] = 0; + _targetTribeIDs[1] = 0; + _targetTribeIDs[2] = 0; + int _validCount = 0; + int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xba]; + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xba])) { - - local_c[0] = iVar2; - - iVar3 = 1; + _targetTribeIDs[0] = _tribeID; + _validCount = 1; } - - iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbb]; - - if ((iVar2 != 0) - && (DAT_TribesState::instance.tribes[iVar2].uid + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbb]; + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbb])) { - - local_c[iVar3] = iVar2; - - iVar3 = iVar3 + 1; + _targetTribeIDs[_validCount] = _tribeID; + _validCount += 1; } - - iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbc]; - - if ((iVar2 != 0) - && (DAT_TribesState::instance.tribes[iVar2].uid + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbc]; + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbc])) { - - local_c[iVar3] = iVar2; + _targetTribeIDs[_validCount] = _tribeID; } - - local_14 = &DAT_UnitsState::instance.units[1]; - - do { - - if ((local_14->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) - && ((((UVar1 = local_14->unitType, - UVar1 == OpenSHC::Map::Units::UT_S_TOWER || (UVar1 == OpenSHC::Map::Units::UT_S_BATTERINGRAM)) - || (UVar1 == OpenSHC::Map::Units::UT_S_SHIELD)) - && ((local_14->unknownSiegeTentRelated02 == 3 && (local_14->aiUnitBehaviourType != 0x15)))))) { - - if (UVar1 == OpenSHC::Map::Units::UT_S_TOWER) { - - if ((local_14->tribeID != 0) + int _shieldCount = 0; + for (int _unitID = 1; _unitID < 2500; _unitID++) { + UnitTypeShort _unitType; + if ((DAT_UnitsState::instance.units[_unitID].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) + && ((((_unitType = DAT_UnitsState::instance.units[_unitID].unitType, + _unitType == OpenSHC::Map::Units::UT_S_TOWER + || (_unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM)) + || (_unitType == OpenSHC::Map::Units::UT_S_SHIELD)) + && ((DAT_UnitsState::instance.units[_unitID].unknownSiegeTentRelated02 == 3 + && (DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType != 0x15)))))) { + if (_unitType == OpenSHC::Map::Units::UT_S_TOWER) { + int _engineTribeID = (int)DAT_UnitsState::instance.units[_unitID].tribeID; + if ((_engineTribeID != 0) && (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc + -4) != 0)) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, - DAT_TribesState::ptr)((int)local_14->tribeID, OpenSHC::Map::Units::STBT_0x414); + DAT_TribesState::ptr)(_engineTribeID, OpenSHC::Map::Units::STBT_0x414); } - - } - - else if (UVar1 == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { - - iVar3 = (int)local_14->tribeID; - - if (iVar3 != 0) { - + } else if (_unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + int _engineTribeID = (int)DAT_UnitsState::instance.units[_unitID].tribeID; + if (_engineTribeID != 0) { if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.gateValuesArray + playerID * 0x177bc + -4) - == 0) { - + != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, + DAT_TribesState::ptr)(_engineTribeID, OpenSHC::Map::Units::STBT_0x3f6); + } else { if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc + -4) != 0) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, - DAT_TribesState::ptr)(iVar3, OpenSHC::Map::Units::STBT_0x413); + DAT_TribesState::ptr)(_engineTribeID, OpenSHC::Map::Units::STBT_0x413); } - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, - DAT_TribesState::ptr)(iVar3, OpenSHC::Map::Units::STBT_0x3f6); } } - - } - - else if (UVar1 == OpenSHC::Map::Units::UT_S_SHIELD) { - - _sectionID = local_14->tribeID; - - _sectionID2 = (int)_sectionID; - - if ((_sectionID2 != 0) && (iVar4 < 3)) { - - iVar3 = local_c[iVar4]; - - DAT_TribesState::instance.tribes[_sectionID2].field56_0x1f2 = (short)iVar3; - - DAT_TribesState::instance.tribes[_sectionID2].uid2 - = DAT_TribesState::instance.tribes[iVar3].uid; - - _targetUnitID = DAT_TribesState::instance.tribes[iVar3].selectionTargetUnitID; - - DAT_TribesState::instance.tribes[iVar3].tribeID = _sectionID; - - _tile = DAT_UnitsState::instance.units[_targetUnitID].tile; - - iVar4 = iVar4 + 1; - - if (0 < _tile) { - - y1 = (uint)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; - - x1 = _tile - DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; - + } else if (_unitType == OpenSHC::Map::Units::UT_S_SHIELD) { + int _shieldTribeID = (int)DAT_UnitsState::instance.units[_unitID].tribeID; + if ((_shieldTribeID != 0) && (_shieldCount < 3)) { + int _targetTribeID = _targetTribeIDs[_shieldCount]; + DAT_TribesState::instance.tribes[_shieldTribeID].field56_0x1f2 = (short)_targetTribeID; + DAT_TribesState::instance.tribes[_shieldTribeID].uid2 + = DAT_TribesState::instance.tribes[_targetTribeID].uid; + int _targetUnitID = (int)DAT_TribesState::instance.tribes[_targetTribeID].selectionTargetUnitID; + DAT_TribesState::instance.tribes[_targetTribeID].tribeID = (short)_shieldTribeID; + int _targetTile = DAT_UnitsState::instance.units[_targetUnitID].tile; + _shieldCount = _shieldCount + 1; + if (0 < _targetTile) { + uint y1 + = (uint)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_targetTile]; + uint x1 = _targetTile - DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - _sectionID2, x1, y1, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - + _shieldTribeID, x1, y1, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: calculatePreferredRelativeOrientation, DAT_DirectionAlgorithmState::ptr)((int)DAT_UnitsState::instance.units[_targetUnitID].x, (int)((int)(DAT_UnitsState::instance.units[_targetUnitID].y)), (int)((int)(x1)), (int)((int)(y1))); - - DAT_TribesState::instance.tribes[_sectionID2].orientation + DAT_TribesState::instance.tribes[_shieldTribeID].orientation = (short)DAT_DirectionAlgorithmState::instance.orientation; } } } } - - local_14 = local_14 + 0x248; - - } while ((int)local_14 < 0x165141a); - - return; + } } - } } From e25f2bfae9bad183541705d844f610a250d912d9 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Thu, 30 Jul 2026 01:13:11 +0200 Subject: [PATCH 019/242] slow improvement --- .../aiCommandTribe11StandGroundToGate.cpp | 40 +++++--- .../aiCommandTribe12AggressiveApproach.cpp | 98 ++++++++++--------- .../aiCommandTribe13DefensiveWave.cpp | 34 ++++--- 3 files changed, 100 insertions(+), 72 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp index 7001fe9cf..ffd86e8ba 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp @@ -13,20 +13,32 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF470 void AICState::aiCommandTribe11StandGroundToGate(int playerID) { - int iVar1; - int iVar2; - if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) - && (iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], iVar2 != 0)) - && (DAT_TribesState::instance.tribes[iVar2].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb])) - && (DAT_TribesState::instance.tribes[iVar2].selectionTargetUnitID != 0)) { - DAT_TribesState::instance.tribes[iVar2].unitStance = Map::Units::Behavior::USE_STAND_GROUND; - iVar1 = MACRO_CALL_MEMBER( - Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)(iVar2); - if (iVar1 == 0) { - MACRO_CALL_MEMBER( - Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)(iVar2); - } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return; + } + + int const iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb]; + + if (iVar2 == 0) { + return; + } + + if (DAT_TribesState::instance.tribes[iVar2].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb]) { + return; + } + + if (DAT_TribesState::instance.tribes[iVar2].selectionTargetUnitID == 0) { + return; + } + + DAT_TribesState::instance.tribes[iVar2].unitStance = Map::Units::Behavior::USE_STAND_GROUND; + + if (MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)( + iVar2) + == 0) { + MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)( + iVar2); } } } diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp index e4b5a1359..8dd97308d 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp @@ -23,55 +23,59 @@ namespace AI { decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CF2E0 - void AICState ::aiCommandTribe12AggressiveApproach(int param_1) - + void AICState ::aiCommandTribe12AggressiveApproach(int playerID) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) { + return; + } + + int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xc]; + + if (tribeID == 0) { + return; + } + + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xc]) { + return; + } + + int targetUnitID = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + + if (targetUnitID == 0) { + return; + } - int iVar1; - - BOOLEnum BVar2; - - int tribeID; - - if ((((DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) - && (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xc], tribeID != 0)) - && (DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xc])) - && (iVar1 = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID, iVar1 != 0)) { - - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, - DAT_PathFindingState::ptr)((int)DAT_UnitsState::instance.units[iVar1].x, - (uint)((int)((int)DAT_UnitsState::instance.units[iVar1].y)), -1, -1, 10000, FALSE); - - iVar1 = DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID; - - DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - BVar2 = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)(iVar1, 200); - - if (((BVar2 != FALSE) - || (BVar2 = MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)( - DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, (int)((int)(150))), - BVar2 != FALSE)) - || ((BVar2 - = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)( - DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, 100), - BVar2 != FALSE - || (BVar2 = MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)( - DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, (int)((int)(50))), - BVar2 != FALSE)))) { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(tribeID, (uint)((int)(DAT_PathFindingState::instance.ALG_ResultX)), - (uint)((int)(DAT_PathFindingState::instance.ALG_ResultY)), 0, 0, - OpenSHC::Map::Units::Instructions::UMSE_0); - } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + DAT_PathFindingState::ptr)((int)DAT_UnitsState::instance.units[targetUnitID].x, + (uint)((int)((int)DAT_UnitsState::instance.units[targetUnitID].y)), -1, -1, 10000, FALSE); + + int attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + // Try progressively smaller search costs; stop at the first one that finds a destination. + // The later probes deliberately re-read attackedPlayerID, as the calls may update it. + if ((MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)(attackedPlayerID, 200) + != FALSE) + || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 150) + != FALSE) + || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 100) + != FALSE) + || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 50) + != FALSE)) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, (uint)((int)(DAT_PathFindingState::instance.ALG_ResultX)), + (uint)((int)(DAT_PathFindingState::instance.ALG_ResultY)), 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); } return; diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp index c28d2776b..bf47a5dfa 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp @@ -11,19 +11,31 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF270 - void AICState::aiCommandTribe13DefensiveWave(int param_1) + void AICState::aiCommandTribe13DefensiveWave(int playerID) { - int tribeID; - if ((DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) - && (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xd], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xd]) - && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { - DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( - tribeID, Map::Units::STBT_0x3f4); - } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return; } + + int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xd]; + + if (tribeID == 0) { + return; + } + + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xd]) { + return; + } + + if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) { + return; + } + + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f4); } } } From bc820af8577afd3909cc10b90ace4ef69f25ea6f Mon Sep 17 00:00:00 2001 From: sourcehold Date: Tue, 4 Aug 2026 00:11:17 +0200 Subject: [PATCH 020/242] integrate main --- .../aiChoiceAttForceRallyPercentage.cpp | 2 +- .../AI/AICState/aiCreateSiegeUnits.cpp | 10 ++-- .../AI/AICState/clearOutdatedAITribes.cpp | 8 +-- .../clearRallyFlagOnAllAIAttackTribes.cpp | 15 ++--- .../AICState/computeAttackPossibilities.cpp | 2 +- .../AICState/computeEnemyKeepApproachTile.cpp | 2 +- .../AICState/destroyAnyBuildingInCategory.cpp | 16 ++--- .../AI/AICState/destroyBuildingIfNoWorker.cpp | 2 +- ...ndAttackTribePositionAndPathToDefenses.cpp | 2 +- .../giveMoveCommandToAttackTribes.cpp | 2 +- ...eUnitsGoDefensiveAndBackToSomeLocation.cpp | 2 +- ...erIsWoodCuttersHutWhileNoWoodAvailable.cpp | 17 ++++++ ...rcentageNonMovingTribesGTEAICSpecified.cpp | 2 +- .../processAttForceRallyPercentage.cpp | 2 +- .../randomlySelectAttackUnitTypeToRecruit.cpp | 31 +++++----- .../recomputeAIPathCostToAttackedKeep.cpp | 2 +- .../AI/AICState/recomputeAIZonerLayer.cpp | 2 +- .../AI/AICState/recomputeAttackAIZone.cpp | 2 +- .../recruitHarrassingSiegeEngines.cpp | 19 +++--- .../AI/AICState/renderDebugDataAiInfo.cpp | 4 +- .../sendUnitsToAttackBreachedCastle.cpp | 2 +- .../AICState/shouldDestroyWoodCutterUnk.cpp | 2 +- .../AICState/shouldNotBeBuildingArmoury.cpp | 6 +- .../AICState/shouldNotBeBuildingGranary.cpp | 6 +- .../AI/AICState/shouldNotBeBuildingHovel.cpp | 6 +- .../AI/AICState/shouldNotBuildKillingPits.cpp | 6 +- ...rketArmoryGranaryBarracksMercenarypost.cpp | 16 +++-- ...uldWaitWithBuildingAPositiveFearFactor.cpp | 60 +++++++++---------- ...ouldWaitWithBuildingNegativeFearFactor.cpp | 30 +++++----- .../AI/AICState/someChatMessageSelection.cpp | 9 ++- .../AI/AICState/updateAIPlayerState.cpp | 6 +- ...12_toPlaceSiegeTentsAndAssignEngineers.cpp | 13 ++-- .../useAITribe_0xe_toPlaceTunnels.cpp | 8 +-- src/OpenSHC/AI/AICState/wipeAICMemory.cpp | 2 +- .../woodCuttersHutWhileNoWoodAvailable.cpp | 17 ------ 35 files changed, 166 insertions(+), 167 deletions(-) create mode 100644 src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp delete mode 100644 src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp index 1e64d7c93..de707eebc 100644 --- a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -16,7 +16,7 @@ namespace AI { decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CEC80 - uint AICState ::aiChoiceAttForceRallyPercentage(int param_1) + BOOLEnum AICState ::aiChoiceAttForceRallyPercentage(int param_1) { diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index fb783db4b..886073a29 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -7,7 +7,7 @@ #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Map/Buildings/BuildingTypeShort.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" @@ -30,7 +30,7 @@ namespace AI { using OpenSHC::AI::AIType; using OpenSHC::AI::AITypeInt; using OpenSHC::AI::Tribes::AITribeType; - using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Commands::MappersEnum; using OpenSHC::Map::Buildings::BuildingType; using OpenSHC::Map::Buildings::BuildingTypeShort; using OpenSHC::Map::Units::SomeTribeBehaviorType; @@ -161,7 +161,7 @@ namespace AI { } else { MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID, _placeTile, _y, - (CommandBuildingType)(( + (MappersEnum)(( int)((uint)(ushort)(short)DAT_SkirmishDefinedData::instance .SiegeEngineMetaInfoArray[_siegeInfoIndex] .commandBuildingType)), @@ -172,10 +172,10 @@ namespace AI { + 0xf; *_pGold = *_pGold - _requiredGold; int _newBuildingID - = DAT_TileMapState::instance.DAT_PlacedBuildingID; + = DAT_TileMapState::instance.placedBuildingID; int _newUID = DAT_BuildingsState::instance .buildings[DAT_TileMapState::instance - .DAT_PlacedBuildingID] + .placedBuildingID] .uid; DAT_GameState::instance.playerDataArray[playerID] .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] diff --git a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp index 86ca327e0..913be6005 100644 --- a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp +++ b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp @@ -23,13 +23,13 @@ namespace AI { if (_index != 8) { - int _groupCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index][1]; + int _tribeCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index].tribeCount; - int _tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index][0]; + int _tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index].tribeType; int _offset = 0; - if (0 < _groupCount) { + if (0 < _tribeCount) { short* _ptrTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeType; @@ -49,7 +49,7 @@ namespace AI { _ptrTribeID = _ptrTribeID + 1; - } while (_offset < _groupCount); + } while (_offset < _tribeCount); } } diff --git a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp index 2cdeef7f8..e01808143 100644 --- a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp @@ -33,24 +33,21 @@ namespace AI { if (DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) { - _ptrTribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; - do { /* - first iteration: 3 */ + first iteration: 0 */ - _tribeCount = *_ptrTribeCount; + _counter = 0; - /* - first iteration: 186 */ + _tribeCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_counter].tribeCount; - _tribeType = (*(int (*)[2])(_ptrTribeCount + -1))[0]; + _tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_counter].tribeType; /* - first iteration: 0 */ + first iteration: 186 */ - _counter = 0; + // _tribeType = (*(int (*)[2])(_ptrTribeCount + -1))[0]; if (0 < _tribeCount) { diff --git a/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp index e73d9dff7..bb31d983e 100644 --- a/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp +++ b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp @@ -26,7 +26,7 @@ namespace AI { piVar1 = &DAT_GameState::instance.playerDataArray[playerID]; - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIInfoLayer))); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackPrimeInfo, this)(playerID, piVar1->attackedPlayerID); diff --git a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp index e833529d0..7f28e4267 100644 --- a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp +++ b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp @@ -56,7 +56,7 @@ namespace AI { this->aiBorderTilesIndex = 0; - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 8000, '\0', (void*)((int)(this->aiBorderTiles))); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); diff --git a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp index 42b5dde68..8f1d56ea7 100644 --- a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp +++ b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp @@ -38,12 +38,12 @@ namespace AI { || BVar1 == Map::Buildings::BT_APOTHECARY || BVar1 == Map::Buildings::BT_CHAPEL || BVar1 == Map::Buildings::BT_CHURCH || BVar1 == Map::Buildings::BT_CATHEDRAL); } else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) { - _matches = (BVar1 == Map::Buildings::BT_GATEHOUSELARGE || BVar1 == Map::Buildings::BT_GATEHOUSESMALL - || BVar1 == Map::Buildings::BT_DRAWBRIDGE || BVar1 == Map::Buildings::BT_TOWER1 - || BVar1 == Map::Buildings::BT_TOWER2 || BVar1 == Map::Buildings::BT_TOWER3 - || BVar1 == Map::Buildings::BT_TOWER4 || BVar1 == Map::Buildings::BT_TOWER5 - || BVar1 == Map::Buildings::BT_ENGINEERSGUILD || BVar1 == Map::Buildings::BT_TUNNELERSGUILD - || BVar1 == Map::Buildings::BT_OILSMELTER); + _matches = (BVar1 == Map::Buildings::BT_GATEHOUSELARGE + || BVar1 == Map::Buildings::BT_GATEHOUSESMALL || BVar1 == Map::Buildings::BT_DRAWBRIDGE + || BVar1 == Map::Buildings::BT_TOWER1 || BVar1 == Map::Buildings::BT_TOWER2 + || BVar1 == Map::Buildings::BT_TOWER3 || BVar1 == Map::Buildings::BT_TOWER4 + || BVar1 == Map::Buildings::BT_TOWER5 || BVar1 == Map::Buildings::BT_ENGINEERSGUILD + || BVar1 == Map::Buildings::BT_TUNNELERSGUILD || BVar1 == Map::Buildings::BT_OILSMELTER); } else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) { _matches = (BVar1 == Map::Buildings::BT_MERCENARYPOST || BVar1 == Map::Buildings::BT_BARRACKS || BVar1 == Map::Buildings::BT_STABLES); @@ -62,8 +62,8 @@ namespace AI { if (_matches) { MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( - _buildingID); + MACRO_CALL_MEMBER( + Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_buildingID); } } _buildingID = _buildingID + 1; diff --git a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp index 29895258e..3cff7bcbf 100644 --- a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp +++ b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp @@ -32,7 +32,7 @@ namespace AI { return 0; // old enough: destroy - MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + MACRO_CALL_MEMBER(AIVState_Func::resetCountdownInHeatMap, DAT_AIVState::ptr)( (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp index d8525fab9..e896ea9ea 100644 --- a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -16,7 +16,7 @@ namespace AI { { uint local_8 = 0; uint local_4 = 0; - int* local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + int* local_c = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; bool _found = false; do { diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp index 4e463ac1d..a224fd2ec 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp @@ -42,7 +42,7 @@ namespace AI { _counter = 0; - _ptrGroupCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + _ptrGroupCount = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; do { diff --git a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp index 7d2f22ddc..540b6cdd5 100644 --- a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp +++ b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp @@ -42,7 +42,7 @@ namespace AI { if ((DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) && (DAT_GameState::instance.playerDataArray[param_1].someTile != 0)) { - local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + local_c = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; do { diff --git a/src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp b/src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp new file mode 100644 index 000000000..09d8f6571 --- /dev/null +++ b/src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp @@ -0,0 +1,17 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004ECAB0 + BOOLEnum AICState::mapperIsWoodCuttersHutWhileNoWoodAvailable( + undefined4 playerID, Commands::MappersEnum commandBuildingType) + { + return ((commandBuildingType == Commands::M_MAPPER_WOODSMAN) + && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0)); + } +} +} diff --git a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp index e98776b56..dba68ea44 100644 --- a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp +++ b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp @@ -47,7 +47,7 @@ namespace AI { _movingFewerThan20Percent = 0; - _ptrSize = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + _ptrSize = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; do { diff --git a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp index 2ecd26042..b53a16f12 100644 --- a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp @@ -29,7 +29,7 @@ namespace AI { int _tribeTotal = 0; int _notReallyMoving = 0; - int* local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + int* local_c = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; do { int iVar2 = (*(int (*)[2])(local_c + -1))[0]; diff --git a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp index 24deba5fb..0fc1d1750 100644 --- a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp +++ b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp @@ -72,7 +72,7 @@ namespace AI { /* clear out flags */ - piVar1 = DAT_SkirmishDefinedData::instance.attackUnitRequired[0] + 1; + piVar1 = &DAT_SkirmishDefinedData::instance.attackUnitRequired[0].required; do { @@ -97,18 +97,18 @@ namespace AI { _index = 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[0][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[0].required = 1; } _maxDiggingUnits = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttDiggingUnitMax; if (((_maxDiggingUnits != 0) && (DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops < (int)_maxDiggingUnits)) - && (5 < DAT_GameState::instance.playerDataArray[_attackedPlayerID].field992_0x396c)) { + && (5 < DAT_GameState::instance.playerDataArray[_attackedPlayerID].moatsOwned)) { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[1][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[1].required = 1; } _maxAssassins = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxAssassins; @@ -118,7 +118,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[2][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[2].required = 1; } _maxUnit2 = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnit2Max; @@ -127,7 +127,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[3][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[3].required = 1; } _maxLaddermen = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxLaddermen; @@ -137,7 +137,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[4][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[4].required = 1; } _maxTunnelers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxTunnelers; @@ -147,7 +147,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[5][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[5].required = 1; } _maxUnitPatrol = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitPatrolMax; @@ -157,7 +157,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[6][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[6].required = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitBackupMax; @@ -167,7 +167,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[7][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[7].required = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitEngageMax; @@ -177,7 +177,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[8][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[8].required = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitSiegeDefMax; @@ -187,7 +187,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[9][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[9].required = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxDefault; @@ -197,7 +197,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[10][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[10].required = 1; } if (_index != 0) { @@ -210,11 +210,12 @@ namespace AI { do { - if (DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2][1] != 0) { + if (DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2].required != 0) { if (_rng == 0) { - return (AIUnitBehaviourType)(DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2][0]); + return (AIUnitBehaviourType)(DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2] + .unitBehaviourType); } _rng = _rng + -1; diff --git a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp index a25c39500..3964e3919 100644 --- a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp @@ -61,7 +61,7 @@ namespace AI { *(int*)((int)DAT_TroopValueState::instance.attackInfo.hackValuesArray + playerID * 0x177bc + -0x10) = _attackedPlayerID; - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, diff --git a/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp index 6213b44c7..199d93eca 100644 --- a/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp @@ -21,7 +21,7 @@ namespace AI { DAT_TroopValueState::instance.attackInfo.playerInfo[0].currentPlayerID_OR_attackedPlayerID_OR_one = 1; - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); MACRO_CALL_MEMBER( diff --git a/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp index 8ab398ad0..3396df9e5 100644 --- a/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp @@ -42,7 +42,7 @@ namespace AI { if ((_fullID != -1) || (DAT_GameSynchronyState::instance.currentAIArray[_playerID] != 0)) { - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, diff --git a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp index 21cd5785b..f497eabdc 100644 --- a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp +++ b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp @@ -4,7 +4,7 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Unit.hpp" @@ -24,7 +24,7 @@ namespace OpenSHC { namespace AI { using OpenSHC::AI::Tribes::AITribeType; - using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Commands::MappersEnum; using OpenSHC::Map::Buildings::BuildingType; using OpenSHC::Map::Units::SomeTribeBehaviorType; using OpenSHC::Map::Units::Unit; @@ -65,7 +65,7 @@ namespace AI { int _aicEnginesArrayIndex; - CommandBuildingType _siegeEngineToBuild; + MappersEnum _siegeEngineToBuild; _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; @@ -171,8 +171,7 @@ namespace AI { _aicEnginesArrayIndex = DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex; - _siegeEngineToBuild - = *(CommandBuildingType*)((int)this + (iVar1 + _aicEnginesArrayIndex) * 4 + 0x1cc); + _siegeEngineToBuild = *(MappersEnum*)((int)this + (iVar1 + _aicEnginesArrayIndex) * 4 + 0x1cc); DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = _aicEnginesArrayIndex + 1; @@ -185,9 +184,9 @@ namespace AI { return; } - iVar1 = DAT_AIVState::instance.DAT_BuildingAppropriateGridYPosition * 5; + iVar1 = DAT_AIVState::instance.buildingAppropriateGridYPosition * 5; - _aicEnginesArrayIndex = DAT_AIVState::instance.DAT_BuildingApproriateGridXPosition * 5; + _aicEnginesArrayIndex = DAT_AIVState::instance.buildingAppropriateGridYPosition * 5; DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; @@ -200,15 +199,15 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)( playerID, _aicEnginesArrayIndex, iVar1, _siegeEngineToBuild, 3, 0xf); - _buildingID = DAT_TileMapState::instance.DAT_PlacedBuildingID; + _buildingID = DAT_TileMapState::instance.placedBuildingID; if (DAT_TileMapState::instance.buildingPlacementFail != FALSE) { return; } - DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.DAT_PlacedBuildingID] - .attackWave = 0; + DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.placedBuildingID].attackWave + = 0; DAT_BuildingsState::instance.buildings[_buildingID].unknownSiegeTentRelated01 = 2; diff --git a/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp index 6367b31c8..46687d253 100644 --- a/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp +++ b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp @@ -143,7 +143,7 @@ namespace AI { if (_playerData->aiType == OpenSHC::AI::AIT_NULL) { - iVar1 = DAT_AIVState::instance.SEC_AIVS[_playerData->aivID].castleID; + iVar1 = DAT_AIVState::instance.aivs[_playerData->aivID].castleID; pcVar2 = "AIV:n/a"; @@ -151,7 +151,7 @@ namespace AI { else { - iVar1 = DAT_AIVState::instance.SEC_AIVS[_playerData->aivID].castleID; + iVar1 = DAT_AIVState::instance.aivs[_playerData->aivID].castleID; pcVar2 = "AIV: %d"; } diff --git a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp index 66d46dc78..54406b440 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp @@ -67,7 +67,7 @@ namespace AI { _defendingLordIndex = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID); - _ptrGroupCount = (int (*)[2])(DAT_SkirmishDefinedData::instance.MaxBreachTribes[0] + 1); + _ptrGroupCount = (int (*)[2])(&DAT_SkirmishDefinedData::instance.MaxBreachTribes[0].tribeCount); do { diff --git a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp index c0e9f4f2a..7b9edebb0 100644 --- a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp +++ b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp @@ -34,7 +34,7 @@ namespace AI { if (_hut == 0) return FALSE; - MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + MACRO_CALL_MEMBER(AIVState_Func::resetCountdownInHeatMap, DAT_AIVState::ptr)( (int)(short)DAT_BuildingsState::instance.buildings[_hut].x, (int)(short)DAT_BuildingsState::instance.buildings[_hut].y); MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp index cff5e2904..51ca93934 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -7,9 +7,9 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004ECA60 - BOOLEnum AICState::shouldNotBeBuildingArmoury(PlayerID playerID, Commands::CommandBuildingType commandBuildingType) + BOOLEnum AICState::shouldNotBeBuildingArmoury(PlayerID playerID, Commands::MappersEnum commandBuildingType) { - if (commandBuildingType != Commands::CBT_ARMORY) { + if (commandBuildingType != Commands::M_MAPPER_ARMOURY) { return FALSE; } return DAT_GameState::instance.playerDataArray[playerID].isArmouryAlmostFilledUp == 0; diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp index 93ea91df5..5ef58f276 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -7,9 +7,9 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004ECA30 - BOOLEnum AICState::shouldNotBeBuildingGranary(int playerID, Commands::CommandBuildingType commandBuildingType) + BOOLEnum AICState::shouldNotBeBuildingGranary(int playerID, Commands::MappersEnum commandBuildingType) { - if (commandBuildingType != Commands::CBT_GRANARY) { + if (commandBuildingType != Commands::M_MAPPER_GRANARY) { return FALSE; } return DAT_GameState::instance.playerDataArray[playerID].granaryIsAlmostFilledUp == FALSE; diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp index 4ba346293..d14e60a15 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -7,9 +7,9 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB5B0 - BOOLEnum AICState::shouldNotBeBuildingHovel(PlayerID playerID, Commands::CommandBuildingType param_2) + BOOLEnum AICState::shouldNotBeBuildingHovel(PlayerID playerID, Commands::MappersEnum param_2) { - if (param_2 != Commands::CBT_HOVEL) { + if (param_2 != Commands::M_MAPPER_HOVEL) { return FALSE; } diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp index e16bf1b27..6c80452e9 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_AIVState.hpp" @@ -7,9 +7,9 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004ECA90 - BOOLEnum AICState::shouldNotBuildKillingPits(int playerID, Commands::CommandBuildingType commandBuildingType) + BOOLEnum AICState::shouldNotBuildKillingPits(int playerID, Commands::MappersEnum commandBuildingType) { - if (commandBuildingType == Commands::CBT_KILLINGPIT) { + if (commandBuildingType == Commands::M_MAPPER_KILLING_PIT) { return (BOOLEnum)(DAT_AIVState::instance.mapExtraInfo.playerTotalKillingPits[playerID] >= 100); } return FALSE; diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp index 544c8e381..c1ac9a6b1 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -8,21 +8,19 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB9F0 BOOLEnum AICState::shouldNotBuildMarketArmoryGranaryBarracksMercenarypost( - int playerID, Commands::CommandBuildingType param_2) + int playerID, Commands::MappersEnum param_2) { if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { // nervous: reject market/mercenarypost/barracks/armory types - if (param_2 != Commands::CBT_MARKETPLACE - && param_2 != Commands::CBT_MERCENARYPOST - && param_2 != Commands::CBT_BARRACKS - && param_2 != Commands::CBT_ARMORY) { - return param_2 != Commands::CBT_GRANARY; + if (param_2 != Commands::M_MAPPER_TRADEPOST && param_2 != Commands::M_MAPPER_BARRACKS_ARAB + && param_2 != Commands::M_MAPPER_BARRACKS_EURO && param_2 != Commands::M_MAPPER_ARMOURY) { + return param_2 != Commands::M_MAPPER_GRANARY; } } else { // not nervous: only reject if destroy tracker > 0 and not marketplace if (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker > 0 - && param_2 != Commands::CBT_MARKETPLACE) { - return param_2 != Commands::CBT_GRANARY; + && param_2 != Commands::M_MAPPER_TRADEPOST) { + return param_2 != Commands::M_MAPPER_GRANARY; } } return FALSE; diff --git a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp index d2a7df33b..83caadc1e 100644 --- a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp +++ b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -7,37 +7,37 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB700 - BOOLEnum AICState::shouldWaitWithBuildingAPositiveFearFactor(int playerID, Commands::CommandBuildingType param_2) + BOOLEnum AICState::shouldWaitWithBuildingAPositiveFearFactor(int playerID, Commands::MappersEnum param_2) { switch (param_2) { - case Commands::CBT_COMMUNAL_GARDEN1: - case Commands::CBT_COMMUNAL_GARDEN2: - case Commands::CBT_COMMUNAL_GARDEN3: - case Commands::CBT_COMMUNAL_GARDEN4: - case Commands::CBT_COMMUNAL_GARDEN5: - case Commands::CBT_SHRUB_GARDEN6: - case Commands::CBT_COMMUNAL_GARDEN7: - case Commands::CBT_COMMUNAL_GARDEN8: - case Commands::CBT_COMMUNAL_GARDEN9: - case Commands::CBT_TOWN_GARDEN10: - case Commands::CBT_TOWN_GARDEN11: - case Commands::CBT_TOWN_GARDEN12: - case Commands::CBT_MAYPOLE: - case Commands::CBT_STATUE1: - case Commands::CBT_STATUE2: - case Commands::CBT_STATUE3: - case Commands::CBT_STATUE4: - case Commands::CBT_STATUE5: - case Commands::CBT_SHRINE1: - case Commands::CBT_SHRINE2: - case Commands::CBT_SHRINE3: - case Commands::CBT_SHRINE4: - case Commands::CBT_SHRINE5: - case Commands::CBT_DANCINGBEAR: - case Commands::CBT_POND_1: - case Commands::CBT_SMALL_POND_3: - case Commands::CBT_LARGE_POND_3: - case Commands::CBT_LARGE_POND_4: + case Commands::M_MAPPER_GARDEN1: + case Commands::M_MAPPER_GARDEN2: + case Commands::M_MAPPER_GARDEN3: + case Commands::M_MAPPER_GARDEN4: + case Commands::M_MAPPER_GARDEN5: + case Commands::M_MAPPER_GARDEN6: + case Commands::M_MAPPER_GARDEN7: + case Commands::M_MAPPER_GARDEN8: + case Commands::M_MAPPER_GARDEN9: + case Commands::M_MAPPER_GARDEN10: + case Commands::M_MAPPER_GARDEN11: + case Commands::M_MAPPER_GARDEN12: + case Commands::M_MAPPER_MAYPOLE: + case Commands::M_MAPPER_STATUE1: + case Commands::M_MAPPER_STATUE2: + case Commands::M_MAPPER_STATUE3: + case Commands::M_MAPPER_STATUE4: + case Commands::M_MAPPER_STATUE5: + case Commands::M_MAPPER_SHRINE1: + case Commands::M_MAPPER_SHRINE2: + case Commands::M_MAPPER_SHRINE3: + case Commands::M_MAPPER_SHRINE4: + case Commands::M_MAPPER_SHRINE5: + case Commands::M_MAPPER_DANCING_BEAR: + case Commands::M_MAPPER_POND1: + case Commands::M_MAPPER_POND2_SMALL: + case Commands::M_MAPPER_POND3_LARGE1: + case Commands::M_MAPPER_POND4_LARGE2: DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay += 1; if (DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay < 200) { return TRUE; diff --git a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp index 36ab16d6f..db2fd86bb 100644 --- a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp +++ b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -7,23 +7,23 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB610 - BOOLEnum AICState::shouldWaitWithBuildingNegativeFearFactor(int param_1, Commands::CommandBuildingType param_2) + BOOLEnum AICState::shouldWaitWithBuildingNegativeFearFactor(int param_1, Commands::MappersEnum param_2) { int* piVar1; switch (param_2) { - case Commands::CBT_GALLOWS: - case Commands::CBT_STOCKS: - case Commands::CBT_CESSPIT1: - case Commands::CBT_CESSPIT2: - case Commands::CBT_CESSPIT3: - case Commands::CBT_CESSPIT4: - case Commands::CBT_BURNINGSTAKE: - case Commands::CBT_GIBBET: - case Commands::CBT_DUNGEON: - case Commands::CBT_STRETCHINGRACK: - case Commands::CBT_RACKFLOGGING: - case Commands::CBT_CHOPPINGBLOCK: - case Commands::CBT_DUNKINGSTOOL: + case Commands::M_MAPPER_GALLOWS: + case Commands::M_MAPPER_STOCKS: + case Commands::M_MAPPER_CESS_PIT1: + case Commands::M_MAPPER_CESS_PIT2: + case Commands::M_MAPPER_CESS_PIT3: + case Commands::M_MAPPER_CESS_PIT4: + case Commands::M_MAPPER_BURNING_STAKE: + case Commands::M_MAPPER_GIBBET: + case Commands::M_MAPPER_DUNGEON: + case Commands::M_MAPPER_RACK_STRETCHING: + case Commands::M_MAPPER_RACK_FLOGGING: + case Commands::M_MAPPER_CHOPPING_BLOCK: + case Commands::M_MAPPER_DUNKING_STOOL: if ((DAT_GameState::instance.playerDataArray[param_1].popularity < 5000) || (piVar1 = &DAT_GameState::instance.playerDataArray[param_1].aivNegativeFearFactorDelay, *piVar1 = *piVar1 + 1, diff --git a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp index 43f52c12f..a92dbbe88 100644 --- a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp +++ b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp @@ -135,7 +135,8 @@ namespace AI { iVar3 = iVar3 + DAT_SkirmishDefinedData::instance .MaxBreachTribes[DAT_GameState::instance.playerDataArray[aiStack_24[iVar4]].aiType - + OpenSHC::AI::AIT_FREDERICK][0]; + + OpenSHC::AI::AIT_FREDERICK] + .tribeType; iVar4 = iVar4 + 1; @@ -158,14 +159,16 @@ namespace AI { iVar5 = iVar5 - DAT_SkirmishDefinedData::instance .MaxBreachTribes[DAT_GameState::instance.playerDataArray[iVar3].aiType - + OpenSHC::AI::AIT_FREDERICK][0]; + + OpenSHC::AI::AIT_FREDERICK] + .tribeType; if (iVar5 < 0) { DAT_GameSynchronyState::instance.DAT_ChatTauntOrMessage = -2 - DAT_SkirmishDefinedData::instance .MaxBreachTribes[DAT_GameState::instance.playerDataArray[iVar3].aiType - + OpenSHC::AI::AIT_FREDERICK][1]; + + OpenSHC::AI::AIT_FREDERICK] + .tribeCount; DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[1] = 1; diff --git a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp index 607b9a752..c0bee72c5 100644 --- a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp @@ -43,7 +43,7 @@ namespace AI { iVar5 != 0)) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToPlayerIDsKeepIfPossible, this)( - playerID, (short*)((int)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk))); + playerID, ((int)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk))); return; } @@ -53,7 +53,7 @@ namespace AI { BOOLEnum _shouldAttack = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::aiShouldAttackOrWaitForTeamCoordination, this)(playerID); if (_shouldAttack == FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRetreatUnits, this)((short*)playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRetreatUnits, this)(playerID); return; } DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; @@ -111,7 +111,7 @@ namespace AI { DAT_BuildingsState::ptr)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeEnemyKeepApproachTile, this)(playerID); if (0 < DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackTribesToLocations, this)((short*)playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackTribesToLocations, this)(playerID); return; } // state 1 with no path: reset to 0 diff --git a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp index b5ec39df2..2b4bb4481 100644 --- a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp +++ b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp @@ -4,7 +4,7 @@ #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/UnitInstructionType.hpp" @@ -19,7 +19,7 @@ namespace AI { using OpenSHC::AI::AIType; using OpenSHC::AI::AITypeInt; using OpenSHC::AI::Tribes::AITribeType; - using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Commands::MappersEnum; using OpenSHC::Map::Units::SomeTribeBehaviorType; using OpenSHC::Map::Units::UnitInstructionType; @@ -43,7 +43,7 @@ namespace AI { int* piVar4; - CommandBuildingType _siegeEngineType; + MappersEnum _siegeEngineType; int iVar5; @@ -132,7 +132,7 @@ namespace AI { /* fixme: parameter reuse */ - _siegeEngineType = (CommandBuildingType)playerID; + _siegeEngineType = (MappersEnum)playerID; do { @@ -151,8 +151,9 @@ namespace AI { _requiredEngineers = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[_counterTill6]; - _siegeEngineType = (CommandBuildingType)DAT_SkirmishDefinedData::instance - .SiegeEngineCommandBuildingTypes[_counterTill6]; + _siegeEngineType + = (MappersEnum) + DAT_SkirmishDefinedData::instance.SiegeEngineMappersEnums[_counterTill6]; break; } diff --git a/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp index ff4f4d85b..3f47b3277 100644 --- a/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp +++ b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp @@ -3,7 +3,7 @@ #include "OpenSHC/Map/Units/TroopValueState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/UnitInstructionType.hpp" @@ -16,7 +16,7 @@ namespace AI { using OpenSHC::AI::AIType; using OpenSHC::AI::Tribes::AITribeType; - using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Commands::MappersEnum; using OpenSHC::Map::Units::SomeTribeBehaviorType; using OpenSHC::Map::Units::UnitInstructionType; @@ -66,8 +66,8 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func:: placeSiegeTentOrTunnelAtSuitableLocationAndAssignEngineers, - DAT_TroopValueState::ptr)(_tribeID, OpenSHC::Commands::CBT_TUNNEL_ENTRANCE, (uint)((int)(50)), - (UnitInstructionType)((int)(21))); + DAT_TroopValueState::ptr)(_tribeID, OpenSHC::Commands::M_MAPPER_TUNNEL_CONSTRUCTION, + (uint)((int)(50)), (UnitInstructionType)((int)(21))); _size = DAT_TribesState::instance.tribes[_aiTribeID].size; } diff --git a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp index 2a2e2abcc..ed4a02035 100644 --- a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp +++ b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp @@ -10,7 +10,7 @@ namespace AI { void AICState::wipeAICMemory() { for (int i = 0; i < 20; i++) { - MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 676, '\0', &this->aics[i]); } } diff --git a/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp b/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp deleted file mode 100644 index 975bfa838..000000000 --- a/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" - -#include "OpenSHC/Globals/DAT_AIVState.hpp" - -namespace OpenSHC { -namespace AI { - - // FUNCTION: STRONGHOLDCRUSADER 0x004ECAB0 - BOOLEnum AICState::woodCuttersHutWhileNoWoodAvailable( - undefined4 playerID, Commands::CommandBuildingType commandBuildingType) - { - return ((commandBuildingType == Commands::CBT_WOODCUTTERSHUT) - && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0)); - } -} -} From 2cf4d822f190e1a904e95457fdf3dea2b65e1f6d Mon Sep 17 00:00:00 2001 From: sourcehold Date: Tue, 4 Aug 2026 12:22:43 +0200 Subject: [PATCH 021/242] sellExcessGoods 61.18% --- src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 118 ++++++++++---------- 1 file changed, 56 insertions(+), 62 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp index f0ef6d940..643d56427 100644 --- a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -14,6 +14,7 @@ namespace AI { using OpenSHC::AI::AIType; using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIC::AICSpecification; using OpenSHC::AI::Trading::AIResourceTradeCategory; using OpenSHC::AI::Trading::AIResourceTradeCategoryInt; using OpenSHC::AI::Trading::ResourceAICResourceMappingEntry; @@ -22,90 +23,83 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D1D60 void AICState ::sellExcessGoods(int param_1) { - AITypeInt AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; - if (AVar1 == OpenSHC::AI::AIT_NULL) + AITypeInt aiType = DAT_GameState::instance.playerDataArray[param_1].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) return; - int iVar3 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - AIResourceTradeCategoryInt* local_18 = &DAT_SkirmishDefinedData::instance.AIResourceTradeAICMapping[0].aic; + int aicIndex = aiType - 1; + AICSpecification& aic = this->aics[aicIndex]; + int nervousActions = DAT_GameState::instance.playerDataArray[param_1].aiNervousActionsTracker; + int& goldResource = DAT_GameState::instance.playerDataArray[param_1].currentResources[0xf]; + int& popularity = DAT_GameState::instance.playerDataArray[param_1].popularity; - do { - ResourceType resourceType - = (OpenSHC::Game::Resources::ResourceType)((ResourceAICResourceMappingEntry*)(local_18 + -1))->game; - AIResourceTradeCategoryInt AVar2 = *local_18; + for (int entryIndex = 0; entryIndex < 20; entryIndex = entryIndex + 1) { + ResourceType resourceType = (OpenSHC::Game::Resources::ResourceType)DAT_SkirmishDefinedData::instance + .AIResourceTradeAICMapping[entryIndex] + .game; + AIResourceTradeCategoryInt category + = DAT_SkirmishDefinedData::instance.AIResourceTradeAICMapping[entryIndex].aic; + int variance = aic.maxResourceVariance; + int& currentResource = DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType]; - int iVar6 = *(int*)((int)this + iVar3 + 0xc0); - int iVar5; - if (AVar2 == OpenSHC::AI::Trading::AIRTC_WOOD) { - iVar5 = *(int*)((int)this + iVar3 + 0xac); - } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { - iVar5 = *(int*)((int)this + iVar3 + 0x80); - } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_STONE) { - iVar5 = *(int*)((int)this + iVar3 + 0xb0); - } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_WEAPONS) { - iVar5 = *(int*)((int)this + iVar3 + 0xb8); - } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_ALE) { - iVar5 = *(int*)((int)this + iVar3 + 0xbc); + int amount; + if (category == OpenSHC::AI::Trading::AIRTC_WOOD) { + amount = aic.maxWood; + } else if (category == OpenSHC::AI::Trading::AIRTC_FOOD) { + amount = aic.maxFood; + } else if (category == OpenSHC::AI::Trading::AIRTC_STONE) { + amount = aic.maxStone; + } else if (category == OpenSHC::AI::Trading::AIRTC_WEAPONS) { + amount = aic.maxEquipment; + } else if (category == OpenSHC::AI::Trading::AIRTC_ALE) { + amount = aic.maxBeer; } else { - iVar5 = *(int*)((int)this + iVar3 + 0xb4); + amount = aic.maxResourceOther; } - uint uVar4 = iVar5 + iVar6; + amount = amount + variance; - if ((DAT_GameState::instance.playerDataArray[param_1].aiNervousActionsTracker <= 0) - || (DAT_GameState::instance.playerDataArray[param_1].currentResources[0xf] >= 0x1f4)) { + if ((nervousActions > 0) && (goldResource < 0x1f4)) { - if (DAT_GameState::instance.playerDataArray[param_1].popularity < *(int*)((int)this + iVar3 + 0x18)) { - if (AVar2 != OpenSHC::AI::Trading::AIRTC_FOOD) { - if (AVar2 == OpenSHC::AI::Trading::AIRTC_WEAPONS) { - uVar4 = 0; - iVar6 = 0; + if (category == OpenSHC::AI::Trading::AIRTC_FOOD) { + amount = amount / 4; + } else { + amount = ((category != OpenSHC::AI::Trading::AIRTC_WEAPONS) - 1) & 10000; + } + variance = 0; + + } else { + if (popularity < aic.criticalPopularity) { + if (category != OpenSHC::AI::Trading::AIRTC_FOOD) { + if (category == OpenSHC::AI::Trading::AIRTC_WEAPONS) { + amount = 0; } else { - uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; - iVar6 = 0; + amount = amount / 4; } - } else { - iVar6 = 0; } + variance = 0; } else { - uVar4 = uVar4 + amount = amount + DAT_GameState::instance.playerDataArray[param_1].resourcesToAcquireArray[resourceType]; } - - } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { - uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; - iVar6 = 0; - } else { - uVar4 = (AVar2 != OpenSHC::AI::Trading::AIRTC_WEAPONS) - 1 & 10000; - iVar6 = 0; } - // Check no-sell list (was LAB_004d1e81) - { - int iVar5_2 = 0; - ResourceType* pRVar7 = (ResourceType*)((int)this + iVar3 + 0xd4); - do { - if (resourceType == *pRVar7) { - uVar4 = 0; - iVar6 = 0; - break; - } - iVar5_2 = iVar5_2 + 1; - pRVar7 = pRVar7 + 1; - } while (iVar5_2 < 0xf); + int* sellResourceList = &aic.sellResource01; + for (int sellResourceIndex = 0; sellResourceIndex < 0xf; sellResourceIndex = sellResourceIndex + 1) { + if (resourceType == sellResourceList[sellResourceIndex]) { + amount = 0; + variance = 0; + break; + } } - if ((int)uVar4 < DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType]) { + if (currentResource > amount) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellGoods, this)(param_1, resourceType, - (DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType] - uVar4) + iVar6); + (DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType] - amount) + + variance); return; } - - local_18 = local_18 + 2; - if (0xb4252b < (int)local_18) - return; - - } while (true); + } } } } From a5fac8e20431ae5256edc2852e6daa2e1e5bb35d Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 5 Aug 2026 00:52:02 +0200 Subject: [PATCH 022/242] fix typo --- .../useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp index 2b4bb4481..f3e1e0afa 100644 --- a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp +++ b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp @@ -151,9 +151,8 @@ namespace AI { _requiredEngineers = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[_counterTill6]; - _siegeEngineType - = (MappersEnum) - DAT_SkirmishDefinedData::instance.SiegeEngineMappersEnums[_counterTill6]; + _siegeEngineType = (MappersEnum)DAT_SkirmishDefinedData::instance + .SiegeEngineCommandBuildingTypes[_counterTill6]; break; } From 4b318e048077580a81f1f07f74916cb32f284f32 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sun, 16 Aug 2026 23:14:43 +0200 Subject: [PATCH 023/242] improve setAICParameters_01 --- src/OpenSHC/AI/AICState/setAICParameters_01.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_01.cpp b/src/OpenSHC/AI/AICState/setAICParameters_01.cpp index 3cb13057a..d085d91ae 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_01.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_01.cpp @@ -13,16 +13,15 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004C6D60 void AICState::setAICParameters_01(int aicID) { - this->aics[aicID].populationPerFarm = 6; - this->aics[aicID].minimumCheese = 0xffffffff; - this->aics[aicID].minimumBread = 0xffffffff; - this->aics[aicID].minimumWheat = 0xffffffff; - this->aics[aicID].minimumHop = 0xffffffff; + this->aics[aicID].minimumCheese = -1; + this->aics[aicID].minimumBread = -1; + this->aics[aicID].minimumWheat = -1; + this->aics[aicID].minimumHop = -1; this->aics[aicID].aiRequestDelay = 0x12; this->aics[aicID].populationPerQuarry = 0x12; + this->aics[aicID].populationPerFarm = 6; this->aics[aicID].maxWoodcutters = 6; this->aics[aicID].maxFarms = 6; - this->aics[aicID].sellResource09 = 0x12; this->aics[aicID].flagType = 0xc; this->aics[aicID].unknown002 = 0; this->aics[aicID].unknown001 = 0; @@ -30,8 +29,8 @@ namespace AI { this->aics[aicID].unknown004 = 0; this->aics[aicID].unknown005 = 0; this->aics[aicID].criticalPopularity = 4000; - this->aics[aicID].lowestPopularity = 0x157c; - this->aics[aicID].highestPopularity = 0x1d4c; + this->aics[aicID].lowestPopularity = 5500; + this->aics[aicID].highestPopularity = 7500; this->aics[aicID].taxesMin = 3; this->aics[aicID].taxesMax = 10; this->aics[aicID].farm1 = 0x20; @@ -66,6 +65,7 @@ namespace AI { this->aics[aicID].sellResource05 = 9; this->aics[aicID].sellResource06 = 0xe; this->aics[aicID].sellResource07 = 0x10; + this->aics[aicID].sellResource09 = 0x12; this->aics[aicID].sellResource11 = 0x14; this->aics[aicID].sellResource12 = 0x15; this->aics[aicID].sellResource13 = 0x16; From c0528593a11006b9d585ebb6cca66bc57fb1a211 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Mon, 17 Aug 2026 00:09:16 +0200 Subject: [PATCH 024/242] improve setAICParameters --- .../AI/AICState/setAICParameters_03.cpp | 14 +- .../AI/AICState/setAICParameters_04.cpp | 10 +- .../AI/AICState/setAICParameters_05.cpp | 20 +-- .../AI/AICState/setAICParameters_06.cpp | 32 ++-- .../AI/AICState/setAICParameters_07.cpp | 8 +- .../AI/AICState/setAICParameters_08.cpp | 144 +---------------- .../AI/AICState/setAICParameters_09.cpp | 141 +--------------- .../AI/AICState/setAICParameters_10.cpp | 140 +--------------- .../AI/AICState/setAICParameters_11.cpp | 152 ++---------------- .../AI/AICState/setAICParameters_12.cpp | 138 +--------------- .../AI/AICState/setAICParameters_13.cpp | 141 +--------------- .../AI/AICState/setAICParameters_14.cpp | 12 +- .../AI/AICState/setAICParameters_15.cpp | 135 +--------------- .../AI/AICState/setAICParameters_16.cpp | 138 +--------------- 14 files changed, 76 insertions(+), 1149 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_03.cpp b/src/OpenSHC/AI/AICState/setAICParameters_03.cpp index 2305891ed..7f8f963a3 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_03.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_03.cpp @@ -13,8 +13,8 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004C7520 void AICState::setAICParameters_03(int param_1) { - this->aics[param_1].minimumWheat = 0xffffffff; - this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].minimumWheat = -1; + this->aics[param_1].minimumHop = -1; this->aics[param_1].flagType = 0xc; this->aics[param_1].unknown002 = 0; this->aics[param_1].unknown001 = 0; @@ -84,8 +84,10 @@ namespace AI { this->aics[param_1].RecruitInterval = 1; this->aics[param_1].RecruitIntervalStrong = 4; this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].OuterPatrolRallyDelay = 0x14; this->aics[param_1].SortieUnitMeleeMin = 5; + this->aics[param_1].SortieUnitRanged = 0x17; + this->aics[param_1].SortieUnitMelee = 0x1a; + this->aics[param_1].OuterPatrolRallyDelay = 0x14; this->aics[param_1].RaidUnitsRandom = 5; this->aics[param_1].recruitProbRaidStrong = 0; this->aics[param_1].recruitProbAttackWeak = 0; @@ -103,14 +105,12 @@ namespace AI { this->aics[param_1].RaidRetargetDelay = 3; this->aics[param_1].AttForceBase = 10; this->aics[param_1].AttForceRandom = 10; - this->aics[param_1].SortieUnitRanged = 0x17; + this->aics[param_1].AttForceSupportAllyThreshold = 10; + this->aics[param_1].AttForceRallyPercentage = 0x3c; this->aics[param_1].DefUnit1 = 0x17; this->aics[param_1].DefUnit2 = 0x17; this->aics[param_1].DefUnit3 = 0x17; - this->aics[param_1].SortieUnitMelee = 0x1a; this->aics[param_1].RaidUnit1 = 0x1a; - this->aics[param_1].AttForceSupportAllyThreshold = 10; - this->aics[param_1].AttForceRallyPercentage = 0x3c; this->aics[param_1].AttMovingTribesThreshold = 100; this->aics[param_1].AttAssaultDelay = 5; this->aics[param_1].AttUnitPatrolRecommandDelay = 0xf; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_04.cpp b/src/OpenSHC/AI/AICState/setAICParameters_04.cpp index e81e060e1..913127402 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_04.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_04.cpp @@ -17,8 +17,8 @@ namespace AI { this->aics[param_1].unknown005 = 1; this->aics[param_1].farm2 = 0x20; this->aics[param_1].farm4 = 0x20; - this->aics[param_1].minimumWheat = 0xffffffff; - this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].minimumWheat = -1; + this->aics[param_1].minimumHop = -1; this->aics[param_1].flagType = 0xd; this->aics[param_1].unknown002 = 0; this->aics[param_1].unknown001 = 0; @@ -91,7 +91,9 @@ namespace AI { this->aics[param_1].SortieUnitRangedMin = 8; this->aics[param_1].SortieUnitRanged = 0x46; this->aics[param_1].SortieUnitMeleeMin = 6; + this->aics[param_1].SortieUnitMelee = 0x19; this->aics[param_1].DefDiggingUnitMax = 8; + this->aics[param_1].DefDiggingUnit = 0x19; this->aics[param_1].DefWalls = 0x50; this->aics[param_1].DefTotal = 100; this->aics[param_1].OuterPatrolGroupsMove = 1; @@ -104,11 +106,9 @@ namespace AI { this->aics[param_1].RaidUnit2 = 0x4a; this->aics[param_1].HarassingSiegeEngine1 = 0xbe; this->aics[param_1].RaidRetargetDelay = 5; + this->aics[param_1].AttForceBase = 0x28; this->aics[param_1].AttForceRandom = 0xf; this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; - this->aics[param_1].SortieUnitMelee = 0x19; - this->aics[param_1].DefDiggingUnit = 0x19; - this->aics[param_1].AttForceBase = 0x28; this->aics[param_1].AttForceRallyPercentage = 0x50; this->aics[param_1].AttMovingTribesThreshold = 100; this->aics[param_1].AttAssaultDelay = 0xc; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_05.cpp b/src/OpenSHC/AI/AICState/setAICParameters_05.cpp index b3958aa09..ad9eb85f1 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_05.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_05.cpp @@ -78,39 +78,39 @@ namespace AI { this->aics[param_1].recruitProbDefStrong = 0x19; this->aics[param_1].RaidUnitsRandom = 5; this->aics[param_1].HarassingSiegeEnginesMax = 5; + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; this->aics[param_1].RecruitIntervalWeak = 1; this->aics[param_1].RecruitInterval = 1; this->aics[param_1].RecruitIntervalStrong = 1; this->aics[param_1].SortieUnitRangedMin = 10; + this->aics[param_1].SortieUnitMeleeMin = 7; + this->aics[param_1].SortieUnitMelee = 0x4b; + this->aics[param_1].SortieUnitRanged = 0x46; this->aics[param_1].OuterPatrolGroupsMove = 1; this->aics[param_1].OuterPatrolRallyDelay = 10; this->aics[param_1].RaidUnitsBase = 10; this->aics[param_1].AttForceRandom = 10; + this->aics[param_1].AttForceBase = 0x32; + this->aics[param_1].AttForceSupportAllyThreshold = 8; + this->aics[param_1].AttForceRallyPercentage = 0x50; this->aics[param_1].recruitProbRaidWeak = 0; this->aics[param_1].recruitProbRaidStrong = 0x19; this->aics[param_1].recruitProbAttackWeak = 0; this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].SortieUnitMeleeMin = 7; - this->aics[param_1].SortieUnitMelee = 0x4b; this->aics[param_1].DefDiggingUnitMax = 4; this->aics[param_1].DefDiggingUnit = 0x47; this->aics[param_1].DefWalls = 0x32; this->aics[param_1].OuterPatrolGroupsCount = 2; this->aics[param_1].DefUnit1 = 0x4b; + this->aics[param_1].DefUnit2 = 0x46; + this->aics[param_1].DefUnit3 = 0x46; + this->aics[param_1].DefUnit4 = 0x46; this->aics[param_1].DefUnit5 = 0x4c; this->aics[param_1].RaidUnit1 = 0x4a; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; this->aics[param_1].RaidRetargetDelay = 3; - this->aics[param_1].AttForceBase = 0x32; this->aics[param_1].recruitProbRaidDefault = 0x21; this->aics[param_1].recruitProbAttackDefault = 0x21; - this->aics[param_1].SortieUnitRanged = 0x46; this->aics[param_1].DefTotal = 0x46; - this->aics[param_1].DefUnit2 = 0x46; - this->aics[param_1].DefUnit3 = 0x46; - this->aics[param_1].DefUnit4 = 0x46; - this->aics[param_1].AttForceSupportAllyThreshold = 8; - this->aics[param_1].AttForceRallyPercentage = 0x50; this->aics[param_1].AttMovingTribesThreshold = 100; this->aics[param_1].AttAssaultDelay = 4; this->aics[param_1].AttUnitPatrolRecommandDelay = 1; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_06.cpp b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp index 2a28425db..b80d16350 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_06.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp @@ -14,13 +14,13 @@ namespace AI { { - this->aics[param_1].minimumCheese = 0xffffffff; + this->aics[param_1].minimumCheese = -1; - this->aics[param_1].minimumBread = 0xffffffff; + this->aics[param_1].minimumBread = -1; - this->aics[param_1].minimumWheat = 0xffffffff; + this->aics[param_1].minimumWheat = -1; - this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].minimumHop = -1; this->aics[param_1].taxesMax = 0xc; @@ -142,8 +142,6 @@ namespace AI { this->aics[param_1].unknown072 = 100; - this->aics[param_1].SortieUnitRangedMin = 7; - this->aics[param_1].unknown073 = 0x14; this->aics[param_1].recruitProbRaidWeak = 0x14; @@ -156,8 +154,14 @@ namespace AI { this->aics[param_1].RecruitIntervalStrong = 0; + this->aics[param_1].SortieUnitRangedMin = 7; + this->aics[param_1].SortieUnitMeleeMin = 5; + this->aics[param_1].SortieUnitRanged = 0x46; + + this->aics[param_1].SortieUnitMelee = 0x4b; + this->aics[param_1].OuterPatrolGroupsCount = 2; this->aics[param_1].HarassingSiegeEnginesMax = 2; @@ -176,8 +180,6 @@ namespace AI { this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].SortieUnitMelee = 0x4b; - this->aics[param_1].DefDiggingUnitMax = 4; this->aics[param_1].DefDiggingUnit = 0x47; @@ -192,20 +194,18 @@ namespace AI { this->aics[param_1].DefUnit1 = 0x4c; - this->aics[param_1].RaidUnitsBase = 0x1e; - - this->aics[param_1].RaidUnitsRandom = 0x1e; - - this->aics[param_1].RaidUnit1 = 0x47; - - this->aics[param_1].SortieUnitRanged = 0x46; - this->aics[param_1].DefUnit2 = 0x46; this->aics[param_1].DefUnit3 = 0x46; this->aics[param_1].DefUnit4 = 0x46; + this->aics[param_1].RaidUnitsBase = 0x1e; + + this->aics[param_1].RaidUnitsRandom = 0x1e; + + this->aics[param_1].RaidUnit1 = 0x47; + this->aics[param_1].HarassingSiegeEngine1 = 0x166; this->aics[param_1].HarassingSiegeEngine2 = 0xbe; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp index 84fc2c94a..9e00fc0d3 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp @@ -14,13 +14,13 @@ namespace AI { { - this->aics[param_1].minimumCheese = 0xffffffff; + this->aics[param_1].minimumCheese = -1; - this->aics[param_1].minimumBread = 0xffffffff; + this->aics[param_1].minimumBread = -1; - this->aics[param_1].minimumWheat = 0xffffffff; + this->aics[param_1].minimumWheat = -1; - this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].minimumHop = -1; this->aics[param_1].maxEquipment = 5; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_08.cpp b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp index fbc4839a2..038ccf902 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_08.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp @@ -8,282 +8,144 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C8920 void AICState ::setAICParameters_08(int param_1) - { - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].farm3 = 0x20; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].minimumApples = 5; - this->aics[param_1].minimumCheese = 5; - - this->aics[param_1].minimumBread = 0xffffffff; - - this->aics[param_1].minimumWheat = 0xffffffff; - - this->aics[param_1].minimumHop = 0xffffffff; - + this->aics[param_1].minimumBread = -1; + this->aics[param_1].minimumWheat = -1; + this->aics[param_1].minimumHop = -1; this->aics[param_1].tradeAmountFood = 5; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown005 = 0; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMin = 3; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].farm1 = 0x21; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 0xc; - this->aics[param_1].maxFood = 200; - this->aics[param_1].tradeAmountEquipment = 2; - this->aics[param_1].aiRequestDelay = 0x16; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxWood = 0x32; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 10; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 10; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 3; - this->aics[param_1].maxIronmines = 4; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxFarms = 0xf; - this->aics[param_1].buildInterval = 4; - this->aics[param_1].resourceRebuildDelay = 0x14; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x14; - this->aics[param_1].sellResource02 = 3; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource06 = 0xe; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].defWallPatrolRallyTime = 8; - this->aics[param_1].defWallPatrolGroups = 4; - this->aics[param_1].defSiegeEngineGoldThreshold = 200; - this->aics[param_1].defSiegeEngineBuildDelay = 2; - this->aics[param_1].unknown072 = 100; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x5a; - this->aics[param_1].recruitProbDefDefault = 0x1e; - this->aics[param_1].recruitProbDefStrong = 10; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].RaidUnitsBase = 10; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbRaidDefault = 0; - this->aics[param_1].recruitProbRaidStrong = 0; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].DefDiggingUnitMax = 0; - this->aics[param_1].DefWalls = 0x14; - this->aics[param_1].OuterPatrolGroupsCount = 2; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].DefUnit2 = 0x16; - this->aics[param_1].RaidUnitsRandom = 4; - this->aics[param_1].RaidUnit1 = 0x16; - this->aics[param_1].HarassingSiegeEnginesMax = 2; - this->aics[param_1].AttForceBase = 0x14; - this->aics[param_1].recruitProbAttackDefault = 0x46; - this->aics[param_1].recruitProbAttackStrong = 0x5a; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].SortieUnitRangedMin = 6; - this->aics[param_1].SortieUnitMeleeMin = 6; - this->aics[param_1].SortieUnitMelee = 0x19; - this->aics[param_1].DefDiggingUnit = 0x19; - this->aics[param_1].DefTotal = 0x28; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 5; - this->aics[param_1].DefUnit3 = 0x19; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RaidRetargetDelay = 5; - this->aics[param_1].AttForceRandom = 5; - this->aics[param_1].AttForceSupportAllyThreshold = 10; - this->aics[param_1].AttForceRallyPercentage = 10; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0x14; - this->aics[param_1].AttUnitPatrolRecommandDelay = 2; - this->aics[param_1].AttCoordinationPreference = 10; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].SiegeEngine2 = 0x27; - this->aics[param_1].SiegeEngine3 = 0x27; - this->aics[param_1].SiegeEngine4 = 0x3b; - this->aics[param_1].SiegeEngine5 = 0x28; - this->aics[param_1].SiegeEngine6 = 0x28; - this->aics[param_1].AttMaxEngineers = 0x10; - this->aics[param_1].AttDiggingUnit = 0x19; - this->aics[param_1].AttDiggingUnitMax = 6; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 3; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x14; - this->aics[param_1].AttUnitBackupGroupsCount = 2; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0x1b; - this->aics[param_1].AttUnitSiegeDefMax = 4; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 2; - this->aics[param_1].AttUnitMain1 = 0x1b; - this->aics[param_1].AttUnitMain2 = 0x19; - this->aics[param_1].AttUnitMain3 = 0x19; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 3; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_09.cpp b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp index 28bd5aac5..1000c8508 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_09.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp @@ -8,276 +8,141 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C8D20 void AICState ::setAICParameters_09(int param_1) - { - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].minimumApples = 5; - this->aics[param_1].minimumCheese = 5; - - this->aics[param_1].minimumBread = 0xffffffff; - - this->aics[param_1].minimumWheat = 0xffffffff; - - this->aics[param_1].minimumHop = 0xffffffff; - + this->aics[param_1].minimumBread = -1; + this->aics[param_1].minimumWheat = -1; + this->aics[param_1].minimumHop = -1; this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 0x157c; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 3; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].farm1 = 0x21; - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].farm3 = 0x1f; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 0xc; - this->aics[param_1].maxFood = 200; - this->aics[param_1].tradeAmountFood = 10; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0x16; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxResourceOther = 0xf; - this->aics[param_1].maxEquipment = 0x14; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 0xc; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 4; - this->aics[param_1].maxIronmines = 5; - this->aics[param_1].maxWoodcutters = 0xc; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 0xc; - this->aics[param_1].buildInterval = 4; - this->aics[param_1].resourceRebuildDelay = 0x1e; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = -999; - this->aics[param_1].poleturnerSetting = 0x14; - this->aics[param_1].sellResource04 = 7; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].defWallPatrolRallyTime = 8; - this->aics[param_1].defWallPatrolGroups = 2; - this->aics[param_1].defSiegeEngineGoldThreshold = 200; - this->aics[param_1].defSiegeEngineBuildDelay = 2; - this->aics[param_1].unknown072 = 100; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 100; - this->aics[param_1].recruitProbDefDefault = 0x32; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].AttForceSupportAllyThreshold = 0x14; - this->aics[param_1].RecruitInterval = 4; - this->aics[param_1].RecruitIntervalStrong = 4; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].SortieUnitMeleeMin = 4; - this->aics[param_1].DefDiggingUnitMax = 10; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].OuterPatrolRallyDelay = 10; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].DefUnit2 = 0x16; - this->aics[param_1].RaidUnitsBase = 4; - this->aics[param_1].AttForceRandom = 4; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackWeak = 0; - this->aics[param_1].recruitProbAttackDefault = 0x1e; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].SortieUnitRangedMin = 0xc; - this->aics[param_1].SortieUnitMelee = 0x1b; - this->aics[param_1].DefWalls = 0x32; - this->aics[param_1].DefTotal = 0x50; - this->aics[param_1].OuterPatrolGroupsCount = 2; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].DefUnit3 = 0x17; - this->aics[param_1].RaidUnitsRandom = 0; - this->aics[param_1].RaidUnit1 = 0x1c; - this->aics[param_1].HarassingSiegeEnginesMax = 2; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RaidRetargetDelay = 6; - this->aics[param_1].AttForceBase = 0x1e; - this->aics[param_1].AttForceRallyPercentage = 0x32; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0x14; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x32; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x28; - this->aics[param_1].SiegeEngine2 = 0x28; - this->aics[param_1].SiegeEngine3 = 0x28; - this->aics[param_1].SiegeEngine4 = 0x28; - this->aics[param_1].SiegeEngine5 = 0x28; - this->aics[param_1].SiegeEngine6 = 0x28; - this->aics[param_1].AttMaxEngineers = 0x12; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0x17; - this->aics[param_1].AttUnitPatrolMax = 0x14; - this->aics[param_1].AttUnitPatrolGroupsCount = 1; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x1e; - this->aics[param_1].AttUnitBackupGroupsCount = 2; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0x17; - this->aics[param_1].AttUnitSiegeDefMax = 10; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; - this->aics[param_1].AttUnitMain1 = 0x1b; - this->aics[param_1].AttUnitMain2 = 0x1b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 4; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp index 0d6b6afba..8b1e50bce 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp @@ -1,6 +1,5 @@ #include "OpenSHC/AI/AICState.func.hpp" #include "OpenSHC/AI/AIC/AITargetChoice.hpp" - namespace OpenSHC { namespace AI { @@ -8,276 +7,141 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C9120 void AICState ::setAICParameters_10(int param_1) - { - this->aics[param_1].taxesMin = 2; - this->aics[param_1].farm1 = 0x20; - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].tradeAmountEquipment = 2; - - this->aics[param_1].minimumWheat = 0xffffffff; - - this->aics[param_1].minimumHop = 0xffffffff; - + this->aics[param_1].minimumWheat = -1; + this->aics[param_1].minimumHop = -1; this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].resourceRebuildDelay = 0x3c; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].populationPerFarm = 5; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumCheese = 10; - this->aics[param_1].minimumBread = 10; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x32; - this->aics[param_1].maxResourceOther = 0xf; - this->aics[param_1].maxEquipment = 6; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 0; - this->aics[param_1].populationPerIronmine = 7; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 1; - this->aics[param_1].maxIronmines = 3; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 8; - this->aics[param_1].buildInterval = 4; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource02 = 3; - this->aics[param_1].sellResource04 = 7; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource06 = 0xe; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x46; - this->aics[param_1].recruitProbDefDefault = 0x28; - this->aics[param_1].RecruitIntervalWeak = 4; - this->aics[param_1].RecruitInterval = 4; - this->aics[param_1].RecruitIntervalStrong = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].DefWalls = 4; - this->aics[param_1].OuterPatrolGroupsCount = 4; - this->aics[param_1].RaidUnitsBase = 4; - this->aics[param_1].RaidUnitsRandom = 4; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x14; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].recruitProbAttackDefault = 0x14; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].SortieUnitMeleeMin = 0x14; - this->aics[param_1].DefTotal = 0x14; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].DefUnit2 = 0x16; - this->aics[param_1].DefUnit3 = 0x16; - this->aics[param_1].DefUnit4 = 0x16; - this->aics[param_1].DefUnit5 = 0x16; - this->aics[param_1].DefUnit6 = 0x16; - this->aics[param_1].HarassingSiegeEnginesMax = 1; - this->aics[param_1].recruitProbRaidDefault = 0x28; - this->aics[param_1].recruitProbAttackStrong = 0x3c; - this->aics[param_1].SortieUnitRangedMin = 2; - this->aics[param_1].SortieUnitMelee = 0x18; - this->aics[param_1].DefDiggingUnit = 0x18; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x1c; - this->aics[param_1].RaidUnit1 = 0x1c; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].AttForceBase = 10; - this->aics[param_1].AttForceRandom = 0x14; - this->aics[param_1].AttForceSupportAllyThreshold = 0x28; - this->aics[param_1].AttForceRallyPercentage = 0x28; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x46; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0; - this->aics[param_1].AttMaxEngineers = 0; - this->aics[param_1].AttDiggingUnit = 0x18; - this->aics[param_1].AttDiggingUnitMax = 0x3c; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0x18; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0; - this->aics[param_1].AttUnitBackupMax = 0; - this->aics[param_1].AttUnitBackupGroupsCount = 0; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x18; - this->aics[param_1].AttUnitMain2 = 0x18; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_11.cpp b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp index 9f6a82e8a..2296787e0 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_11.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp @@ -8,274 +8,140 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C94F0 void AICState ::setAICParameters_11(int param_1) - { - this->aics[param_1].taxesMin = 2; - - this->aics[param_1].minimumApples = 0xffffffff; - - this->aics[param_1].minimumCheese = 0xffffffff; - - this->aics[param_1].minimumBread = 0xffffffff; - + this->aics[param_1].minimumApples = -1; + this->aics[param_1].minimumCheese = -1; + this->aics[param_1].minimumBread = -1; this->aics[param_1].minimumWheat = 2; - - this->aics[param_1].minimumHop = 0xffffffff; - + this->aics[param_1].minimumHop = -1; this->aics[param_1].flagType = 10; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm1 = 0x1e; - this->aics[param_1].populationPerFarm = 5; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0x16; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x1e; - this->aics[param_1].doubleRationsFoodThreshold = 0x32; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x28; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 100; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 6; - this->aics[param_1].populationPerIronmine = 0xc; - this->aics[param_1].populationPerPitchrig = 6; - this->aics[param_1].maxQuarries = 3; - this->aics[param_1].maxIronmines = 1; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 4; - this->aics[param_1].maxFarms = 8; - this->aics[param_1].buildInterval = 3; - this->aics[param_1].resourceRebuildDelay = 0x32; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource02 = 3; - this->aics[param_1].sellResource03 = 6; - this->aics[param_1].sellResource06 = 0xe; - this->aics[param_1].sellResource08 = 0x11; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x46; - this->aics[param_1].recruitProbDefDefault = 0x1e; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x14; - this->aics[param_1].recruitProbAttackWeak = 0x1e; - this->aics[param_1].DefDiggingUnitMax = 4; - + this->aics[param_1].DefDiggingUnit = 0x47; this->aics[param_1].RaidUnitsBase = 0x1e; - this->aics[param_1].HarassingSiegeEnginesMax = 4; - + this->aics[param_1].HarassingSiegeEngine1 = 0x166; this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].SortieUnitMeleeMin = 10; - + this->aics[param_1].SortieUnitRangedMin = 6; + this->aics[param_1].SortieUnitMelee = 0x4b; + this->aics[param_1].SortieUnitRanged = 0x4a; this->aics[param_1].RaidUnitsRandom = 10; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbAttackDefault = 0x32; - this->aics[param_1].recruitProbAttackStrong = 0x3c; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 1; - - this->aics[param_1].SortieUnitRangedMin = 6; - - this->aics[param_1].SortieUnitMelee = 0x4b; - - this->aics[param_1].DefDiggingUnit = 0x47; - this->aics[param_1].DefWalls = 0x28; - this->aics[param_1].DefTotal = 0x28; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x46; - this->aics[param_1].DefUnit2 = 0x4c; - - this->aics[param_1].HarassingSiegeEngine1 = 0x166; - this->aics[param_1].AttForceBase = 0x28; - this->aics[param_1].AttForceRandom = 5; - - this->aics[param_1].SortieUnitRanged = 0x4a; - this->aics[param_1].RaidUnit1 = 0x4a; - this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; - this->aics[param_1].AttForceRallyPercentage = 0x50; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 4; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x5a; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x28; - this->aics[param_1].SiegeEngine2 = 0x4d; - this->aics[param_1].SiegeEngine3 = 0x4d; - this->aics[param_1].SiegeEngine4 = 0x4d; - this->aics[param_1].AttMaxEngineers = 9; - this->aics[param_1].AttDiggingUnit = 0x47; - this->aics[param_1].AttDiggingUnitMax = 0xf; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x4a; - this->aics[param_1].AttUnitBackupMax = 0x50; - this->aics[param_1].AttUnitBackupGroupsCount = 1; - this->aics[param_1].AttUnitEngageMax = 10; - this->aics[param_1].AttUnitEngage = 0x4c; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x4b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp index a09be5a21..d2c250af1 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp @@ -8,274 +8,140 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C9900 void AICState ::setAICParameters_12(int param_1) - { - this->aics[param_1].farm1 = 0x1e; - this->aics[param_1].farm3 = 0x1e; - - this->aics[param_1].minimumCheese = 0xffffffff; - - this->aics[param_1].minimumBread = 0xffffffff; - + this->aics[param_1].minimumCheese = -1; + this->aics[param_1].minimumBread = -1; this->aics[param_1].flagType = 10; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].farm4 = 0x1f; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 0x50; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumWheat = 2; - this->aics[param_1].minimumHop = 2; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 6; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 4; - this->aics[param_1].maxIronmines = 3; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 0x10; - this->aics[param_1].buildInterval = 2; - this->aics[param_1].resourceRebuildDelay = 0x28; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x50; - this->aics[param_1].recruitProbDefDefault = 0x28; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 10; - this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].SortieUnitMeleeMin = 0x14; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].RaidUnitsRandom = 10; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackDefault = 0x28; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitInterval = 0; - this->aics[param_1].RecruitIntervalStrong = 0; - this->aics[param_1].SortieUnitRanged = 0x46; - this->aics[param_1].SortieUnitMelee = 0x4b; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].DefWalls = 0x32; - this->aics[param_1].DefTotal = 0x32; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].DefUnit2 = 0x46; - this->aics[param_1].RaidUnitsBase = 0x1e; - this->aics[param_1].RaidUnit1 = 0x4b; - this->aics[param_1].HarassingSiegeEnginesMax = 3; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].HarassingSiegeEngine2 = 0xbe; - this->aics[param_1].HarassingSiegeEngine3 = 0x166; - this->aics[param_1].AttForceBase = 0x1e; - this->aics[param_1].AttForceRandom = 10; - this->aics[param_1].AttForceSupportAllyThreshold = 0x14; - this->aics[param_1].AttForceRallyPercentage = 0x50; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x50; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].SiegeEngine2 = 0x27; - this->aics[param_1].SiegeEngine3 = 0x3d; - this->aics[param_1].AttMaxEngineers = 6; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 0xf; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x4a; - this->aics[param_1].AttUnitBackupMax = 0x50; - this->aics[param_1].AttUnitBackupGroupsCount = 1; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x4b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_13.cpp b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp index be05cbf93..1bfe3d4ef 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_13.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp @@ -8,268 +8,137 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C9CF0 void AICState ::setAICParameters_13(int param_1) - { - - this->aics[param_1].minimumCheese = 0xffffffff; - - this->aics[param_1].minimumBread = 0xffffffff; - + this->aics[param_1].minimumCheese = -1; + this->aics[param_1].minimumBread = -1; this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumWheat = 5; - this->aics[param_1].minimumHop = 5; - this->aics[param_1].recruitGoldThreshold = 100; - this->aics[param_1].flagType = 10; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm1 = 0x1e; - this->aics[param_1].farm2 = 0x1e; - this->aics[param_1].farm3 = 0x1e; - this->aics[param_1].farm4 = 0x1f; - this->aics[param_1].populationPerFarm = 3; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].tradeAmountFood = 10; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x1e; - this->aics[param_1].doubleRationsFoodThreshold = 0x1e; - this->aics[param_1].maxWood = 0x32; - this->aics[param_1].maxStone = 0x28; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 0x14; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0xf; - this->aics[param_1].maxQuarries = 1; - this->aics[param_1].maxIronmines = 2; - this->aics[param_1].maxWoodcutters = 0xc; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 0x10; - this->aics[param_1].buildInterval = 1; - this->aics[param_1].resourceRebuildDelay = 0x14; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource03 = 6; - this->aics[param_1].sellResource08 = 0x11; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x50; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackDefault = 0x1e; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].RecruitInterval = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].recruitProbDefDefault = 0x32; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbAttackWeak = 0x14; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitIntervalWeak = 8; - this->aics[param_1].SortieUnitRanged = 0x46; - + this->aics[param_1].SortieUnitRangedMin = 5; this->aics[param_1].SortieUnitMeleeMin = 0xf; - this->aics[param_1].SortieUnitMelee = 0x46; - this->aics[param_1].DefDiggingUnitMax = 0x3c; - this->aics[param_1].DefDiggingUnit = 0x47; - this->aics[param_1].DefWalls = 0x50; - this->aics[param_1].DefTotal = 0x50; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x46; - this->aics[param_1].HarassingSiegeEnginesMax = 0; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].AttForceBase = 0x28; - this->aics[param_1].AttForceRandom = 0; - - this->aics[param_1].SortieUnitRangedMin = 5; - + this->aics[param_1].AttForceSupportAllyThreshold = 10; + this->aics[param_1].AttForceRallyPercentage = 0x32; this->aics[param_1].RaidUnitsBase = 5; - this->aics[param_1].RaidUnitsRandom = 5; - this->aics[param_1].RaidUnit1 = 0x49; - - this->aics[param_1].AttForceSupportAllyThreshold = 10; - - this->aics[param_1].AttForceRallyPercentage = 0x32; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x32; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].AttMaxEngineers = 0; - this->aics[param_1].AttDiggingUnit = 0x47; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 0x28; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x4a; - this->aics[param_1].AttUnitBackupMax = 0; - this->aics[param_1].AttUnitBackupGroupsCount = 0; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x49; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 4; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp index c5590667e..91bb5efe5 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp @@ -150,6 +150,8 @@ namespace AI { this->aics[param_1].DefDiggingUnitMax = 4; + this->aics[param_1].DefDiggingUnit = 0x1a; + this->aics[param_1].RaidUnitsRandom = 4; this->aics[param_1].RaidRetargetDelay = 4; @@ -164,6 +166,10 @@ namespace AI { this->aics[param_1].SortieUnitMeleeMin = 10; + this->aics[param_1].SortieUnitRanged = 0x17; + + this->aics[param_1].SortieUnitMelee = 0x1a; + this->aics[param_1].DefTotal = 0x32; this->aics[param_1].RaidUnitsBase = 10; @@ -174,8 +180,6 @@ namespace AI { this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].SortieUnitRanged = 0x17; - this->aics[param_1].DefWalls = 0x28; this->aics[param_1].OuterPatrolGroupsCount = 1; @@ -200,10 +204,6 @@ namespace AI { this->aics[param_1].HarassingSiegeEngine2 = 0x166; - this->aics[param_1].SortieUnitMelee = 0x1a; - - this->aics[param_1].DefDiggingUnit = 0x1a; - this->aics[param_1].RaidUnit1 = 0x1a; this->aics[param_1].AttForceBase = 0x32; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_15.cpp b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp index db36e5ca0..f05d8235b 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_15.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp @@ -8,268 +8,137 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CA4D0 void AICState ::setAICParameters_15(int param_1) - { - this->aics[param_1].farm1 = 0x21; - this->aics[param_1].farm3 = 0x21; - this->aics[param_1].farm4 = 0x21; - this->aics[param_1].populationPerFarm = 5; - this->aics[param_1].minimumHop = 5; - - this->aics[param_1].minimumBread = 0xffffffff; - - this->aics[param_1].minimumWheat = 0xffffffff; - + this->aics[param_1].minimumBread = -1; + this->aics[param_1].minimumWheat = -1; this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 7; - this->aics[param_1].populationPerIronmine = 7; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].maxResourceOther = 0xc; - this->aics[param_1].maxIronmines = 3; - this->aics[param_1].buildInterval = 3; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].farm2 = 0x1f; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumCheese = 10; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0; - this->aics[param_1].doubleRationsFoodThreshold = 0x50; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x32; - this->aics[param_1].maxEquipment = 10; - this->aics[param_1].maxBeer = 6; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 1; - this->aics[param_1].maxWoodcutters = 8; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 9; - this->aics[param_1].resourceRebuildDelay = 0x28; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource04 = 7; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].RecruitIntervalStrong = 4; - this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].SortieUnitMeleeMin = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].RaidUnitsRandom = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].recruitProbRaidWeak = 0x28; - this->aics[param_1].recruitProbRaidDefault = 0x28; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].DefTotal = 0x28; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].AttForceBase = 10; - this->aics[param_1].AttForceSupportAllyThreshold = 10; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x32; - this->aics[param_1].recruitProbDefDefault = 0x1e; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackDefault = 0x1e; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].SortieUnitMelee = 0x1c; - this->aics[param_1].DefWalls = 0x1e; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].RaidUnitsBase = 0x10; - this->aics[param_1].RaidUnit1 = 0x1c; - this->aics[param_1].HarassingSiegeEnginesMax = 1; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].AttForceRandom = 0x14; - this->aics[param_1].AttForceRallyPercentage = 0x32; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x46; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x28; - this->aics[param_1].SiegeEngine2 = 0x28; - this->aics[param_1].AttMaxEngineers = 6; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x1e; - this->aics[param_1].AttUnitBackupGroupsCount = 3; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x1b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_16.cpp b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp index 98b8a0d26..d7e7a4390 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_16.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp @@ -6,272 +6,138 @@ namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CA8A0 void AICState ::setAICParameters_16(int param_1) - { - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm2 = 0x1e; - this->aics[param_1].farm3 = 0x1e; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].maxFarms = 0xc; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].farm1 = 0x1f; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumApples = 10; - - this->aics[param_1].minimumCheese = 0xffffffff; - - this->aics[param_1].minimumBread = 0xffffffff; - + this->aics[param_1].minimumCheese = -1; + this->aics[param_1].minimumBread = -1; this->aics[param_1].minimumWheat = 2; - this->aics[param_1].minimumHop = 2; - this->aics[param_1].tradeAmountFood = 5; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x28; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 5; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 0x32; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 6; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 4; - this->aics[param_1].maxIronmines = 2; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 0; - this->aics[param_1].buildInterval = 2; - this->aics[param_1].resourceRebuildDelay = 0x28; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource03 = 6; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x50; - this->aics[param_1].recruitProbDefDefault = 0x28; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 10; - this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].recruitProbAttackDefault = 0x28; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].SortieUnitMeleeMin = 0x14; - this->aics[param_1].SortieUnitMelee = 0x25; - this->aics[param_1].DefWalls = 0x1e; - this->aics[param_1].DefTotal = 0x1e; - this->aics[param_1].RaidUnitsBase = 0x1e; - this->aics[param_1].RaidUnitsRandom = 10; - this->aics[param_1].RaidUnit1 = 0x25; - this->aics[param_1].HarassingSiegeEnginesMax = 5; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].AttForceBase = 0x32; - this->aics[param_1].AttForceRandom = 10; - this->aics[param_1].AttForceSupportAllyThreshold = 0x28; - this->aics[param_1].AttForceRallyPercentage = 0x50; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x50; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].SiegeEngine2 = 0x27; - this->aics[param_1].SiegeEngine3 = 0x27; - this->aics[param_1].SiegeEngine4 = 0x27; - this->aics[param_1].AttMaxEngineers = 8; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 10; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x28; - this->aics[param_1].AttUnitBackupGroupsCount = 1; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x25; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; - return; } - } } From 970160ccded2b521e73de4964e1e4ddf495b3b06 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Mon, 17 Aug 2026 21:08:23 +0200 Subject: [PATCH 025/242] improve setAICParameters --- src/OpenSHC/AI/AICState/setAICParameters_07.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp index 9e00fc0d3..589ad5bd9 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp @@ -22,10 +22,6 @@ namespace AI { this->aics[param_1].minimumHop = -1; - this->aics[param_1].maxEquipment = 5; - - this->aics[param_1].maxResourceVariance = 5; - this->aics[param_1].flagType = 10; this->aics[param_1].unknown002 = 0; @@ -74,8 +70,12 @@ namespace AI { this->aics[param_1].maxResourceOther = 10; + this->aics[param_1].maxEquipment = 5; + this->aics[param_1].maxBeer = 0x14; + this->aics[param_1].maxResourceVariance = 5; + this->aics[param_1].recruitGoldThreshold = 200; this->aics[param_1].populationPerWoodcutter = 2; From f9805921428f0f7e13b2f4a4aa7131c6993e7a50 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sun, 19 Jul 2026 18:12:29 +0200 Subject: [PATCH 026/242] reimplement OpenSHC::AI::AICState: first pass --- .../AI/AICState/abortAttackAndGoIdle.cpp | 23 ++++++++ .../addBuildingToTargetableBuildings.cpp | 24 +++++++++ .../AI/AICState/addEngineersToSelection.cpp | 45 ++++++++++++++++ .../AI/AICState/addEngineersToTribe.cpp | 35 +++++++++++++ src/OpenSHC/AI/AICState/aiFarmChoice.cpp | 22 ++++++++ src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp | 31 +++++++++++ .../AI/AICState/aiShouldBuildIronMine.cpp | 34 ++++++++++++ .../AI/AICState/aiShouldBuildPitchrig.cpp | 36 +++++++++++++ .../AI/AICState/aiShouldBuildQuarry.cpp | 34 ++++++++++++ .../AI/AICState/aiShouldBuildWoodcutter.cpp | 46 ++++++++++++++++ src/OpenSHC/AI/AICState/destroyHouse.cpp | 34 ++++++++++++ .../AI/AICState/getResourceRebuildDelay.cpp | 21 ++++++++ src/OpenSHC/AI/AICState/sellGoods.cpp | 1 - .../setCurrentAttackRaidParameter.cpp | 37 +++++++++++++ .../AI/AICState/setCurrentAttackStrength.cpp | 40 ++++++++++++++ .../AI/AICState/setNextFarmTypeToBuild.cpp | 29 +++++++++++ .../AICState/shouldNotBeBuildingArmoury.cpp | 18 +++++++ .../AICState/shouldNotBeBuildingGranary.cpp | 18 +++++++ .../AI/AICState/shouldNotBeBuildingHovel.cpp | 26 ++++++++++ .../AI/AICState/shouldNotBuildKillingPits.cpp | 19 +++++++ ...uldWaitWithBuildingAPositiveFearFactor.cpp | 52 +++++++++++++++++++ ...ouldWaitWithBuildingNegativeFearFactor.cpp | 38 ++++++++++++++ .../woodCuttersHutWhileNoWoodAvailable.cpp | 20 +++++++ 23 files changed, 682 insertions(+), 1 deletion(-) create mode 100644 src/OpenSHC/AI/AICState/abortAttackAndGoIdle.cpp create mode 100644 src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp create mode 100644 src/OpenSHC/AI/AICState/addEngineersToSelection.cpp create mode 100644 src/OpenSHC/AI/AICState/addEngineersToTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/aiFarmChoice.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp create mode 100644 src/OpenSHC/AI/AICState/destroyHouse.cpp create mode 100644 src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp create mode 100644 src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp create mode 100644 src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp create mode 100644 src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp create mode 100644 src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp diff --git a/src/OpenSHC/AI/AICState/abortAttackAndGoIdle.cpp b/src/OpenSHC/AI/AICState/abortAttackAndGoIdle.cpp new file mode 100644 index 000000000..bdd9f7312 --- /dev/null +++ b/src/OpenSHC/AI/AICState/abortAttackAndGoIdle.cpp @@ -0,0 +1,23 @@ +#include "../AICState.func.hpp" + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D45E0 + void AICState::abortAttackAndGoIdle(int playerID) + { + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + MACRO_CALL_MEMBER(AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + MACRO_CALL_MEMBER(AICState_Func::addEngineersToTribe, this)(playerID); + MACRO_CALL_MEMBER(AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp b/src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp new file mode 100644 index 000000000..8f92126ff --- /dev/null +++ b/src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp @@ -0,0 +1,24 @@ +#include "../AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDA50 + void AICState::addBuildingToTargetableBuildings(int buildingID) + { + int _player = DAT_BuildingsState::instance.buildings[buildingID].owner; + if (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY) { + int* piVar1 = &DAT_GameState::instance.playerDataArray[_player].top100TargetableBuildingsTracker; + if ((*piVar1 < 100) && (DAT_BuildingsState::instance.buildings[buildingID].fireDuration == 0)) { + DAT_GameState::instance.playerDataArray[_player].top100TargetableBuildings[*piVar1] = (short)buildingID; + *piVar1 = *piVar1 + 1; + } + } + } + +} +} diff --git a/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp b/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp new file mode 100644 index 000000000..db3392918 --- /dev/null +++ b/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp @@ -0,0 +1,45 @@ +#include "../AICState.func.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC680 + int AICState::addEngineersToSelection(int playerID, int unitCount) + { + int tribeID; + uint unitID; + + tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + /* Unit offset 150 */ + Map::Units::Unit* _ptrUnit = &DAT_UnitsState::instance.units[1]; + do { + if (unitCount <= 0) { + return tribeID; + } + if ((((_ptrUnit->logicalState == Map::Units::ULS_NORMAL) && (_ptrUnit->owner == playerID)) + && (_ptrUnit->dying == 0)) + && (((_ptrUnit->unitType == Map::Units::UT_E_ENGINEER) && (_ptrUnit->aiUnitBehaviourType == 10)) + && ((_ptrUnit->tribeID == 0) + && ((_ptrUnit->state).generic != Map::Units::States::US_STAND_UPUnk)))) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, tribeID); + unitCount = unitCount + -1; + } + unitID = unitID + 1; + _ptrUnit = _ptrUnit + 1; + } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + return tribeID; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp b/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp new file mode 100644 index 000000000..e9c39df1a --- /dev/null +++ b/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp @@ -0,0 +1,35 @@ +#include "../AICState.func.hpp" + +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4040 + void AICState::addEngineersToTribe(int playerID) + { + int unitID; + + unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + /* Unit offset 150 */ + Map::Units::Unit* psVar1 = &DAT_UnitsState::instance.units[1]; + do { + /* if logicalState == normal && owner == playerID && unitType == 0x1e (engineer) + && aiUnitBehaviourType == 10 */ + if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == playerID)) + && (psVar1->dying == 0)) + && (((psVar1->unitType == Map::Units::UT_E_ENGINEER) && (psVar1->aiUnitBehaviourType == 10)) + && (psVar1->tribeID == 0))) { + MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 10); + } + unitID = unitID + 1; + psVar1 = psVar1 + 1; + } while (unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiFarmChoice.cpp b/src/OpenSHC/AI/AICState/aiFarmChoice.cpp new file mode 100644 index 000000000..82412eba9 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiFarmChoice.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB180 + int AICState::aiFarmChoice(PlayerID playerID) + + { + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + + /* ugly because EAX is always 1 or higher */ + return (&this->DAT_AICArray[(aiType - 1)].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp new file mode 100644 index 000000000..cd1bede8d --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB220 + uint AICState::aiShouldBuildFarm(PlayerID playerID) + { + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + int _farmCount + = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countFarms, DAT_BuildingsState::ptr)(playerID, 1); + if (_farmCount < 1) { + return 1; + } + AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + if (_farmCount >= (int)spec->maxFarms) { + return 0; + } + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / _farmCount + >= (int)spec->populationPerFarm; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp new file mode 100644 index 000000000..a9a7fde60 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp @@ -0,0 +1,34 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB4D0 + uint AICState::aiShouldBuildIronMine(PlayerID playerID) + { + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + if ((int)spec->populationPerIronmine <= 0) { + return 0; + } + int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_IRONMINE, 1); + if (iVar3 < 1) { + iVar3 = 1; + } else if (iVar3 >= (int)spec->maxIronmines) { + return 0; + } + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / iVar3 + >= (int)spec->populationPerIronmine; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp new file mode 100644 index 000000000..2ef6bf1f7 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp @@ -0,0 +1,36 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB540 + uint AICState::aiShouldBuildPitchrig(PlayerID param_1) + { + int const aiType = DAT_GameState::instance.playerDataArray[param_1].aiType; + if (aiType == AITA_NULL) { + return 0; + } + AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + if ((int)spec->populationPerPitchrig <= 0) { + return 0; + } + int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(param_1, Map::Buildings::BT_PITCHRIG, 1); + if (iVar3 < 1) { + iVar3 = 1; + } else { + if (iVar3 >= (int)spec->maxPitchrigs) { + return 0; + } + } + return DAT_GameState::instance.playerDataArray[param_1].currentPopulation / iVar3 + >= (int)spec->populationPerPitchrig; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp new file mode 100644 index 000000000..c8f602ef5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp @@ -0,0 +1,34 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB330 + uint AICState::aiShouldBuildQuarry(PlayerID playerID) + { + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + if ((int)spec->populationPerQuarry <= 0) { + return 0; + } + int _quarryCount = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_QUARRY, 1); + if (_quarryCount < 1) { + _quarryCount = 1; + } else if (_quarryCount >= (int)spec->maxQuarries) { + return 0; + } + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / _quarryCount + >= (int)spec->populationPerQuarry; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp new file mode 100644 index 000000000..4e78da7d0 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp @@ -0,0 +1,46 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB290 + uint AICState::aiShouldBuildWoodcutter(PlayerID playerID) + { + if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 1) { + return 0; + } + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + if ((int)spec->populationPerWoodcutter <= 0) { + return 0; + } + int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT, 1); + if (iVar3 < 1) { + iVar3 = 1; + } else { + if (iVar3 >= (int)spec->maxWoodcutters) { + return 0; + } + if ((5 < iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 91)) { + return 0; + } + if ((2 < iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 31)) { + return 0; + } + } + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / iVar3 + >= (int)spec->populationPerWoodcutter; + } +} +} diff --git a/src/OpenSHC/AI/AICState/destroyHouse.cpp b/src/OpenSHC/AI/AICState/destroyHouse.cpp new file mode 100644 index 000000000..e04f4d87f --- /dev/null +++ b/src/OpenSHC/AI/AICState/destroyHouse.cpp @@ -0,0 +1,34 @@ +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB810 + BOOLEnum AICState::destroyHouse(int playerID) + { + int _hovelID; + if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (_hovelID = DAT_GameState::instance.playerDataArray[playerID].currentPopulation, + _hovelID <= DAT_GameState::instance.playerDataArray[playerID].populationCap)) + && (8 < _hovelID)) + && (0x14 < DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk)) { + _hovelID = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_HOVEL); + if (_hovelID == 0) { + return FALSE; + } + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(_hovelID, playerID, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hovelID); + return TRUE; + } + return FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp b/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp new file mode 100644 index 000000000..9d8493888 --- /dev/null +++ b/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB150 + int AICState::getResourceRebuildDelay(int playerID) + + { + int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return 0; + } + + return this->DAT_AICArray[(aiType - 1)].resourceRebuildDelay; + } +} +} diff --git a/src/OpenSHC/AI/AICState/sellGoods.cpp b/src/OpenSHC/AI/AICState/sellGoods.cpp index 5ebd21d63..c830f93ea 100644 --- a/src/OpenSHC/AI/AICState/sellGoods.cpp +++ b/src/OpenSHC/AI/AICState/sellGoods.cpp @@ -23,6 +23,5 @@ namespace AI { MACRO_CALL_MEMBER(Game::GameStateStructures_Func::displayPlayerTradeVisualEffect, DAT_GameState::ptr)( playerID, 1, -amount, resourceType); } - } } diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp new file mode 100644 index 000000000..92afcf357 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp @@ -0,0 +1,37 @@ +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDF10 + void AICState::setCurrentAttackRaidParameter(int playerID) + { + int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType != AITA_NULL) { + int _rng = (int)SEC_RNG::instance.currentNumber2; + MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + AICSpecification const* spec = &this->DAT_AICArray[_aiType - 1]; + int _gold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; + int _raidUnitsRandom = (int)spec->RaidUnitsRandom; + if (_gold < 1000) { + _raidUnitsRandom = 0; + } else if (4999 < _gold) { + _raidUnitsRandom = _raidUnitsRandom * 2; + } + if (DAT_GameState::instance + .playerDataArray[DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk] + .currentResources[0xf] + < 500) { + _raidUnitsRandom = -((int)spec->RaidUnitsBase / 2); + } + DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + = (_raidUnitsRandom * (_rng % 100)) / 100; + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp new file mode 100644 index 000000000..53cc9576f --- /dev/null +++ b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDE60 + void AICState::setCurrentAttackStrength(int playerID) + { + int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType != AITA_NULL) { + int _randomNumber = (int)SEC_RNG::instance.currentNumber2; + MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + int _attForceRandom = (int)this->DAT_AICArray[_aiType - 1].AttForceRandom; + int* _attackWave = &DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; + *_attackWave = *_attackWave + 1; + int _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength + = (_attForceRandom * (_randomNumber % 100)) / 100; + int _currentAttackWave = DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; + if (_currentGold < 10001) { + int* _ptrAttackStrength + = &DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; + *_ptrAttackStrength = *_ptrAttackStrength + _currentAttackWave * 5; + } else { + int* _ptrAttackStrength + = &DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; + *_ptrAttackStrength = *_ptrAttackStrength + _currentAttackWave * 7; + } + if (200 < DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength) { + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 200; + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp new file mode 100644 index 000000000..5e81a2a99 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB1B0 + int AICState::setNextFarmTypeToBuild(PlayerID playerID) + + { + int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == AITA_NULL) { + return 0; + } + int* _ptrAiFarmIndex = &DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex; + *_ptrAiFarmIndex = *_ptrAiFarmIndex + 1; + if (7 < DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex) { + DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; + } + if ((&this->DAT_AICArray[_aiType - 1].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] + == 0) { + DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; + } + return (&this->DAT_AICArray[_aiType - 1].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp new file mode 100644 index 000000000..cff5e2904 --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp @@ -0,0 +1,18 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004ECA60 + BOOLEnum AICState::shouldNotBeBuildingArmoury(PlayerID playerID, Commands::CommandBuildingType commandBuildingType) + { + if (commandBuildingType != Commands::CBT_ARMORY) { + return FALSE; + } + return DAT_GameState::instance.playerDataArray[playerID].isArmouryAlmostFilledUp == 0; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp new file mode 100644 index 000000000..93ea91df5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp @@ -0,0 +1,18 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004ECA30 + BOOLEnum AICState::shouldNotBeBuildingGranary(int playerID, Commands::CommandBuildingType commandBuildingType) + { + if (commandBuildingType != Commands::CBT_GRANARY) { + return FALSE; + } + return DAT_GameState::instance.playerDataArray[playerID].granaryIsAlmostFilledUp == FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp new file mode 100644 index 000000000..43483ef0a --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB5B0 + BOOLEnum AICState::shouldNotBeBuildingHovel(PlayerID playerID, Commands::CommandBuildingType param_2) + { + if (param_2 == Commands::CBT_HOVEL) { + int const populationCap = DAT_GameState::instance.playerDataArray[playerID].populationCap; + if (12 < populationCap) { + if (((populationCap <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation) + && (DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants < 5)) + && (DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk < 5)) { + return DAT_GameState::instance.playerDataArray[playerID].popularity < 5000; + } + return TRUE; + } + } + return FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp new file mode 100644 index 000000000..47697719a --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004ECA90 + BOOLEnum AICState::shouldNotBuildKillingPits(int playerID, Commands::CommandBuildingType commandBuildingType) + { + BOOLEnum _totalAbove99 = FALSE; + if (commandBuildingType == Commands::CBT_KILLINGPIT) { + _totalAbove99 = (BOOLEnum)(DAT_AIVState::instance.mapExtraInfo.playerTotalKillingPits[playerID] >= 100); + } + return _totalAbove99; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp new file mode 100644 index 000000000..676b02f35 --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp @@ -0,0 +1,52 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB700 + BOOLEnum AICState::shouldWaitWithBuildingAPositiveFearFactor(int playerID, Commands::CommandBuildingType param_2) + { + int* piVar1; + switch (param_2) { + case Commands::CBT_COMMUNAL_GARDEN1: + case Commands::CBT_COMMUNAL_GARDEN2: + case Commands::CBT_COMMUNAL_GARDEN3: + case Commands::CBT_COMMUNAL_GARDEN4: + case Commands::CBT_COMMUNAL_GARDEN5: + case Commands::CBT_SHRUB_GARDEN6: + case Commands::CBT_COMMUNAL_GARDEN7: + case Commands::CBT_COMMUNAL_GARDEN8: + case Commands::CBT_COMMUNAL_GARDEN9: + case Commands::CBT_TOWN_GARDEN10: + case Commands::CBT_TOWN_GARDEN11: + case Commands::CBT_TOWN_GARDEN12: + case Commands::CBT_MAYPOLE: + case Commands::CBT_STATUE1: + case Commands::CBT_STATUE2: + case Commands::CBT_STATUE3: + case Commands::CBT_STATUE4: + case Commands::CBT_STATUE5: + case Commands::CBT_SHRINE1: + case Commands::CBT_SHRINE2: + case Commands::CBT_SHRINE3: + case Commands::CBT_SHRINE4: + case Commands::CBT_SHRINE5: + case Commands::CBT_DANCINGBEAR: + case Commands::CBT_POND_1: + case Commands::CBT_SMALL_POND_3: + case Commands::CBT_LARGE_POND_3: + case Commands::CBT_LARGE_POND_4: + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay; + *piVar1 = *piVar1 + 1; + if (DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay < 200) { + return TRUE; + } + DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay = 0; + } + return FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp new file mode 100644 index 000000000..36ab16d6f --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp @@ -0,0 +1,38 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB610 + BOOLEnum AICState::shouldWaitWithBuildingNegativeFearFactor(int param_1, Commands::CommandBuildingType param_2) + { + int* piVar1; + switch (param_2) { + case Commands::CBT_GALLOWS: + case Commands::CBT_STOCKS: + case Commands::CBT_CESSPIT1: + case Commands::CBT_CESSPIT2: + case Commands::CBT_CESSPIT3: + case Commands::CBT_CESSPIT4: + case Commands::CBT_BURNINGSTAKE: + case Commands::CBT_GIBBET: + case Commands::CBT_DUNGEON: + case Commands::CBT_STRETCHINGRACK: + case Commands::CBT_RACKFLOGGING: + case Commands::CBT_CHOPPINGBLOCK: + case Commands::CBT_DUNKINGSTOOL: + if ((DAT_GameState::instance.playerDataArray[param_1].popularity < 5000) + || (piVar1 = &DAT_GameState::instance.playerDataArray[param_1].aivNegativeFearFactorDelay, + *piVar1 = *piVar1 + 1, + DAT_GameState::instance.playerDataArray[param_1].aivNegativeFearFactorDelay < 100)) { + return TRUE; + } + DAT_GameState::instance.playerDataArray[param_1].aivNegativeFearFactorDelay = 0; + } + return FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp b/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp new file mode 100644 index 000000000..851e01542 --- /dev/null +++ b/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp @@ -0,0 +1,20 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004ECAB0 + BOOLEnum AICState::woodCuttersHutWhileNoWoodAvailable( + undefined4 playerID, Commands::CommandBuildingType commandBuildingType) + { + if ((commandBuildingType == Commands::CBT_WOODCUTTERSHUT) + && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0)) { + return TRUE; + } + return FALSE; + } +} +} From dffaee58ffe0a69883a9daa4684a44baf94bf917 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sun, 19 Jul 2026 22:16:23 +0200 Subject: [PATCH 027/242] pass 2 --- src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp | 25 ++++++++------- .../AI/AICState/aiShouldBuildWoodcutter.cpp | 19 ++++++------ src/OpenSHC/AI/AICState/buyGoods.cpp | 1 - .../getCurrentDesiredAttackRaidUnitCount.cpp | 22 +++++++++++++ .../AI/AICState/hasNotEnoughSupplies.cpp | 27 ++++++++++++++++ .../AICState/setAttackCoordinationLevel.cpp | 31 +++++++++++++++++++ .../AI/AICState/setAttackPrimeInfo.cpp | 22 +++++++++++++ .../AI/AICState/setNextFarmTypeToBuild.cpp | 10 +++--- .../setSomeTimeToNowIfInIngameMenu.cpp | 19 ++++++++++++ .../AICState/setTriggerForAITauntResponse.cpp | 19 ++++++++++++ src/OpenSHC/AI/AICState/yieldCowThrow.cpp | 26 ++++++++++++++++ 11 files changed, 194 insertions(+), 27 deletions(-) create mode 100644 src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp create mode 100644 src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp create mode 100644 src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp create mode 100644 src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp create mode 100644 src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp create mode 100644 src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp create mode 100644 src/OpenSHC/AI/AICState/yieldCowThrow.cpp diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp index cd1bede8d..25aca2c0d 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp @@ -9,23 +9,24 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB220 - uint AICState::aiShouldBuildFarm(PlayerID playerID) + BOOLEnum AICState::aiShouldBuildFarm(PlayerID playerID) { - int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + int const _playerID = playerID; + unsigned int aiType = DAT_GameState::instance.playerDataArray[_playerID].aiType; if (aiType == AITA_NULL) { - return 0; + return aiType; // return 0 => return } - int _farmCount - = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countFarms, DAT_BuildingsState::ptr)(playerID, 1); - if (_farmCount < 1) { - return 1; + aiType -= 1; + int const _farmCount + = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countFarms, DAT_BuildingsState::ptr)(_playerID, 1); + if (_farmCount <= 0) { + return TRUE; } - AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; - if (_farmCount >= (int)spec->maxFarms) { - return 0; + if (_farmCount >= (int)this->DAT_AICArray[aiType].maxFarms) { + return FALSE; } - return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / _farmCount - >= (int)spec->populationPerFarm; + return DAT_GameState::instance.playerDataArray[_playerID].currentPopulation / _farmCount + >= (int)this->DAT_AICArray[aiType].populationPerFarm; } } } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp index 4e78da7d0..ce4ba794a 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp @@ -13,34 +13,35 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB290 uint AICState::aiShouldBuildWoodcutter(PlayerID playerID) { - if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 1) { + if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0) { return 0; } - int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (aiType == AITA_NULL) { return 0; } - AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; - if ((int)spec->populationPerWoodcutter <= 0) { + aiType -= 1; + // AICSpecification const* spec = &this->DAT_AICArray[aiType]; + if ((int)this->DAT_AICArray[aiType].populationPerWoodcutter <= 0) { return 0; } int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT, 1); - if (iVar3 < 1) { + if (iVar3 <= 0) { iVar3 = 1; } else { - if (iVar3 >= (int)spec->maxWoodcutters) { + if (iVar3 >= (int)this->DAT_AICArray[aiType].maxWoodcutters) { return 0; } - if ((5 < iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 91)) { + if ((6 <= iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 90)) { return 0; } - if ((2 < iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 31)) { + if ((3 <= iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 30)) { return 0; } } return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / iVar3 - >= (int)spec->populationPerWoodcutter; + >= (int)this->DAT_AICArray[aiType].populationPerWoodcutter; } } } diff --git a/src/OpenSHC/AI/AICState/buyGoods.cpp b/src/OpenSHC/AI/AICState/buyGoods.cpp index 7075afd56..e79ac2405 100644 --- a/src/OpenSHC/AI/AICState/buyGoods.cpp +++ b/src/OpenSHC/AI/AICState/buyGoods.cpp @@ -24,6 +24,5 @@ namespace AI { } return FALSE; } - } } diff --git a/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp b/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp new file mode 100644 index 000000000..8be83b087 --- /dev/null +++ b/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Game/TrailType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D12A0 + int AICState::getCurrentDesiredAttackRaidUnitCount(int aiType, int playerID) + { + if (((DAT_GameCore::instance.gameMode_2 == Game::GM_SKIRMISH_AND_MULTIPLAYER) && + (DAT_GameCore::instance.isSkirmishTrail == TRUE)) && (DAT_GameCore::instance.currentTrailType == Game::TT_EXTREME)) { + return (int)((DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + this->DAT_AICArray[aiType].RaidUnitsBase) * 4) / 3; + } + return DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + this->DAT_AICArray[aiType].RaidUnitsBase; + } +} +} diff --git a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp new file mode 100644 index 000000000..0f772a912 --- /dev/null +++ b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp @@ -0,0 +1,27 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D00A0 + BOOLEnum AICState::hasNotEnoughSupplies(int playerID) + { + BOOLEnum BVar1 = TRUE; + if (((((DAT_GameState::instance.playerDataArray[playerID].marketplace.id != 0) || + (DAT_BuildingsState::instance.buildingCosts[0x1a].requiredWood <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) || + (0 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)) && + (((DAT_GameState::instance.playerDataArray[playerID].granary.id != 0 || + (DAT_BuildingsState::instance.buildingCosts[0x13].requiredWood <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) || + (1 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)))) && + (((0 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] || + (25 < DAT_GameState::instance.playerDataArray[playerID].popularity)) || + (0 < DAT_GameState::instance.playerDataArray[playerID].totalFood)))) { + BVar1 = FALSE; + } + return BVar1; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp new file mode 100644 index 000000000..4895c8e2b --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Random/RNG.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0110 + void AICState::setAttackCoordinationLevel(int playerID) + { + int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType != AITA_NULL) { + int _willingnessPercentage = (int)this->DAT_AICArray[_aiType - 1].AttCoordinationPreference + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; + if (90 < _willingnessPercentage) { + _willingnessPercentage = 90; + } + int _rng = (int)SEC_RNG::instance.currentNumber2; + MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + if (_rng % 100 < _willingnessPercentage / 2) { + DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = 2; + return; + } + DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = (uint)(_rng % 100 < _willingnessPercentage); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp new file mode 100644 index 000000000..172e3b81c --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDFD0 + void AICState::setAttackPrimeInfo(int playerID, int attackedPlayerID) + { + int _tile = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile; + DAT_TroopValueState::instance.attackInfo.startCon = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; + DAT_TroopValueState::instance.attackInfo.startZone = (int)(char)DAT_TileMapState::instance.AIZoneLayer[_tile]; + DAT_TroopValueState::instance.attackInfo.zoneSize = DAT_PathFindingState::instance.zoneSizesArray[(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]]; + DAT_TroopValueState::instance.attackInfo.unknownOne_0x20f90 = 1; + DAT_TroopValueState::instance.attackInfo.keepCon = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry]; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp index 5e81a2a99..5e876dac7 100644 --- a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp +++ b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp @@ -10,20 +10,20 @@ namespace AI { int AICState::setNextFarmTypeToBuild(PlayerID playerID) { - int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + unsigned int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (_aiType == AITA_NULL) { return 0; } + _aiType += -1; int* _ptrAiFarmIndex = &DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex; *_ptrAiFarmIndex = *_ptrAiFarmIndex + 1; - if (7 < DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex) { + if (8 <= DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex) { DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; } - if ((&this->DAT_AICArray[_aiType - 1].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] - == 0) { + if ((&this->DAT_AICArray[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] == 0) { DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; } - return (&this->DAT_AICArray[_aiType - 1].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + return (&this->DAT_AICArray[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; } } } diff --git a/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp b/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp new file mode 100644 index 000000000..01f0675d3 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Game/GameCore.func.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1090 + void AICState::setSomeTimeToNowIfInIngameMenu() + { + BOOLEnum BVar1 = MACRO_CALL_MEMBER(Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)(); + if (BVar1 != FALSE) { + this->DAT_SomeTime = timeGetTime(); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp b/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp new file mode 100644 index 000000000..3d849bf26 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Game/GameCore.func.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1090 + void AICState::setTriggerForAITauntResponse() + { + BOOLEnum BVar1 = MACRO_CALL_MEMBER(Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)(); + if (BVar1 != FALSE) { + this->aiTauntResponseTimeWindow = timeGetTime(); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/yieldCowThrow.cpp b/src/OpenSHC/AI/AICState/yieldCowThrow.cpp new file mode 100644 index 000000000..42c6a14d2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/yieldCowThrow.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFF60 + BOOLEnum AICState::yieldCowThrow(int playerID) + { + int* _pCounter; + int const _ai = DAT_GameState::instance.playerDataArray[playerID].aiType; + if ((((_ai != AITA_NULL) && (DAT_GameState::instance.mapAndTime.noCowThrowing == 0)) && + (this->DAT_AICArray[_ai - 1].CowThrowInterval != 0)) && + ((0 < DAT_GameState::instance.playerDataArray[playerID].counter && + (_pCounter = &DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter, + *_pCounter = *_pCounter + 1, + (int)this->DAT_AICArray[_ai - 1].CowThrowInterval < DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter)))) { + DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter = 0; + return TRUE; + } + return FALSE; + } +} +} From 9c02a5f280ff30aef04e48c30c00d5b316dcc26f Mon Sep 17 00:00:00 2001 From: sourcehold Date: Mon, 20 Jul 2026 01:14:16 +0200 Subject: [PATCH 028/242] processed ghidra changes --- src/OpenSHC/AI/AICState/aiFarmChoice.cpp | 2 +- src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp | 6 ++--- .../AI/AICState/aiShouldBuildIronMine.cpp | 2 +- .../AI/AICState/aiShouldBuildPitchrig.cpp | 2 +- .../AI/AICState/aiShouldBuildQuarry.cpp | 2 +- .../AI/AICState/aiShouldBuildWoodcutter.cpp | 22 +++++++++---------- .../getCurrentDesiredAttackRaidUnitCount.cpp | 16 +++++++++----- .../AI/AICState/getResourceRebuildDelay.cpp | 2 +- .../AICState/setAttackCoordinationLevel.cpp | 9 ++++---- .../setCurrentAttackRaidParameter.cpp | 2 +- .../AI/AICState/setCurrentAttackStrength.cpp | 2 +- .../AI/AICState/setNextFarmTypeToBuild.cpp | 4 ++-- .../setSomeTimeToNowIfInIngameMenu.cpp | 19 ---------------- .../AICState/setTriggerForAITauntResponse.cpp | 3 +-- src/OpenSHC/AI/AICState/yieldCowThrow.cpp | 13 ++++++----- 15 files changed, 46 insertions(+), 60 deletions(-) delete mode 100644 src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp diff --git a/src/OpenSHC/AI/AICState/aiFarmChoice.cpp b/src/OpenSHC/AI/AICState/aiFarmChoice.cpp index 82412eba9..ca1d6515f 100644 --- a/src/OpenSHC/AI/AICState/aiFarmChoice.cpp +++ b/src/OpenSHC/AI/AICState/aiFarmChoice.cpp @@ -16,7 +16,7 @@ namespace AI { } /* ugly because EAX is always 1 or higher */ - return (&this->DAT_AICArray[(aiType - 1)].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + return (&this->aics[(aiType - 1)].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; } } } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp index 25aca2c0d..29132eb9c 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp @@ -9,7 +9,7 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB220 - BOOLEnum AICState::aiShouldBuildFarm(PlayerID playerID) + BOOLEnum AICState::aiShouldBuildFarm(int playerID) { int const _playerID = playerID; unsigned int aiType = DAT_GameState::instance.playerDataArray[_playerID].aiType; @@ -22,11 +22,11 @@ namespace AI { if (_farmCount <= 0) { return TRUE; } - if (_farmCount >= (int)this->DAT_AICArray[aiType].maxFarms) { + if (_farmCount >= (int)this->aics[aiType].maxFarms) { return FALSE; } return DAT_GameState::instance.playerDataArray[_playerID].currentPopulation / _farmCount - >= (int)this->DAT_AICArray[aiType].populationPerFarm; + >= (int)this->aics[aiType].populationPerFarm; } } } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp index a9a7fde60..7ddf0e041 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp @@ -16,7 +16,7 @@ namespace AI { if (aiType == AITA_NULL) { return 0; } - AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + AICSpecification const* spec = &this->aics[aiType - 1]; if ((int)spec->populationPerIronmine <= 0) { return 0; } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp index 2ef6bf1f7..0227c21c7 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp @@ -16,7 +16,7 @@ namespace AI { if (aiType == AITA_NULL) { return 0; } - AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + AICSpecification const* spec = &this->aics[aiType - 1]; if ((int)spec->populationPerPitchrig <= 0) { return 0; } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp index c8f602ef5..ac4afab74 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp @@ -16,7 +16,7 @@ namespace AI { if (aiType == AITA_NULL) { return 0; } - AICSpecification const* spec = &this->DAT_AICArray[aiType - 1]; + AICSpecification const* spec = &this->aics[aiType - 1]; if ((int)spec->populationPerQuarry <= 0) { return 0; } diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp index ce4ba794a..221047ca9 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp @@ -11,37 +11,37 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB290 - uint AICState::aiShouldBuildWoodcutter(PlayerID playerID) + BOOLEnum AICState::aiShouldBuildWoodcutter(int playerID) { if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0) { - return 0; + return FALSE; } int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (aiType == AITA_NULL) { - return 0; + return FALSE; } aiType -= 1; - // AICSpecification const* spec = &this->DAT_AICArray[aiType]; - if ((int)this->DAT_AICArray[aiType].populationPerWoodcutter <= 0) { - return 0; + // AICSpecification const* spec = &this->aics[aiType]; + if ((int)this->aics[aiType].populationPerWoodcutter <= 0) { + return FALSE; } int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT, 1); if (iVar3 <= 0) { iVar3 = 1; } else { - if (iVar3 >= (int)this->DAT_AICArray[aiType].maxWoodcutters) { - return 0; + if (iVar3 >= (int)this->aics[aiType].maxWoodcutters) { + return FALSE; } if ((6 <= iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 90)) { - return 0; + return FALSE; } if ((3 <= iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 30)) { - return 0; + return FALSE; } } return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / iVar3 - >= (int)this->DAT_AICArray[aiType].populationPerWoodcutter; + >= (int)this->aics[aiType].populationPerWoodcutter; } } } diff --git a/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp b/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp index 8be83b087..b36972206 100644 --- a/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp +++ b/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp @@ -1,10 +1,9 @@ #include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Game/GameMode2.hpp" #include "OpenSHC/Game/TrailType.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { @@ -12,11 +11,16 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D12A0 int AICState::getCurrentDesiredAttackRaidUnitCount(int aiType, int playerID) { - if (((DAT_GameCore::instance.gameMode_2 == Game::GM_SKIRMISH_AND_MULTIPLAYER) && - (DAT_GameCore::instance.isSkirmishTrail == TRUE)) && (DAT_GameCore::instance.currentTrailType == Game::TT_EXTREME)) { - return (int)((DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + this->DAT_AICArray[aiType].RaidUnitsBase) * 4) / 3; + if (((DAT_GameCore::instance.gameMode_2 == Game::GM_SKIRMISH_AND_MULTIPLAYER) + && (DAT_GameCore::instance.isSkirmishTrail == TRUE)) + && (DAT_GameCore::instance.currentTrailType == Game::TT_EXTREME)) { + return (int)((DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + + this->aics[aiType].RaidUnitsBase) + * 4) + / 3; } - return DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + this->DAT_AICArray[aiType].RaidUnitsBase; + return DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + + this->aics[aiType].RaidUnitsBase; } } } diff --git a/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp b/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp index 9d8493888..d20a9e2f9 100644 --- a/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp +++ b/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp @@ -15,7 +15,7 @@ namespace AI { return 0; } - return this->DAT_AICArray[(aiType - 1)].resourceRebuildDelay; + return this->aics[(aiType - 1)].resourceRebuildDelay; } } } diff --git a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp index 4895c8e2b..2a27d6607 100644 --- a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp +++ b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp @@ -1,8 +1,7 @@ +#include "OpenSHC/Random/RNG.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" -#include "OpenSHC/Random/RNG.func.hpp" - #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/SEC_RNG.hpp" @@ -14,7 +13,8 @@ namespace AI { { int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (_aiType != AITA_NULL) { - int _willingnessPercentage = (int)this->DAT_AICArray[_aiType - 1].AttCoordinationPreference + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; + int _willingnessPercentage = (int)this->aics[_aiType - 1].AttCoordinationPreference + + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; if (90 < _willingnessPercentage) { _willingnessPercentage = 90; } @@ -24,7 +24,8 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = 2; return; } - DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = (uint)(_rng % 100 < _willingnessPercentage); + DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel + = (uint)(_rng % 100 < _willingnessPercentage); } } } diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp index 92afcf357..21e9aeba4 100644 --- a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp +++ b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp @@ -15,7 +15,7 @@ namespace AI { if (_aiType != AITA_NULL) { int _rng = (int)SEC_RNG::instance.currentNumber2; MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - AICSpecification const* spec = &this->DAT_AICArray[_aiType - 1]; + AICSpecification const* spec = &this->aics[_aiType - 1]; int _gold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; int _raidUnitsRandom = (int)spec->RaidUnitsRandom; if (_gold < 1000) { diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp index 53cc9576f..a762c3c96 100644 --- a/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp +++ b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp @@ -15,7 +15,7 @@ namespace AI { if (_aiType != AITA_NULL) { int _randomNumber = (int)SEC_RNG::instance.currentNumber2; MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - int _attForceRandom = (int)this->DAT_AICArray[_aiType - 1].AttForceRandom; + int _attForceRandom = (int)this->aics[_aiType - 1].AttForceRandom; int* _attackWave = &DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; *_attackWave = *_attackWave + 1; int _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; diff --git a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp index 5e876dac7..8f0706f81 100644 --- a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp +++ b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp @@ -20,10 +20,10 @@ namespace AI { if (8 <= DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex) { DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; } - if ((&this->DAT_AICArray[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] == 0) { + if ((&this->aics[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] == 0) { DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; } - return (&this->DAT_AICArray[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + return (&this->aics[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; } } } diff --git a/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp b/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp deleted file mode 100644 index 01f0675d3..000000000 --- a/src/OpenSHC/AI/AICState/setSomeTimeToNowIfInIngameMenu.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "OpenSHC/AI/AICState.hpp" - -#include "OpenSHC/Game/GameCore.func.hpp" - -#include "OpenSHC/Globals/DAT_GameCore.hpp" - -namespace OpenSHC { -namespace AI { - - // FUNCTION: STRONGHOLDCRUSADER 0x004D1090 - void AICState::setSomeTimeToNowIfInIngameMenu() - { - BOOLEnum BVar1 = MACRO_CALL_MEMBER(Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)(); - if (BVar1 != FALSE) { - this->DAT_SomeTime = timeGetTime(); - } - } -} -} diff --git a/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp b/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp index 3d849bf26..1b9dcf37b 100644 --- a/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp +++ b/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp @@ -1,6 +1,5 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Game/GameCore.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameCore.hpp" diff --git a/src/OpenSHC/AI/AICState/yieldCowThrow.cpp b/src/OpenSHC/AI/AICState/yieldCowThrow.cpp index 42c6a14d2..16c993e2f 100644 --- a/src/OpenSHC/AI/AICState/yieldCowThrow.cpp +++ b/src/OpenSHC/AI/AICState/yieldCowThrow.cpp @@ -11,12 +11,13 @@ namespace AI { { int* _pCounter; int const _ai = DAT_GameState::instance.playerDataArray[playerID].aiType; - if ((((_ai != AITA_NULL) && (DAT_GameState::instance.mapAndTime.noCowThrowing == 0)) && - (this->DAT_AICArray[_ai - 1].CowThrowInterval != 0)) && - ((0 < DAT_GameState::instance.playerDataArray[playerID].counter && - (_pCounter = &DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter, - *_pCounter = *_pCounter + 1, - (int)this->DAT_AICArray[_ai - 1].CowThrowInterval < DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter)))) { + if ((((_ai != AITA_NULL) && (DAT_GameState::instance.mapAndTime.noCowThrowing == 0)) + && (this->aics[_ai - 1].CowThrowInterval != 0)) + && ((0 < DAT_GameState::instance.playerDataArray[playerID].counter + && (_pCounter = &DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter, + *_pCounter = *_pCounter + 1, + (int)this->aics[_ai - 1].CowThrowInterval + < DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter)))) { DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter = 0; return TRUE; } From 296d6882bad45f171e4d00a7bbd7704e00fcd7cb Mon Sep 17 00:00:00 2001 From: sourcehold Date: Mon, 20 Jul 2026 01:40:55 +0200 Subject: [PATCH 029/242] more rough unchecked reimplementations --- .../aiCommandTribe11StandGroundToGate.cpp | 31 ++++++++++ .../aiCommandTribe13DefensiveWave.cpp | 28 +++++++++ .../AICState/aiCommandWallAssaultTribes.cpp | 37 ++++++++++++ .../AICState/hasNoTroopsOrAllAreDiggers.cpp | 57 +++++++++++++++++++ .../AICState/ifHasTribe0SendUnitsToKeep.cpp | 19 +++++++ .../AI/AICState/makeOutpostTribesAttack.cpp | 29 ++++++++++ .../sendAITribe_0xf_toAttackPatrol.cpp | 30 ++++++++++ .../AICState/sendTribeAtOffset1ToCampfire.cpp | 19 +++++++ src/OpenSHC/AI/AICState/sendTribeToAttack.cpp | 28 +++++++++ .../AI/AICState/sendUnitsToCampfire.cpp | 21 +++++++ src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp | 21 +++++++ ...htTribe0xc0TribesToAggressiveAndAttack.cpp | 37 ++++++++++++ ...x11ToAggressiveAndAttackIfConditionMet.cpp | 30 ++++++++++ .../setTribe0xCtoAggressiveAndAttack.cpp | 28 +++++++++ .../setTribe0xbToAggressiveAndAttack.cpp | 28 +++++++++ .../AICState/shouldDestroyWoodCutterUnk.cpp | 46 +++++++++++++++ ...rketArmoryGranaryBarracksMercenarypost.cpp | 24 ++++++++ 17 files changed, 513 insertions(+) create mode 100644 src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp create mode 100644 src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp create mode 100644 src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp create mode 100644 src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp create mode 100644 src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp create mode 100644 src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp create mode 100644 src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp create mode 100644 src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp create mode 100644 src/OpenSHC/AI/AICState/sendTribeToAttack.cpp create mode 100644 src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp create mode 100644 src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp create mode 100644 src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp create mode 100644 src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp create mode 100644 src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp create mode 100644 src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp create mode 100644 src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp new file mode 100644 index 000000000..6057d9080 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF470 + void AICState::aiCommandTribe11StandGroundToGate(int playerID) + { + int iVar1; + int iVar2; + if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], iVar2 != 0)) && + (DAT_TribesState::instance.tribes[iVar2].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb])) && + (DAT_TribesState::instance.tribes[iVar2].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[iVar2].unitStance = Map::Units::Behavior::USE_STAND_GROUND; + iVar1 = MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)(iVar2); + if (iVar1 == 0) { + MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)(iVar2); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp new file mode 100644 index 000000000..5f9524b07 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF270 + void AICState::aiCommandTribe13DefensiveWave(int param_1) + { + int tribeID; + if ((DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) && + (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xd], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xd]) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f4); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp new file mode 100644 index 000000000..55c81532f --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp @@ -0,0 +1,37 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF660 + void AICState::aiCommandWallAssaultTribes(int param_1) + { + int tribeID; + int iVar1; + short* psVar2; + if (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) { + iVar1 = 0; + psVar2 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + 0xbe; + do { + tribeID = (int)*psVar2; + if (((tribeID != 0) && + (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar1 + 0xbe])) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + } + iVar1 = iVar1 + 1; + psVar2 = psVar2 + 1; + } while (iVar1 < 2); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp new file mode 100644 index 000000000..b4f0895ac --- /dev/null +++ b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp @@ -0,0 +1,57 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFFD0 + BOOLEnum AICState::hasNoTroopsOrAllAreDiggers(int playerID) + { + int _totalBackup; + int _totalBackup2; + int _total1; + int _totalTroops; + int _halfOfDiggingTroops; + int _totalBackupLate; + int _totalBackupLate2; + + _total1 = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + + DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops; + _halfOfDiggingTroops = 0; + if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState == 6) { + if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 17) { + _totalBackup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + } + else { + _totalBackupLate = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + _totalBackup = (int)(_totalBackupLate + (_totalBackupLate >> 0x1f & 7U)) >> 3; + } + _totalTroops = _total1 + DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops + + _totalBackup + + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + } + else { + _halfOfDiggingTroops = DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops / 2; + if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 13) { + _totalBackup2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + } + else { + _totalBackupLate2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + _totalBackup2 = (int)(_totalBackupLate2 + (_totalBackupLate2 >> 0x1f & 7U)) >> 3; + } + _totalTroops = _total1 + _totalBackup2 + + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + } + if ((1 < _totalTroops) && ((4 < _totalTroops || (_halfOfDiggingTroops <= _totalTroops * 2)))) { + return FALSE; + } + return TRUE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp new file mode 100644 index 000000000..fb68e2842 --- /dev/null +++ b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2830 + void AICState::ifHasTribe0SendUnitsToKeep(int playerID) + { + int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0]; + if ((0 < tribeID) && + (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0])) { + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp new file mode 100644 index 000000000..8168e916d --- /dev/null +++ b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3960 + void AICState::makeOutpostTribesAttack() + { + uint _tribeID; + int _countDown; + short* _tribeIDs; + int* _tribeUIDs; + _tribeUIDs = this->tribeUIDArray; + _tribeIDs = this->tribeIDArray; + _countDown = 1000; + do { + _tribeID = (uint)*_tribeIDs; + if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid == *_tribeUIDs)) { + MACRO_CALL_MEMBER(AICState_Func::decideOnTribeAttackLocation, this)(_tribeID); + } + _tribeIDs = _tribeIDs + 1; + _tribeUIDs = _tribeUIDs + 1; + _countDown = _countDown + -1; + } while (_countDown != 0); + } +} +} diff --git a/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp b/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp new file mode 100644 index 000000000..e39cd8bcd --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp @@ -0,0 +1,30 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF4F0 + void AICState::sendAITribe_0xf_toAttackPatrol(int playerID) + { + int _tribeID; + /* bug: only sends 0xf, while 0xf+1 could also be send if defined by 'AIC: AttUnitPatrolGroupsCount' */ + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (_tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xf], _tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xf]) && + (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::sendAttackingPatrolTribeToComputedDestination, DAT_TroopValueState::ptr)(_tribeID); + return; + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp new file mode 100644 index 000000000..d54d90ecd --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp @@ -0,0 +1,19 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2870 + void AICState::sendTribeAtOffset1ToCampfire(int playerID) + { + int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[1]; + if ((0 < _tribeID) && + (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[1])) { + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp b/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp new file mode 100644 index 000000000..70816a822 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF750 + void AICState::sendTribeToAttack(int playerID) + { + int tribeID; + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbd], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbd]) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3fb); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp b/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp new file mode 100644 index 000000000..3438b8701 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD110 + void AICState::sendUnitsToCampfire(int tribeID, int playerID) + { + if (0 < DAT_GameState::instance.playerDataArray[playerID].campground.id) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, DAT_GameState::instance.playerDataArray[playerID].campground.xEntry, DAT_GameState::instance.playerDataArray[playerID].campground.yEntry, 0); + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp new file mode 100644 index 000000000..79a4d2d29 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD0C0 + void AICState::sendUnitsToKeep(undefined4 tribeID, int playerID) + { + int iVar1 = DAT_GameState::instance.playerDataArray[playerID].keep.id; + if (0 < iVar1) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, (int)(short)DAT_BuildingsState::instance.buildings[iVar1].x + 3, (int)(short)DAT_BuildingsState::instance.buildings[iVar1].y + 4, 0); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp new file mode 100644 index 000000000..16bce6ec3 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp @@ -0,0 +1,37 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF5E0 + void AICState::setEightTribe0xc0TribesToAggressiveAndAttack(int playerID) + { + int _tribeID; + int iVar1; + short* psVar2; + if (DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) { + iVar1 = 0; + psVar2 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xc0; + do { + _tribeID = (int)*psVar2; + if (((_tribeID != 0) && + (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar1 + 0xc0])) && + (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(_tribeID, Map::Units::STBT_0x3f2); + } + iVar1 = iVar1 + 1; + psVar2 = psVar2 + 1; + } while (iVar1 < 8); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp b/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp new file mode 100644 index 000000000..c92c7b451 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp @@ -0,0 +1,30 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF560 + void AICState::setTribe0x11ToAggressiveAndAttackIfConditionMet(int param_1) + { + int tribeID; + if (((0 < *(int*)((int)DAT_TroopValueState::instance.attackInfo.moatValuesArray + param_1 * 0x177bc + -4)) && + (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL)) && + (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0x11], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0x11]) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f7); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp new file mode 100644 index 000000000..45520c9d5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF400 + void AICState::setTribe0xCtoAggressiveAndAttack(int playerID) + { + int tribeID; + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xc], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xc]) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp new file mode 100644 index 000000000..259138f45 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF6E0 + void AICState::setTribe0xbToAggressiveAndAttack(int playerID) + { + int tribeID; + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb]) && + (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp new file mode 100644 index 000000000..68feb468c --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp @@ -0,0 +1,46 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/AI/AIVState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_AIVState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB890 + BOOLEnum AICState::shouldDestroyWoodCutterUnk(int playerID) + { + int _hut; + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return FALSE; + } + if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 1) { + _hut = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT); + } + else { + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] < 0x15) { + return FALSE; + } + if (DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 2) { + return FALSE; + } + if (DAT_GameState::instance.playerDataArray[playerID].someCount10 < 25) { + return FALSE; + } + _hut = DAT_GameState::instance.playerDataArray[playerID].someCount11; + } + if (_hut == 0) { + return FALSE; + } + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)((int)(short)DAT_BuildingsState::instance.buildings[_hut].x, (int)(short)DAT_BuildingsState::instance.buildings[_hut].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(_hut, playerID, 50); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hut); + return TRUE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp new file mode 100644 index 000000000..3a98835e1 --- /dev/null +++ b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Commands/CommandBuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB9F0 + BOOLEnum AICState::shouldNotBuildMarketArmoryGranaryBarracksMercenarypost(int playerID, Commands::CommandBuildingType param_2) + { + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) { + if ((0 < DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker) && (param_2 != Commands::CBT_MARKETPLACE)) { + return param_2 != Commands::CBT_GRANARY; + } + } + else if ((((param_2 != Commands::CBT_MARKETPLACE) && (param_2 != Commands::CBT_MERCENARYPOST)) && (param_2 != Commands::CBT_BARRACKS)) && (param_2 != Commands::CBT_ARMORY)) { + return param_2 != Commands::CBT_GRANARY; + } + return FALSE; + } +} +} From 183a4b7cd8ccbf2bcab8c7764d224e77a793e33f Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 20 Jul 2026 15:34:56 +0200 Subject: [PATCH 030/242] batch 4 unpolished --- .../AI/AICState/Constructor_AICState.cpp | 14 +++ src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp | 26 +++++ .../addUnitToSmallestBehaviourTypeTribe.cpp | 88 +++++++++++++++ .../AICState/addUnitToSmallestPatrolTribe.cpp | 25 +++++ .../AI/AICState/addUnitsToTribe166.cpp | 35 ++++++ .../AICState/aiAddUnitToMoatDiggerTribe.cpp | 30 ++++++ .../AI/AICState/aiAssignMoatDiggers.cpp | 48 +++++++++ .../AICState/aiAssignUnitToDefensiveTribe.cpp | 26 +++++ .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 80 ++++++++++++++ .../AICState/aiReassignTunnelersToTribe.cpp | 35 ++++++ .../AICState/aiRecruitEngineerForOilDuty.cpp | 61 +++++++++++ .../AI/AICState/aiRecruitEngineers.cpp | 32 ++++++ .../assignRequiredIdleEngineersToNewTribe.cpp | 45 ++++++++ .../AI/AICState/assignUnitToATribe.cpp | 49 +++++++++ .../canNavigateUnitsFromTileToTargetTile.cpp | 24 +++++ .../AI/AICState/createTribeForUnitType.cpp | 26 +++++ .../AICState/destroyAnyBuildingInCategory.cpp | 102 ++++++++++++++++++ .../AI/AICState/destroyBuildingIfNoWorker.cpp | 40 +++++++ src/OpenSHC/AI/AICState/digNearestMoat.cpp | 44 ++++++++ .../AI/AICState/getDefensiveTribeForUnit.cpp | 80 ++++++++++++++ ...qualThanMinimumGoodsRequiredAfterTrade.cpp | 24 +++++ .../AI/AICState/playAnger1BikFromPlayer.cpp | 32 ++++++ .../playAnger2BikFromPlayerToPlayer.cpp | 29 +++++ .../playFriendlyVictoryBikFromPlayer.cpp | 22 ++++ .../playGoodsNotSentBikFromPlayer.cpp | 22 ++++ .../playGoodsRequestBikFromPlayerToPlayer.cpp | 23 ++++ .../playGoodsSentBikFromPlayerToPlayer.cpp | 23 ++++ .../AI/AICState/playJokeBikFromAIToHuman.cpp | 21 ++++ .../AI/AICState/playNervous1BikFromPlayer.cpp | 23 ++++ .../AI/AICState/playNervous2BikFromPlayer.cpp | 28 +++++ .../AI/AICState/playNoHelpBikFromPlayer.cpp | 22 ++++ ...yerKilledBiksFromKilledAndKillerPlayer.cpp | 56 ++++++++++ .../AICState/playRequestHelpBikFromPlayer.cpp | 27 +++++ ...playTauntToAttackedPlayerBikFromPlayer.cpp | 33 ++++++ .../AICState/playTeamWinningBikFromPlayer.cpp | 22 ++++ .../playThanksBikFromPlayerToPlayer.cpp | 32 ++++++ .../playVictory2BikFromPlayerToPlayer.cpp | 31 ++++++ .../AI/AICState/recreateEngineersTribe.cpp | 22 ++++ .../AI/AICState/smallestTribeOfUnitType.cpp | 60 +++++++++++ .../AICState/syncBehaviourType7UnitTribes.cpp | 35 ++++++ .../AI/AICState/teamIsWeakRelativeToEnemy.cpp | 65 +++++++++++ src/OpenSHC/AI/AICState/wipeAICMemory.cpp | 22 ++++ 42 files changed, 1584 insertions(+) create mode 100644 src/OpenSHC/AI/AICState/Constructor_AICState.cpp create mode 100644 src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp create mode 100644 src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp create mode 100644 src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp create mode 100644 src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp create mode 100644 src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/assignUnitToATribe.cpp create mode 100644 src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp create mode 100644 src/OpenSHC/AI/AICState/createTribeForUnitType.cpp create mode 100644 src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp create mode 100644 src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp create mode 100644 src/OpenSHC/AI/AICState/digNearestMoat.cpp create mode 100644 src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp create mode 100644 src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp create mode 100644 src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp create mode 100644 src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp create mode 100644 src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp create mode 100644 src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp create mode 100644 src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp create mode 100644 src/OpenSHC/AI/AICState/wipeAICMemory.cpp diff --git a/src/OpenSHC/AI/AICState/Constructor_AICState.cpp b/src/OpenSHC/AI/AICState/Constructor_AICState.cpp new file mode 100644 index 000000000..104d8e012 --- /dev/null +++ b/src/OpenSHC/AI/AICState/Constructor_AICState.cpp @@ -0,0 +1,14 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3940 + AICState* AICState::Constructor_AICState() + { + MACRO_CALL_MEMBER(AICState_Func::setInitialAIC, this)(); + this->aiTauntResponseTimeWindow = 0; + return this; + } +} +} diff --git a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp new file mode 100644 index 000000000..2dcf5a1a0 --- /dev/null +++ b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D27E0 + void AICState::addUnitToItsTribe(int unitID, int aiUnitBehaviourType) + { + int iVar1 = (int)DAT_UnitsState::instance.units[unitID].owner; + if (DAT_GameState::instance.playerDataArray[iVar1].aiType != AITA_NULL) { + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = (short)aiUnitBehaviourType; + iVar1 = MACRO_CALL_MEMBER(AICState_Func::addUnitToSmallestBehaviourTypeTribe, this)(iVar1, unitID, aiUnitBehaviourType); + if (iVar1 != 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp new file mode 100644 index 000000000..9c0cb83fb --- /dev/null +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp @@ -0,0 +1,88 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CCD20 + int AICState::addUnitToSmallestBehaviourTypeTribe(undefined4 playerID, undefined4 param_2, undefined4 aiUnitBehaviourType) + { + int _playerID = (int)playerID; + int AVar1 = DAT_GameState::instance.playerDataArray[_playerID].aiType; + if (AVar1 == AITA_NULL) { + return 0; + } + int _tribeTypeOffset = DAT_SkirmishDefinedData::instance.DAT_AIUnitBehaviourTypeMapping[(int)aiUnitBehaviourType + -10]; + int _smallestTribe = 0; + int _smallestTribeOffset = 0; + short _smallestTribeSize = 1000; + dword _groupsCount; + switch (_tribeTypeOffset) { + case 0xf: + _groupsCount = this->aics[AVar1 - 1].AttUnitPatrolGroupsCount; + break; + default: + goto switchD_004ccd78_caseD_10; + case 0xba: + _groupsCount = this->aics[AVar1 - 1].AttUnitBackupGroupsCount; + break; + case 0xbe: + _groupsCount = this->aics[AVar1 - 1].AttUnitSiegeDefGroupsCount; + break; + case 0xc0: + _groupsCount = this->aics[AVar1 - 1].AttMainGroupsCount; + } + int _selectedTribe; + int _selectedSlot; + if (((int)_groupsCount < 1) || (_groupsCount == 1)) { +switchD_004ccd78_caseD_10: + int _tribeID_groupsCount1 = (int)DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_tribeTypeOffset]; + if ((_tribeID_groupsCount1 != 0) && + (DAT_TribesState::instance.tribes[_tribeID_groupsCount1].uid == DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { + return _tribeID_groupsCount1; + } + _selectedTribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); + _selectedSlot = _tribeTypeOffset; + } + else { + int _maxOffset = _groupsCount + _tribeTypeOffset; + _selectedTribe = 0; + _selectedSlot = 0; + short* _pTribeIDs = DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs + _tribeTypeOffset; + if (_tribeTypeOffset < _maxOffset) { + do { + int _tribeID_2 = (int)*_pTribeIDs; + if ((_tribeID_2 == 0) || + (DAT_TribesState::instance.tribes[_tribeID_2].uid != DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { + _selectedTribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); + _selectedSlot = _tribeTypeOffset; + break; + } + short _tribeSize = DAT_TribesState::instance.tribes[_tribeID_2].size; + if (_tribeSize < _smallestTribeSize) { + _smallestTribeOffset = _tribeTypeOffset; + _smallestTribe = _tribeID_2; + _smallestTribeSize = _tribeSize; + } + _pTribeIDs = _pTribeIDs + 1; + _tribeTypeOffset = _tribeTypeOffset + 1; + _selectedTribe = _smallestTribe; + _selectedSlot = _smallestTribeOffset; + } while (_tribeTypeOffset < _maxOffset); + } + } + if (0 < _selectedTribe) { + DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_selectedSlot] = (short)_selectedTribe; + DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_selectedSlot] = DAT_TribesState::instance.tribes[_selectedTribe].uid; + return _selectedTribe; + } + return 0; + } +} +} diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp new file mode 100644 index 000000000..ef1b52ec1 --- /dev/null +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp @@ -0,0 +1,25 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2730 + void AICState::addUnitToSmallestPatrolTribe(int unitID) + { + int iVar1 = (int)DAT_UnitsState::instance.units[unitID].owner; + int _aiType = DAT_GameState::instance.playerDataArray[iVar1].aiType; + if (_aiType != AITA_NULL) { + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 4; + iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::getSmallestPatrolTribe, DAT_TribesState::ptr)(iVar1, (int)this->aics[_aiType - 1].OuterPatrolGroupsCount); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp b/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp new file mode 100644 index 000000000..7eedbe481 --- /dev/null +++ b/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp @@ -0,0 +1,35 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC720 + void AICState::addUnitsToTribe166(int playerID) + { + int tribeID; + uint unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + Map::Units::Unit* pUVar1 = &DAT_UnitsState::instance.units[1]; + do { + if ((((pUVar1->owner == playerID) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) && + (pUVar1->dying == 0)) && (pUVar1->aiUnitBehaviourType == 6)) { + tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; + if (pUVar1->tribeID != tribeID) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)pUVar1->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + } + } + unitID = unitID + 1; + pUVar1 = pUVar1 + 1; + } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp new file mode 100644 index 000000000..857e55933 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp @@ -0,0 +1,30 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC840 + void AICState::aiAddUnitToMoatDiggerTribe(int unitID) + { + int _owner = (int)DAT_UnitsState::instance.units[unitID].owner; + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 5; + int _tribe = (int)DAT_GameState::instance.playerDataArray[_owner].aiTribeIDs[10]; + if ((_tribe == 0) || + (DAT_TribesState::instance.tribes[_tribe].uid != DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10])) { + _tribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_owner); + int _uid = DAT_TribesState::instance.tribes[_tribe].uid; + DAT_GameState::instance.playerDataArray[_owner].aiTribeIDs[10] = (short)_tribe; + DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10] = _uid; + } + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribe); + DAT_TribesState::instance.tribes[_tribe].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp new file mode 100644 index 000000000..037a2f2fe --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp @@ -0,0 +1,48 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3F70 + void AICState::aiAssignMoatDiggers(int playerID) + { + int _unitID; + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + Map::Units::UnitTypeShort _unitType; + if (((_aiType != AITA_NULL) && (0 < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType0)) && + (_unitID = 1, 1 < (int)DAT_UnitsState::instance.maxUnitCount)) { + Map::Units::Unit* _ptrUnit = &DAT_UnitsState::instance.units[1]; + do { + if ((((((_ptrUnit->logicalState != Map::Units::ULS_INVISIBLE) && (_ptrUnit->owner == playerID)) && + ((_ptrUnit->isSelectable_OR_matchTime != 0 && + ((_ptrUnit->aiUnitBehaviourType == 0 && (_ptrUnit->dying == 0)))))) && + (_unitType = _ptrUnit->unitType, _unitType != Map::Units::UT_LORD)) && + ((((_unitType != Map::Units::UT_E_ENGINEER && (_unitType != Map::Units::UT_TUNNELER)) && + (_unitType != Map::Units::UT_S_CATAPULT)) && + ((_unitType != Map::Units::UT_S_TREBUCHET && (_unitType != Map::Units::UT_S_MANGONEL)))))) && + (((_unitType != Map::Units::UT_S_TOWER && + ((_unitType != Map::Units::UT_S_BATTERINGRAM && (_unitType != Map::Units::UT_S_SHIELD)))) && + ((_unitType != Map::Units::UT_S_BALLISTA && (_unitType != Map::Units::UT_S_FBALLISTA)))))) { + if (((((int)this->aics[_aiType - 1].DefDiggingUnitMax == 0) || + (_unitType == Map::Units::UT_E_ARCHER)) || (_unitType == Map::Units::UT_E_XBOW)) || + (_ptrUnit->someUnitStat4 == 0)) { + MACRO_CALL_MEMBER(AICState_Func::assignUnitToATribe, this)(_unitID); + } + else { + MACRO_CALL_MEMBER(AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); + } + } + _unitID = _unitID + 1; + _ptrUnit = _ptrUnit + 1; + } while (_unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp new file mode 100644 index 000000000..22cda9ad7 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2790 + void AICState::aiAssignUnitToDefensiveTribe(int unitID) + { + int _playerID = (int)DAT_UnitsState::instance.units[unitID].owner; + if (DAT_GameState::instance.playerDataArray[_playerID].aiType != AITA_NULL) { + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 2; + int _tribeID = MACRO_CALL_MEMBER(AICState_Func::getDefensiveTribeForUnit, this)(_playerID, unitID); + if (_tribeID != 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp new file mode 100644 index 000000000..75dc1e348 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -0,0 +1,80 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D28B0 + void AICState::aiGiveOuterPatrolCommand(int playerID) + { + int* piVar1; + short sVar2; + int iVar3; + short* psVar4; + int _buildingID; + int _buildingID2; + int _tile; + BOOLEnum _canNavigate; + int _aicOffset; + int _tribeID; + int _index; + int _count; + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType != 0) { + _aicOffset = (_aiType + -1) * 0x2a4; + _count = (int)this->aics[_aiType - 1].OuterPatrolGroupsCount; + _index = 0; + if (((0 < _count) && + (piVar1 = &DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker, + *piVar1 = *piVar1 + 1, + (int)this->aics[_aiType - 1].OuterPatrolRallyDelay <= DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker)) && + (DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker = 0, 0 < _count)) { + psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; + do { + _tribeID = (int)*psVar4; + DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + if (((_tribeID != 0) && + (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0xaa])) && + ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0xb && + ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk < 0xb && + (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk < 0xb)))))) { + if (((int)this->aics[_aiType - 1].OuterPatrolGroupsMove == 0) || + (_buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)(playerID, _index), + _buildingID == 0)) { + _buildingID2 = MACRO_CALL_MEMBER(AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + if (_buildingID2 == 0) goto LAB_004d2a44; + _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryX + + DAT_ViewportRenderState::instance.translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryY].addXgetTile; + } + else { + _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + + DAT_ViewportRenderState::instance.translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryY].addXgetTile; + } + if (_tile != 0) { + sVar2 = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + iVar3 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; + _canNavigate = MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(_tribeID, _tile); + if (_canNavigate == FALSE) { + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); + } + else { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(_tribeID, _tile - iVar3, (int)sVar2, 0); + } + } + } +LAB_004d2a44: + _index = _index + 1; + psVar4 = psVar4 + 1; + } while (_index < _count); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp new file mode 100644 index 000000000..640f619e3 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp @@ -0,0 +1,35 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D40B0 + void AICState::aiReassignTunnelersToTribe(int param_1) + { + uint unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + Map::Units::Unit* psVar1 = &DAT_UnitsState::instance.units[1]; + do { + if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == param_1)) && + (psVar1->dying == 0)) && + ((psVar1->unitType == Map::Units::UT_TUNNELER && (psVar1->aiUnitBehaviourType == 0xf)))) { + if (psVar1->tribeID != 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)psVar1->tribeID); + } + MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 0xf); + } + unitID = unitID + 1; + psVar1 = psVar1 + 1; + } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp new file mode 100644 index 000000000..7379a3ed6 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp @@ -0,0 +1,61 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/AI/Tribes/AITribeType.hpp" + +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2610 + void AICState::aiRecruitEngineerForOilDuty(int playerID) + { + BOOLEnum _hasTribes; + int _newTribe; + int _unitID; + int _amount; + int _oilSmelter; + int _buildingUID; + if (((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && + (_newTribe = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, + DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) && + (29 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf])) && + ((0 < _newTribe && (DAT_BuildingsState::instance.buildings[_newTribe].buildingType == Map::Buildings::BT_ENGINEERSGUILD)))) && + ((_oilSmelter = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id, 0 < _oilSmelter && + ((DAT_BuildingsState::instance.buildings[_oilSmelter].buildingType == Map::Buildings::BT_OILSMELTER && + (_amount = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1] + 1, 1 < _amount)))))) { + if ((DAT_BuildingsState::instance.buildings[_oilSmelter].resourcePitch < 1) && + (DAT_GameState::instance.playerDataArray[playerID].currentResources[7] < 1)) { + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[7] = 4; + return; + } + _hasTribes = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)(playerID, _amount, TRUE); + if (_hasTribes != FALSE) { + _newTribe = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)(playerID, _amount, FALSE); + _unitID = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)(Map::Units::UT_E_ENGINEER, DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, playerID, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(_unitID, _newTribe); + if (_unitID != 0) { + DAT_UnitsState::instance.units[_unitID].engineerRelatedUnk = 1; + DAT_TribesState::instance.tribes[_newTribe].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + _buildingUID = DAT_BuildingsState::instance.buildings[_oilSmelter].uid; + DAT_TribesState::instance.tribes[_newTribe].tribeType = Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_newTribe].tribeBehaviorType = Map::Units::STBT_0x41d; + MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(_newTribe, Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _oilSmelter, _buildingUID, 0); + } + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp b/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp new file mode 100644 index 000000000..7af062fb0 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp @@ -0,0 +1,32 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC520 + void AICState::aiRecruitEngineers(int playerID) + { + int recruitmentBuilding; + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if ((((_aiType != AITA_NULL) && + (DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired != FALSE)) && + (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) && + (((0x1d < (int)this->aics[_aiType - 1].recruitGoldThreshold + DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] && + (recruitmentBuilding = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, + 0 < recruitmentBuilding)) && + (DAT_BuildingsState::instance.buildings[recruitmentBuilding].buildingType == Map::Buildings::BT_ENGINEERSGUILD)))) { + MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)(Map::Units::UT_E_ENGINEER, recruitmentBuilding, playerID, 0); + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = FALSE; + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp new file mode 100644 index 000000000..aeb6e8986 --- /dev/null +++ b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp @@ -0,0 +1,45 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC5A0 + int AICState::assignRequiredIdleEngineersToNewTribe(int playerID, int count) + { + Map::Units::States::UnitStateShort UVar1; + int tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + uint unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + Map::Units::Unit* psVar2 = &DAT_UnitsState::instance.units[1]; + do { + if (count < 1) { + return tribeID; + } + if (((((psVar2->logicalState == Map::Units::ULS_NORMAL) && (psVar2->owner == playerID)) && + (psVar2->dying == 0)) && + ((psVar2->unitType == Map::Units::UT_E_ENGINEER && (psVar2->aiUnitBehaviourType != 0x16)))) && + ((psVar2->aiUnitBehaviourType != 10 && (psVar2->engineerRelatedUnk == 0))) && + (((UVar1 = (psVar2->state).generic, UVar1 == 0x69 || (UVar1 == 2)) || (UVar1 == Map::Units::States::US_IDLEUnk)))) { + if (psVar2->tribeID != 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)psVar2->tribeID); + } + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + count = count + -1; + } + unitID = unitID + 1; + psVar2 = psVar2 + 1; + } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + return tribeID; + } +} +} diff --git a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp new file mode 100644 index 000000000..383a4e51c --- /dev/null +++ b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp @@ -0,0 +1,49 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2660 + void AICState::assignUnitToATribe(int unitID) + { + short* _unitTypeIndex; + int _isOfType; + int _tribeID; + int _playerID = (int)DAT_UnitsState::instance.units[unitID].owner; + if (DAT_GameState::instance.playerDataArray[_playerID].aiType != AITA_NULL) { + int iVar1; + if ((DAT_GameState::instance.playerDataArray[_playerID].aivCurrentPauseIndex == 1) && + (0 < DAT_GameState::instance.playerDataArray[_playerID].aivPauses[1])) { + iVar1 = 1; + } + else { + iVar1 = 0; + } + _unitTypeIndex = (short*)MACRO_CALL(Global_Func::GetUnitTypeIndexForUnitID)(unitID, iVar1); + int _tribeSize = DAT_GameState::instance.playerDataArray[_playerID].aivUnitLocationSlotLocationCount[(int)_unitTypeIndex]; + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 1; + if (_tribeSize < 1) { + _isOfType = MACRO_CALL_MEMBER(AICState_Func::unitIDIsRangedOrArmored, this)(unitID); + if (_isOfType != 0) { + _tribeID = MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(_playerID, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + return; + } + _tribeID = MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(_playerID, 1); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + return; + } + _tribeID = MACRO_CALL_MEMBER(AICState_Func::smallestTribeOfUnitType, this)(_playerID, _unitTypeIndex); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp new file mode 100644 index 000000000..8b18080b6 --- /dev/null +++ b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" + +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD250 + BOOLEnum AICState::canNavigateUnitsFromTileToTargetTile(int tribeID, int tile) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)( + DAT_TribesState::instance.tribes[tribeID].owner, + (int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID].tile], + (int)(short)DAT_TileMapState::instance.PathConnectionLayer[tile], + 0); + return (uint)(iVar1 != 0); + } +} +} diff --git a/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp b/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp new file mode 100644 index 000000000..11260ee9e --- /dev/null +++ b/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp @@ -0,0 +1,26 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC960 + int AICState::createTribeForUnitType(int playerID, int unitSelectionTypeIndex) + { + short* psVar1 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + unitSelectionTypeIndex; + int _tribeID = (int)*psVar1; + if ((_tribeID == 0) || + (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex])) { + _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; + *psVar1 = (short)_tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex] = _tribeUID; + } + return _tribeID; + } +} +} diff --git a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp new file mode 100644 index 000000000..88bab103f --- /dev/null +++ b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp @@ -0,0 +1,102 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0280 + void AICState::destroyAnyBuildingInCategory(int playerID, AINervousDestroyBuildingCategory buildingCategory) + { + Map::Buildings::BuildingTypeShort BVar1; + int _buildingID; + bool bVar2; + + _buildingID = 1; + if (1 < DAT_BuildingsState::instance.maxBuildingsCount) { + Map::Buildings::Building* pBVar2 = &DAT_BuildingsState::instance.buildings[1]; + do { + if (((pBVar2->logicalState != 0) && (pBVar2->logicalState != Map::Buildings::BLS_REMOVE)) && + (pBVar2->owner == playerID)) { + if (buildingCategory == AINDBC_FEAR_FACTOR_BUILDINGS) { + BVar1 = pBVar2->buildingType; + if (((BVar1 != Map::Buildings::BT_CESSPIT) && (BVar1 != Map::Buildings::BT_BURNINGSTAKE)) && + (((BVar1 != Map::Buildings::BT_GIBBET && + (((BVar1 != Map::Buildings::BT_DUNGEON && (BVar1 != Map::Buildings::BT_STRETCHINGRACK)) && (BVar1 != Map::Buildings::BT_RACKFLOGGING)))) && + (((BVar1 != Map::Buildings::BT_CHOPPINGBLOCK && (BVar1 != Map::Buildings::BT_DUNKINGSTOOL)) && + ((BVar1 != Map::Buildings::BT_DOGCAGE && + (((BVar1 != Map::Buildings::BT_STATUE && (BVar1 != Map::Buildings::BT_SHRINE)) && + ((BVar1 != Map::Buildings::BT_DANCINGBEAR && + ((((BVar1 != Map::Buildings::BT_POND && (BVar1 != Map::Buildings::BT_GALLOWS)) && (BVar1 != Map::Buildings::BT_STOCKS)) && + ((BVar1 != Map::Buildings::BT_WITCHHOIST && (BVar1 != Map::Buildings::BT_MAYPOLE)))))))))))))))) { + bVar2 = BVar1 == Map::Buildings::BT_GARDEN; + goto LAB_004d04de; + } + } + else if (buildingCategory == AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS) { + BVar1 = pBVar2->buildingType; + if (((BVar1 != Map::Buildings::BT_FLETCHER) && (BVar1 != Map::Buildings::BT_BLACKSMITH)) && + (((BVar1 != Map::Buildings::BT_POLETURNER && + (((BVar1 != Map::Buildings::BT_ARMOURER && (BVar1 != Map::Buildings::BT_TANNER)) && (BVar1 != Map::Buildings::BT_INN)))) && + (((BVar1 != Map::Buildings::BT_APOTHECARY && (BVar1 != Map::Buildings::BT_CHAPEL)) && (BVar1 != Map::Buildings::BT_CHURCH)))))) { + bVar2 = BVar1 == Map::Buildings::BT_CATHEDRAL; + goto LAB_004d04de; + } + } + else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) { + BVar1 = pBVar2->buildingType; + if (((((BVar1 != Map::Buildings::BT_GATEHOUSELARGE) && (BVar1 != Map::Buildings::BT_GATEHOUSESMALL)) && + ((BVar1 != Map::Buildings::BT_DRAWBRIDGE && + ((((BVar1 != Map::Buildings::BT_TOWER1 && (BVar1 != Map::Buildings::BT_TOWER2)) && (BVar1 != Map::Buildings::BT_TOWER3)) && + ((BVar1 != Map::Buildings::BT_TOWER4 && (BVar1 != Map::Buildings::BT_TOWER5)))))))) && (BVar1 != Map::Buildings::BT_ENGINEERSGUILD)) && + (BVar1 != Map::Buildings::BT_TUNNELERSGUILD)) { + bVar2 = BVar1 == Map::Buildings::BT_OILSMELTER; + goto LAB_004d04de; + } + } + else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) { + BVar1 = pBVar2->buildingType; + if ((BVar1 != Map::Buildings::BT_MERCENARYPOST) && (BVar1 != Map::Buildings::BT_BARRACKS)) { + bVar2 = BVar1 == Map::Buildings::BT_STABLES; + goto LAB_004d04de; + } + } + else if (buildingCategory == AINDBC_WATER_BUILDINGS) { + if (pBVar2->buildingType != Map::Buildings::BT_WELL) { + bVar2 = pBVar2->buildingType == Map::Buildings::BT_WATERPOT; + goto LAB_004d04de; + } + } + else if (buildingCategory == AINDBC_RESOURCE_BUILDINGS) { + BVar1 = pBVar2->buildingType; + if (((BVar1 != Map::Buildings::BT_OXTETHER) && (BVar1 != Map::Buildings::BT_IRONMINE)) && + ((BVar1 != Map::Buildings::BT_PITCHRIG && + (((BVar1 != Map::Buildings::BT_BAKERY && (BVar1 != Map::Buildings::BT_BREWERY)) && (BVar1 != Map::Buildings::BT_QUARRY)))))) { + bVar2 = BVar1 == Map::Buildings::BT_MILL; +LAB_004d04de: + if (!bVar2) goto LAB_004d04f9; + } + } + else { + if (((buildingCategory == AINDBC_FARMS) && + (BVar1 = pBVar2->buildingType, BVar1 != Map::Buildings::BT_WHEATFARM)) && + ((BVar1 != Map::Buildings::BT_HOPFARM && (BVar1 != Map::Buildings::BT_APPLEFARM)))) { + bVar2 = BVar1 == Map::Buildings::BT_DAIRYFARM; + goto LAB_004d04de; + } + } + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_buildingID); + } +LAB_004d04f9: + _buildingID = _buildingID + 1; + pBVar2 = pBVar2 + 1; + } while (_buildingID < DAT_BuildingsState::instance.maxBuildingsCount); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp new file mode 100644 index 000000000..97c182d7a --- /dev/null +++ b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/AI/AIVState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_AIVState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB940 + undefined4 AICState::destroyBuildingIfNoWorker(int buildingID) + { + short _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; + int _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; + if ((((0 < _value) && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1)) && + (DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0)) && + (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY)) { + if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] == 0) { + if (0x13 < _value) { + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(buildingID); + return 1; + } + } + else if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { + DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = _value + -1; + } + } + return 0; + } +} +} diff --git a/src/OpenSHC/AI/AICState/digNearestMoat.cpp b/src/OpenSHC/AI/AICState/digNearestMoat.cpp new file mode 100644 index 000000000..c734a3ff9 --- /dev/null +++ b/src/OpenSHC/AI/AICState/digNearestMoat.cpp @@ -0,0 +1,44 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD160 + void AICState::digNearestMoat(int playerID) + { + int iVar1; + BOOLEnum tile; + int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10]; + if ((((tribeID != 0) && + (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10])) && + (0 < DAT_TribesState::instance.tribes[tribeID].size)) && + (DAT_TribesState::instance.tribes[tribeID].percentageSomething < 0x51)) { + iVar1 = MACRO_CALL_MEMBER(Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)(playerID); + if (iVar1 < 1) { + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); + return; + } + iVar1 = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + tile = MACRO_CALL_MEMBER(Map::TileMapState_Func::findNearestFriendlyMoatTileForDigging, DAT_TileMapState::ptr)(playerID, iVar1, 1); + if (-1 < (int)tile) { + MACRO_CALL_MEMBER(Map::TileMapState_Func::setXYBasedOnMoatID, DAT_TileMapState::ptr)(tile, 1, (int)DAT_UnitsState::instance.units[iVar1].x, (int)DAT_UnitsState::instance.units[iVar1].y); + iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::updateTribeRallyFlags, DAT_TribesState::ptr)(tribeID); + if (iVar1 == 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(tribeID, Map::Units::UIT_DIG_MOAT, DAT_TileMapState::instance.ALG_MoatXResult, DAT_TileMapState::instance.ALG_MoatYResult, 0); + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_STAND_GROUND; + } + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp new file mode 100644 index 000000000..7aaa535d8 --- /dev/null +++ b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp @@ -0,0 +1,80 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CCBF0 + int AICState::getDefensiveTribeForUnit(int playerID, int unitID) + { + int _index = 0; + int _unitType = (int)(short)DAT_UnitsState::instance.units[unitID].unitType; + int _unitType2; + do { + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index]) || + (_unitType2 = (int)(short)DAT_UnitsState::instance.units[unitID].unitTypeToChangeInto, + _unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index])) break; + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1]) || + (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1])) { + _index = _index + 1; + break; + } + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2]) || + (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2])) { + _index = _index + 2; + break; + } + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3]) || + (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3])) { + _index = _index + 3; + break; + } + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4]) || + (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4])) { + _index = _index + 4; + break; + } + _index = _index + 5; + } while (_index < 0x14); + int _tribeIndex; + if (_index < 1) { + _tribeIndex = 0xb4; + } + else if (_index < 2) { + _tribeIndex = 0xb5; + } + else if (_index < 7) { + _tribeIndex = 0xb6; + } + else if (_index < 0xc) { + _tribeIndex = 0xb7; + } + else if (_index < 0xf) { + _tribeIndex = 0xb8; + } + else { + if (19 < _index) { + return 0; + } + _tribeIndex = 0xb9; + } + short* _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeIndex; + int _tribeID = (int)*_pTribeID; + if ((_tribeID == 0) || + (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex])) { + _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; + *_pTribeID = (short)_tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex] = _tribeUID; + } + return _tribeID; + } +} +} diff --git a/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp b/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp new file mode 100644 index 000000000..6dd67d991 --- /dev/null +++ b/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp @@ -0,0 +1,24 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Game/Resources/ResourceType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0520 + BOOLEnum AICState::isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade(int playerID, ResourceType resourceType, int buffer) + { + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == AITA_NULL) { + return TRUE; + } + if (resourceType == Game::Resources::RT_GOLD) { + return FALSE; + } + return (int)this->aics[_aiType - 1].minimumGoodsRequiredAfterTrade + buffer <= DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType]; + } +} +} diff --git a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp new file mode 100644 index 000000000..4f4662e1d --- /dev/null +++ b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp @@ -0,0 +1,32 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" +#include "OpenSHC/Globals/INT_ARRAY_00eb0af0.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0830 + void AICState::playAnger1BikFromPlayer(int playerID) + { + int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar2 != 0) { + int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] != DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) && + (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { + DWORD DVar3 = timeGetTime(); + if ((INT_ARRAY_00eb0af0::instance[playerID] == 0) || (599999 < DVar3 - INT_ARRAY_00eb0af0::instance[playerID])) { + INT_ARRAY_00eb0af0::instance[playerID] = DVar3; + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 5); + } + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp new file mode 100644 index 000000000..b235964f5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp @@ -0,0 +1,29 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0C00 + void AICState::playAnger2BikFromPlayerToPlayer(int playerID, int targetPlayerID) + { + if (DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + bool bVar2; + if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 == 0)) && + (bVar2 = targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, + DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 = 0x60, bVar2)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 6); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp new file mode 100644 index 000000000..2d99ef4d8 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0FC0 + void AICState::playFriendlyVictoryBikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 10); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp new file mode 100644 index 000000000..d3d56f13d --- /dev/null +++ b/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0B70 + void AICState::playGoodsNotSentBikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1c); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp new file mode 100644 index 000000000..8aec4a1c2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0A20 + void AICState::playGoodsRequestBikFromPlayerToPlayer(int playerID, int targetPlayerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) && (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID].lordKilledByPlayerID == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0xe); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp new file mode 100644 index 000000000..fbab88edc --- /dev/null +++ b/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0BB0 + void AICState::playGoodsSentBikFromPlayerToPlayer(int playerID, int targetPlayerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if ((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1d); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp b/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp new file mode 100644 index 000000000..b976cc78c --- /dev/null +++ b/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp @@ -0,0 +1,21 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0F90 + void AICState::playJokeBikFromAIToHuman(int playerID, int aiType) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, aiType, 0x14); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp new file mode 100644 index 000000000..28e61efb1 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp @@ -0,0 +1,23 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0CF0 + void AICState::playNervous1BikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if ((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 == 0)) { + DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 = 0x30; + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 8); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp new file mode 100644 index 000000000..4d3b6da36 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp @@ -0,0 +1,28 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0B10 + void AICState::playNervous2BikFromPlayer(int playerID) + { + int iVar3 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar2 = DAT_GameSynchronyState::instance.currentPlayerSlotID; + if ((iVar3 != 0) && (DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown == 0)) { + int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown = 48; + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] != DAT_GameState::instance.mapAndTime.playerTeams[iVar2]) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 9); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp new file mode 100644 index 000000000..d8ca73671 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1050 + void AICState::playNoHelpBikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1f); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp new file mode 100644 index 000000000..b9bf203fe --- /dev/null +++ b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp @@ -0,0 +1,56 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D08B0 + void AICState::playPlayerKilledBiksFromKilledAndKillerPlayer(int killerPlayerID, int killedPlayerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(killerPlayerID); + if (iVar1 != 0) { + if (killedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + iVar1 = 0xc; + } + else { + if (killerPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + int i = 1; + do { + if ((DAT_GameState::instance.playerDataArray[i].aiType != AITA_NULL) && + (DAT_GameState::instance.mapAndTime.playerTeams[i] == DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i); + if (iVar2 != 0) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(i, (int)DAT_GameState::instance.playerDataArray[i].aiType - 1, 0x11); + } + } + i = i + 1; + } while (i < 9); + return; + } + iVar1 = DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]; + if (iVar1 == DAT_GameState::instance.mapAndTime.playerTeams[killedPlayerID]) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 0x10); + return; + } + if (DAT_GameState::instance.mapAndTime.playerTeams[killerPlayerID] == iVar1) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 0x12); + return; + } + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + iVar1 = 0xd; + } + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, iVar1); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp new file mode 100644 index 000000000..1dc39d4bf --- /dev/null +++ b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp @@ -0,0 +1,27 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0D40 + void AICState::playRequestHelpBikFromPlayer(int playerID) + { + int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 = DAT_GameSynchronyState::instance.currentPlayerSlotID; + if ((iVar2 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 == 0)) { + DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 = 0x30; + if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[iVar1]) && (DAT_GameState::instance.playerDataArray[iVar1].lordKilledByPlayerID == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x13); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp new file mode 100644 index 000000000..89cacc944 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp @@ -0,0 +1,33 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D07C0 + void AICState::playTauntToAttackedPlayerBikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + iVar1 = 0; + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { + iVar1 = 0x17; + } + if (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (iVar1 == 0) { + iVar1 = ((byte)SEC_RNG::instance.currentNumber2 & 3) + 1; + } + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, iVar1); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp new file mode 100644 index 000000000..e27c7b599 --- /dev/null +++ b/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1000 + void AICState::playTeamWinningBikFromPlayer(int playerID) + { + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker == 0)) && (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1e); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp new file mode 100644 index 000000000..e216c8c1f --- /dev/null +++ b/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp @@ -0,0 +1,32 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" +#include "OpenSHC/Globals/DWORD_00eb0b18.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0A80 + void AICState::playThanksBikFromPlayerToPlayer(int playerID, int targetPlayerID) + { + DWORD DVar2; + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (iVar1 != 0) { + iVar1 = (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + DAT_GameState::instance.playerDataArray[playerID].aiRequestDelay = this->aics[iVar1].aiRequestDelay; + if (((targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) && + (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID].lordKilledByPlayerID == 0)) && + ((DVar2 = timeGetTime(), DWORD_00eb0b18::instance == 0 || (1199999 < DVar2 - DWORD_00eb0b18::instance)))) { + DWORD_00eb0b18::instance = DVar2; + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, iVar1, 0xf); + } + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp new file mode 100644 index 000000000..5fb4e29cf --- /dev/null +++ b/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp @@ -0,0 +1,31 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0C70 + void AICState::playVictory2BikFromPlayerToPlayer(int playerID, int targetPlayerID) + { + int iVar1; + bool bVar2; + if ((((DAT_GameState::instance.playerDataArray[targetPlayerID].aiType != AITA_NULL) && + (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] != -1)) && + (iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(targetPlayerID), iVar1 != 0)) && + (((iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID), iVar1 != 0 && + (DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 == 0)) && + (bVar2 = playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, + DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 = 0x30, bVar2)))) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(targetPlayerID, (int)DAT_GameState::instance.playerDataArray[targetPlayerID].aiType - 1, 0xb); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp new file mode 100644 index 000000000..ad2cf43b2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4630 + void AICState::recreateEngineersTribe(int playerID) + { + if (0 < DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops) { + int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; + if ((_tribeID != 0) && + (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12] = 0; + } + MACRO_CALL_MEMBER(AICState_Func::addEngineersToTribe, this)(playerID); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp new file mode 100644 index 000000000..b1b870c29 --- /dev/null +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -0,0 +1,60 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC9B0 + int AICState::smallestTribeOfUnitType(int playerID, short* unitType) + { + int iVar7 = 0; + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == AITA_NULL) { + return 0; + } + int iVar3 = (int)this->aics[_aiType - 1].defWallPatrolGroups; + int iVar6 = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[(int)unitType]; + int _tribeID = 0; + int local_c = 0; + short sVar4 = 1000; + if ((iVar3 < iVar6) && + (((unitType == (short*)0x8 || (unitType == (short*)0xa)) || (unitType == (short*)0x11)))) { + iVar6 = iVar3; + } + iVar3 = DAT_SkirmishDefinedData::instance.DAT_AiTribeIDOffsetForUnitType[(int)unitType]; + if (0 < iVar6) { + unitType = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar3; + do { + int iVar5 = (int)*unitType; + if ((iVar5 == 0) || + (DAT_TribesState::instance.tribes[iVar5].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7])) { + _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + goto LAB_004ccaae; + } + short sVar1 = DAT_TribesState::instance.tribes[iVar5].size; + if (sVar1 < sVar4) { + _tribeID = iVar5; + local_c = iVar7; + sVar4 = sVar1; + } + unitType = unitType + 1; + iVar7 = iVar7 + 1; + } while (iVar7 < iVar6); + iVar7 = local_c; + if (_tribeID != 0) { +LAB_004ccaae: + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[iVar3 + iVar7] = (short)_tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] = DAT_TribesState::instance.tribes[_tribeID].uid; + return _tribeID; + } + } + return 0; + } +} +} diff --git a/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp b/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp new file mode 100644 index 000000000..45d773b2c --- /dev/null +++ b/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp @@ -0,0 +1,35 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC7B0 + void AICState::syncBehaviourType7UnitTribes(int param_1) + { + int tribeID; + uint unitID = 1; + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + Map::Units::Unit* pUVar1 = &DAT_UnitsState::instance.units[1]; + do { + if ((((pUVar1->owner == param_1) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) && + (pUVar1->dying == 0)) && (pUVar1->aiUnitBehaviourType == 7)) { + tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xa7]; + if (pUVar1->tribeID != tribeID) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)pUVar1->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + } + } + unitID = unitID + 1; + pUVar1 = pUVar1 + 1; + } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + } + } +} +} diff --git a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp new file mode 100644 index 000000000..fb055692e --- /dev/null +++ b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp @@ -0,0 +1,65 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/Game/GameStateStructures.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameCore.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D0190 + BOOLEnum AICState::teamIsWeakRelativeToEnemy(int playerID, BOOLEnum param_2) + { + short _relativeStrength; + int _totalEnemyTroopValue = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; + if (_totalEnemyTroopValue == 0) { + _relativeStrength = 100; + } + else { + _relativeStrength = (short)((DAT_GameState::instance.playerDataArray[playerID].totalTeamTroopValue * 100) / _totalEnemyTroopValue); + } + DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy = _relativeStrength; + if (param_2 == FALSE) { + if (DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue < 100) { + return FALSE; + } + BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + if (BVar2 != FALSE) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 50) { + return TRUE; + } + return FALSE; + } + if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 250) { + return TRUE; + } + return FALSE; + } + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 75) { + return TRUE; + } + } + else { + BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + if (BVar2 != FALSE) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 0x46) { + return TRUE; + } + return FALSE; + } + if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 300) { + return TRUE; + } + return FALSE; + } + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 100) { + return TRUE; + } + } + return FALSE; + } +} +} diff --git a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp new file mode 100644 index 000000000..414009e9a --- /dev/null +++ b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp @@ -0,0 +1,22 @@ +#include "OpenSHC/AI/AICState.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004C6D30 + void AICState::wipeAICMemory() + { + AICSpecification* destination = this->aics; + int iVar1 = 20; + do { + MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)(676, '\0', destination); + destination = destination + 1; + iVar1 = iVar1 + -1; + } while (iVar1 != 0); + } +} +} From fe391814d241cccc71d653f6ccb0bba399708362 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 20 Jul 2026 16:28:18 +0200 Subject: [PATCH 031/242] batch 5 unpolished --- .../AI/AICState/setAICParameters_01.cpp | 150 ++++++++++++++++++ .../AI/AICState/setAICParameters_02.cpp | 148 +++++++++++++++++ .../AI/AICState/setAICParameters_03.cpp | 148 +++++++++++++++++ .../AI/AICState/setAICParameters_04.cpp | 149 +++++++++++++++++ .../AI/AICState/setAICParameters_05.cpp | 148 +++++++++++++++++ 5 files changed, 743 insertions(+) create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_01.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_02.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_03.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_04.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_05.cpp diff --git a/src/OpenSHC/AI/AICState/setAICParameters_01.cpp b/src/OpenSHC/AI/AICState/setAICParameters_01.cpp new file mode 100644 index 000000000..3cb13057a --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_01.cpp @@ -0,0 +1,150 @@ +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AICState.hpp" + +namespace OpenSHC { +namespace AI { + + using AIC::AITC_ANY; + using AIC::AITC_BALANCED; + using AIC::AITC_CLOSEST; + using AIC::AITC_GOLD; + using AIC::AITC_PLAYER; + + // FUNCTION: STRONGHOLDCRUSADER 0x004C6D60 + void AICState::setAICParameters_01(int aicID) + { + this->aics[aicID].populationPerFarm = 6; + this->aics[aicID].minimumCheese = 0xffffffff; + this->aics[aicID].minimumBread = 0xffffffff; + this->aics[aicID].minimumWheat = 0xffffffff; + this->aics[aicID].minimumHop = 0xffffffff; + this->aics[aicID].aiRequestDelay = 0x12; + this->aics[aicID].populationPerQuarry = 0x12; + this->aics[aicID].maxWoodcutters = 6; + this->aics[aicID].maxFarms = 6; + this->aics[aicID].sellResource09 = 0x12; + this->aics[aicID].flagType = 0xc; + this->aics[aicID].unknown002 = 0; + this->aics[aicID].unknown001 = 0; + this->aics[aicID].unknown003 = 0; + this->aics[aicID].unknown004 = 0; + this->aics[aicID].unknown005 = 0; + this->aics[aicID].criticalPopularity = 4000; + this->aics[aicID].lowestPopularity = 0x157c; + this->aics[aicID].highestPopularity = 0x1d4c; + this->aics[aicID].taxesMin = 3; + this->aics[aicID].taxesMax = 10; + this->aics[aicID].farm1 = 0x20; + this->aics[aicID].unknown011 = 0x14; + this->aics[aicID].maxFood = 100; + this->aics[aicID].minimumApples = 10; + this->aics[aicID].tradeAmountFood = 10; + this->aics[aicID].tradeAmountEquipment = 2; + this->aics[aicID].minimumGoodsRequiredAfterTrade = 0; + this->aics[aicID].doubleRationsFoodThreshold = 0; + this->aics[aicID].maxWood = 0x1e; + this->aics[aicID].maxStone = 0x28; + this->aics[aicID].maxResourceOther = 0x14; + this->aics[aicID].maxEquipment = 0x14; + this->aics[aicID].maxBeer = 0x14; + this->aics[aicID].maxResourceVariance = 5; + this->aics[aicID].recruitGoldThreshold = 200; + this->aics[aicID].populationPerWoodcutter = 8; + this->aics[aicID].populationPerIronmine = 0; + this->aics[aicID].populationPerPitchrig = 0; + this->aics[aicID].maxQuarries = 1; + this->aics[aicID].maxIronmines = 1; + this->aics[aicID].maxPitchrigs = 1; + this->aics[aicID].buildInterval = 1; + this->aics[aicID].resourceRebuildDelay = 10; + this->aics[aicID].blacksmithSetting = 0x16; + this->aics[aicID].fletcherSetting = 0x11; + this->aics[aicID].poleturnerSetting = 0x13; + this->aics[aicID].sellResource02 = 3; + this->aics[aicID].sellResource03 = 6; + this->aics[aicID].sellResource04 = 7; + this->aics[aicID].sellResource05 = 9; + this->aics[aicID].sellResource06 = 0xe; + this->aics[aicID].sellResource07 = 0x10; + this->aics[aicID].sellResource11 = 0x14; + this->aics[aicID].sellResource12 = 0x15; + this->aics[aicID].sellResource13 = 0x16; + this->aics[aicID].sellResource14 = 0x17; + this->aics[aicID].sellResource15 = 0x18; + this->aics[aicID].defWallPatrolRallyTime = 0x14; + this->aics[aicID].defWallPatrolGroups = 1; + this->aics[aicID].defSiegeEngineGoldThreshold = 200; + this->aics[aicID].defSiegeEngineBuildDelay = 0x14; + this->aics[aicID].unknown072 = 800; + this->aics[aicID].unknown073 = 0x50; + this->aics[aicID].recruitProbDefWeak = 0x32; + this->aics[aicID].RecruitIntervalWeak = 1; + this->aics[aicID].RecruitInterval = 1; + this->aics[aicID].RecruitIntervalStrong = 1; + this->aics[aicID].SortieUnitRanged = 0x16; + this->aics[aicID].SortieUnitMelee = 0x18; + this->aics[aicID].DefDiggingUnit = 0x18; + this->aics[aicID].OuterPatrolGroupsCount = 1; + this->aics[aicID].OuterPatrolRallyDelay = 10; + this->aics[aicID].DefUnit1 = 0x18; + this->aics[aicID].DefUnit2 = 0x18; + this->aics[aicID].DefUnit3 = 0x16; + this->aics[aicID].DefUnit4 = 0x16; + this->aics[aicID].RaidUnitsBase = 10; + this->aics[aicID].RaidUnit1 = 0x18; + this->aics[aicID].RaidUnit2 = 0x18; + this->aics[aicID].RaidUnit3 = 0x16; + this->aics[aicID].recruitProbDefDefault = 0; + this->aics[aicID].recruitProbDefStrong = 0; + this->aics[aicID].recruitProbRaidWeak = 0x32; + this->aics[aicID].recruitProbRaidDefault = 0x32; + this->aics[aicID].recruitProbRaidStrong = 0; + this->aics[aicID].recruitProbAttackWeak = 0; + this->aics[aicID].recruitProbAttackDefault = 0x32; + this->aics[aicID].recruitProbAttackStrong = 100; + this->aics[aicID].SortieUnitRangedMin = 5; + this->aics[aicID].SortieUnitMeleeMin = 6; + this->aics[aicID].DefDiggingUnitMax = 0; + this->aics[aicID].DefWalls = 0x14; + this->aics[aicID].DefTotal = 0x1e; + this->aics[aicID].OuterPatrolGroupsMove = 0; + this->aics[aicID].RaidUnitsRandom = 0xf; + this->aics[aicID].HarassingSiegeEnginesMax = 0; + this->aics[aicID].HarassingSiegeEngine1 = 0xbe; + this->aics[aicID].RaidRetargetDelay = 3; + this->aics[aicID].AttForceBase = 0x14; + this->aics[aicID].AttForceRandom = 10; + this->aics[aicID].AttForceSupportAllyThreshold = 0xf; + this->aics[aicID].AttForceRallyPercentage = 0x32; + this->aics[aicID].AttMovingTribesThreshold = 100; + this->aics[aicID].AttAssaultDelay = 0; + this->aics[aicID].AttUnitPatrolRecommandDelay = 0x19; + this->aics[aicID].AttCoordinationPreference = 0x14; + this->aics[aicID].SiegeEngine1 = 0; + this->aics[aicID].CowThrowInterval = 1000; + this->aics[aicID].AttMaxEngineers = 0; + this->aics[aicID].AttDiggingUnit = 0x18; + this->aics[aicID].AttDiggingUnitMax = 0x14; + this->aics[aicID].AttMaxAssassins = 0; + this->aics[aicID].AttUnit2 = 0x16; + this->aics[aicID].AttUnit2Max = 0; + this->aics[aicID].AttMaxLaddermen = 0; + this->aics[aicID].AttMaxTunnelers = 0; + this->aics[aicID].AttUnitPatrol = 0x16; + this->aics[aicID].AttUnitPatrolMax = 0; + this->aics[aicID].AttUnitPatrolGroupsCount = 0; + this->aics[aicID].AttUnitBackup = 0x16; + this->aics[aicID].AttUnitBackupMax = 0x10; + this->aics[aicID].AttUnitBackupGroupsCount = 0; + this->aics[aicID].AttUnitEngageMax = 0; + this->aics[aicID].AttUnitEngage = 0; + this->aics[aicID].AttUnitSiegeDef = 0x18; + this->aics[aicID].AttUnitSiegeDefMax = 0; + this->aics[aicID].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicID].AttUnitMain1 = 0x18; + this->aics[aicID].AttMaxDefault = 200; + this->aics[aicID].AttMainGroupsCount = 1; + this->aics[aicID].TargetChoice = AITC_PLAYER; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_02.cpp b/src/OpenSHC/AI/AICState/setAICParameters_02.cpp new file mode 100644 index 000000000..c3e0c0b69 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_02.cpp @@ -0,0 +1,148 @@ +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AICState.hpp" + +namespace OpenSHC { +namespace AI { + + using AIC::AITC_ANY; + using AIC::AITC_BALANCED; + using AIC::AITC_CLOSEST; + using AIC::AITC_GOLD; + using AIC::AITC_PLAYER; + + // FUNCTION: STRONGHOLDCRUSADER 0x004C7120 + void AICState::setAICParameters_02(int param_1) + { + this->aics[param_1].minimumBread = 0xffffffff; + this->aics[param_1].minimumWheat = 0xffffffff; + this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].populationPerFarm = 5; + this->aics[param_1].unknown011 = 0xf; + this->aics[param_1].tradeAmountFood = 5; + this->aics[param_1].aiRequestDelay = 0xc; + this->aics[param_1].maxResourceOther = 0xf; + this->aics[param_1].maxEquipment = 0xc; + this->aics[param_1].maxBeer = 5; + this->aics[param_1].maxResourceVariance = 5; + this->aics[param_1].populationPerWoodcutter = 5; + this->aics[param_1].populationPerQuarry = 0xf; + this->aics[param_1].resourceRebuildDelay = 0xc; + this->aics[param_1].flagType = 0xc; + this->aics[param_1].unknown002 = 0; + this->aics[param_1].unknown001 = 0; + this->aics[param_1].unknown003 = 0; + this->aics[param_1].unknown004 = 0; + this->aics[param_1].unknown005 = 0; + this->aics[param_1].criticalPopularity = 4000; + this->aics[param_1].lowestPopularity = 5000; + this->aics[param_1].highestPopularity = 8000; + this->aics[param_1].taxesMin = 3; + this->aics[param_1].taxesMax = 0xb; + this->aics[param_1].farm1 = 0x20; + this->aics[param_1].maxFood = 0x96; + this->aics[param_1].minimumApples = 10; + this->aics[param_1].minimumCheese = 0x14; + this->aics[param_1].tradeAmountEquipment = 6; + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + this->aics[param_1].doubleRationsFoodThreshold = 0x50; + this->aics[param_1].maxWood = 0x30; + this->aics[param_1].maxStone = 0x28; + this->aics[param_1].recruitGoldThreshold = 200; + this->aics[param_1].populationPerIronmine = 0; + this->aics[param_1].populationPerPitchrig = 0; + this->aics[param_1].maxQuarries = 2; + this->aics[param_1].maxIronmines = 1; + this->aics[param_1].maxWoodcutters = 10; + this->aics[param_1].maxPitchrigs = 1; + this->aics[param_1].maxFarms = 10; + this->aics[param_1].buildInterval = 2; + this->aics[param_1].blacksmithSetting = 0x16; + this->aics[param_1].fletcherSetting = 0x11; + this->aics[param_1].poleturnerSetting = 0x13; + this->aics[param_1].sellResource02 = 3; + this->aics[param_1].sellResource03 = 6; + this->aics[param_1].sellResource04 = 7; + this->aics[param_1].sellResource05 = 9; + this->aics[param_1].sellResource06 = 0xe; + this->aics[param_1].sellResource07 = 0x10; + this->aics[param_1].sellResource09 = 0x12; + this->aics[param_1].sellResource11 = 0x14; + this->aics[param_1].sellResource12 = 0x15; + this->aics[param_1].sellResource13 = 0x16; + this->aics[param_1].sellResource14 = 0x17; + this->aics[param_1].sellResource15 = 0x18; + this->aics[param_1].defWallPatrolRallyTime = 2; + this->aics[param_1].defWallPatrolGroups = 4; + this->aics[param_1].defSiegeEngineGoldThreshold = 500; + this->aics[param_1].defSiegeEngineBuildDelay = 0x14; + this->aics[param_1].unknown072 = 400; + this->aics[param_1].unknown073 = 0x3c; + this->aics[param_1].recruitProbDefStrong = 0x14; + this->aics[param_1].SortieUnitRanged = 0x16; + this->aics[param_1].DefDiggingUnitMax = 0x14; + this->aics[param_1].DefUnit1 = 0x16; + this->aics[param_1].RaidUnitsRandom = 10; + this->aics[param_1].recruitProbDefWeak = 0x46; + this->aics[param_1].recruitProbRaidDefault = 0x28; + this->aics[param_1].recruitProbRaidStrong = 0x28; + this->aics[param_1].recruitProbAttackWeak = 0; + this->aics[param_1].recruitProbAttackStrong = 0x28; + this->aics[param_1].RecruitIntervalWeak = 0; + this->aics[param_1].RecruitInterval = 1; + this->aics[param_1].RecruitIntervalStrong = 1; + this->aics[param_1].SortieUnitRangedMin = 2; + this->aics[param_1].SortieUnitMeleeMin = 8; + this->aics[param_1].SortieUnitMelee = 0x18; + this->aics[param_1].DefDiggingUnit = 0x18; + this->aics[param_1].DefWalls = 0x32; + this->aics[param_1].DefTotal = 0x50; + this->aics[param_1].OuterPatrolGroupsCount = 3; + this->aics[param_1].OuterPatrolGroupsMove = 1; + this->aics[param_1].OuterPatrolRallyDelay = 2; + this->aics[param_1].RaidUnit1 = 0x47; + this->aics[param_1].RaidUnit2 = 0x47; + this->aics[param_1].RaidUnit3 = 0x47; + this->aics[param_1].RaidUnit4 = 0x48; + this->aics[param_1].HarassingSiegeEnginesMax = 1; + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + this->aics[param_1].recruitProbDefDefault = 0x1e; + this->aics[param_1].recruitProbRaidWeak = 0x1e; + this->aics[param_1].recruitProbAttackDefault = 0x1e; + this->aics[param_1].RaidUnitsBase = 0x1e; + this->aics[param_1].RaidRetargetDelay = 3; + this->aics[param_1].AttForceBase = 0x1e; + this->aics[param_1].AttForceRandom = 10; + this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; + this->aics[param_1].AttForceRallyPercentage = 0x32; + this->aics[param_1].AttMovingTribesThreshold = 100; + this->aics[param_1].AttAssaultDelay = 0; + this->aics[param_1].AttUnitPatrolRecommandDelay = 0x19; + this->aics[param_1].AttCoordinationPreference = 0x28; + this->aics[param_1].SiegeEngine1 = 0x27; + this->aics[param_1].CowThrowInterval = 1000; + this->aics[param_1].AttMaxEngineers = 2; + this->aics[param_1].AttDiggingUnit = 0x18; + this->aics[param_1].AttDiggingUnitMax = 0x14; + this->aics[param_1].AttMaxAssassins = 0; + this->aics[param_1].AttUnit2 = 0x16; + this->aics[param_1].AttUnit2Max = 0x14; + this->aics[param_1].AttMaxLaddermen = 10; + this->aics[param_1].AttMaxTunnelers = 0; + this->aics[param_1].AttUnitPatrol = 0x48; + this->aics[param_1].AttUnitPatrolMax = 0; + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + this->aics[param_1].AttUnitBackup = 0x46; + this->aics[param_1].AttUnitBackupMax = 0x32; + this->aics[param_1].AttUnitBackupGroupsCount = 1; + this->aics[param_1].AttUnitEngageMax = 0; + this->aics[param_1].AttUnitEngage = 0; + this->aics[param_1].AttUnitSiegeDef = 0x16; + this->aics[param_1].AttUnitSiegeDefMax = 0x1e; + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + this->aics[param_1].AttUnitMain1 = 0x18; + this->aics[param_1].AttMaxDefault = 200; + this->aics[param_1].AttMainGroupsCount = 1; + this->aics[param_1].TargetChoice = AITC_BALANCED; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_03.cpp b/src/OpenSHC/AI/AICState/setAICParameters_03.cpp new file mode 100644 index 000000000..2305891ed --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_03.cpp @@ -0,0 +1,148 @@ +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AICState.hpp" + +namespace OpenSHC { +namespace AI { + + using AIC::AITC_ANY; + using AIC::AITC_BALANCED; + using AIC::AITC_CLOSEST; + using AIC::AITC_GOLD; + using AIC::AITC_PLAYER; + + // FUNCTION: STRONGHOLDCRUSADER 0x004C7520 + void AICState::setAICParameters_03(int param_1) + { + this->aics[param_1].minimumWheat = 0xffffffff; + this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].flagType = 0xc; + this->aics[param_1].unknown002 = 0; + this->aics[param_1].unknown001 = 0; + this->aics[param_1].unknown003 = 0; + this->aics[param_1].unknown004 = 0; + this->aics[param_1].unknown005 = 0; + this->aics[param_1].criticalPopularity = 5000; + this->aics[param_1].lowestPopularity = 7000; + this->aics[param_1].highestPopularity = 0x2134; + this->aics[param_1].taxesMin = 3; + this->aics[param_1].taxesMax = 0xb; + this->aics[param_1].farm1 = 0x21; + this->aics[param_1].populationPerFarm = 4; + this->aics[param_1].unknown011 = 0x14; + this->aics[param_1].maxFood = 400; + this->aics[param_1].minimumApples = 10; + this->aics[param_1].minimumCheese = 10; + this->aics[param_1].minimumBread = 10; + this->aics[param_1].tradeAmountFood = 5; + this->aics[param_1].tradeAmountEquipment = 4; + this->aics[param_1].aiRequestDelay = 0xc; + this->aics[param_1].minimumGoodsRequiredAfterTrade = 100; + this->aics[param_1].doubleRationsFoodThreshold = 0x3c; + this->aics[param_1].maxWood = 0x46; + this->aics[param_1].maxStone = 0x28; + this->aics[param_1].maxResourceOther = 10; + this->aics[param_1].maxEquipment = 10; + this->aics[param_1].maxBeer = 5; + this->aics[param_1].maxResourceVariance = 5; + this->aics[param_1].recruitGoldThreshold = 200; + this->aics[param_1].populationPerWoodcutter = 6; + this->aics[param_1].populationPerQuarry = 0x19; + this->aics[param_1].populationPerIronmine = 10; + this->aics[param_1].populationPerPitchrig = 0x14; + this->aics[param_1].maxQuarries = 2; + this->aics[param_1].maxIronmines = 4; + this->aics[param_1].maxWoodcutters = 8; + this->aics[param_1].maxPitchrigs = 1; + this->aics[param_1].maxFarms = 0xc; + this->aics[param_1].buildInterval = 3; + this->aics[param_1].resourceRebuildDelay = 0x32; + this->aics[param_1].blacksmithSetting = 0x15; + this->aics[param_1].fletcherSetting = 0x12; + this->aics[param_1].poleturnerSetting = 0x13; + this->aics[param_1].sellResource02 = 3; + this->aics[param_1].sellResource04 = 7; + this->aics[param_1].sellResource05 = 9; + this->aics[param_1].sellResource06 = 0xe; + this->aics[param_1].sellResource07 = 0x10; + this->aics[param_1].sellResource08 = 0x11; + this->aics[param_1].sellResource10 = 0x13; + this->aics[param_1].sellResource11 = 0x14; + this->aics[param_1].sellResource13 = 0x16; + this->aics[param_1].sellResource15 = 0x18; + this->aics[param_1].defWallPatrolRallyTime = 10; + this->aics[param_1].defWallPatrolGroups = 4; + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + this->aics[param_1].defSiegeEngineBuildDelay = 0x14; + this->aics[param_1].unknown072 = 200; + this->aics[param_1].unknown073 = 0x28; + this->aics[param_1].recruitProbDefWeak = 100; + this->aics[param_1].recruitProbDefDefault = 0x3c; + this->aics[param_1].recruitProbDefStrong = 0x1e; + this->aics[param_1].recruitProbRaidWeak = 0; + this->aics[param_1].recruitProbRaidDefault = 0; + this->aics[param_1].RecruitIntervalWeak = 1; + this->aics[param_1].RecruitInterval = 1; + this->aics[param_1].RecruitIntervalStrong = 4; + this->aics[param_1].SortieUnitRangedMin = 4; + this->aics[param_1].OuterPatrolRallyDelay = 0x14; + this->aics[param_1].SortieUnitMeleeMin = 5; + this->aics[param_1].RaidUnitsRandom = 5; + this->aics[param_1].recruitProbRaidStrong = 0; + this->aics[param_1].recruitProbAttackWeak = 0; + this->aics[param_1].recruitProbAttackDefault = 0x28; + this->aics[param_1].recruitProbAttackStrong = 0x46; + this->aics[param_1].DefDiggingUnitMax = 0; + this->aics[param_1].DefDiggingUnit = 0x18; + this->aics[param_1].DefWalls = 0x1e; + this->aics[param_1].DefTotal = 0x28; + this->aics[param_1].OuterPatrolGroupsCount = 2; + this->aics[param_1].OuterPatrolGroupsMove = 1; + this->aics[param_1].RaidUnitsBase = 10; + this->aics[param_1].HarassingSiegeEnginesMax = 2; + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + this->aics[param_1].RaidRetargetDelay = 3; + this->aics[param_1].AttForceBase = 10; + this->aics[param_1].AttForceRandom = 10; + this->aics[param_1].SortieUnitRanged = 0x17; + this->aics[param_1].DefUnit1 = 0x17; + this->aics[param_1].DefUnit2 = 0x17; + this->aics[param_1].DefUnit3 = 0x17; + this->aics[param_1].SortieUnitMelee = 0x1a; + this->aics[param_1].RaidUnit1 = 0x1a; + this->aics[param_1].AttForceSupportAllyThreshold = 10; + this->aics[param_1].AttForceRallyPercentage = 0x3c; + this->aics[param_1].AttMovingTribesThreshold = 100; + this->aics[param_1].AttAssaultDelay = 5; + this->aics[param_1].AttUnitPatrolRecommandDelay = 0xf; + this->aics[param_1].AttCoordinationPreference = 0x14; + this->aics[param_1].CowThrowInterval = 0x1e; + this->aics[param_1].SiegeEngine1 = 0x27; + this->aics[param_1].SiegeEngine2 = 0x27; + this->aics[param_1].SiegeEngine3 = 0x27; + this->aics[param_1].SiegeEngine4 = 0x3b; + this->aics[param_1].AttMaxEngineers = 10; + this->aics[param_1].AttDiggingUnit = 0x1a; + this->aics[param_1].AttDiggingUnitMax = 10; + this->aics[param_1].AttMaxAssassins = 0; + this->aics[param_1].AttUnit2 = 0; + this->aics[param_1].AttUnit2Max = 0; + this->aics[param_1].AttMaxLaddermen = 0; + this->aics[param_1].AttMaxTunnelers = 0; + this->aics[param_1].AttUnitPatrol = 0; + this->aics[param_1].AttUnitPatrolMax = 0; + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + this->aics[param_1].AttUnitBackup = 0x17; + this->aics[param_1].AttUnitBackupMax = 5; + this->aics[param_1].AttUnitBackupGroupsCount = 1; + this->aics[param_1].AttUnitEngageMax = 0; + this->aics[param_1].AttUnitEngage = 0; + this->aics[param_1].AttUnitSiegeDef = 0x1a; + this->aics[param_1].AttUnitSiegeDefMax = 0; + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + this->aics[param_1].AttUnitMain1 = 0x1a; + this->aics[param_1].AttMaxDefault = 200; + this->aics[param_1].AttMainGroupsCount = 2; + this->aics[param_1].TargetChoice = AITC_GOLD; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_04.cpp b/src/OpenSHC/AI/AICState/setAICParameters_04.cpp new file mode 100644 index 000000000..e81e060e1 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_04.cpp @@ -0,0 +1,149 @@ +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AICState.hpp" + +namespace OpenSHC { +namespace AI { + + using AIC::AITC_ANY; + using AIC::AITC_BALANCED; + using AIC::AITC_CLOSEST; + using AIC::AITC_GOLD; + using AIC::AITC_PLAYER; + + // FUNCTION: STRONGHOLDCRUSADER 0x004C7910 + void AICState::setAICParameters_04(int param_1) + { + this->aics[param_1].unknown004 = 1; + this->aics[param_1].unknown005 = 1; + this->aics[param_1].farm2 = 0x20; + this->aics[param_1].farm4 = 0x20; + this->aics[param_1].minimumWheat = 0xffffffff; + this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].flagType = 0xd; + this->aics[param_1].unknown002 = 0; + this->aics[param_1].unknown001 = 0; + this->aics[param_1].unknown003 = 0; + this->aics[param_1].criticalPopularity = 0x1194; + this->aics[param_1].lowestPopularity = 6000; + this->aics[param_1].highestPopularity = 9000; + this->aics[param_1].taxesMin = 3; + this->aics[param_1].taxesMax = 0xb; + this->aics[param_1].farm1 = 0x21; + this->aics[param_1].farm3 = 0x1f; + this->aics[param_1].populationPerFarm = 5; + this->aics[param_1].unknown011 = 0xc; + this->aics[param_1].maxFood = 200; + this->aics[param_1].minimumApples = 5; + this->aics[param_1].minimumCheese = 5; + this->aics[param_1].minimumBread = 5; + this->aics[param_1].tradeAmountFood = 10; + this->aics[param_1].tradeAmountEquipment = 4; + this->aics[param_1].aiRequestDelay = 0x14; + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x28; + this->aics[param_1].doubleRationsFoodThreshold = 0x1e; + this->aics[param_1].maxWood = 0x3c; + this->aics[param_1].maxStone = 0x32; + this->aics[param_1].maxResourceOther = 10; + this->aics[param_1].maxEquipment = 10; + this->aics[param_1].maxBeer = 0xf; + this->aics[param_1].maxResourceVariance = 5; + this->aics[param_1].recruitGoldThreshold = 200; + this->aics[param_1].populationPerWoodcutter = 4; + this->aics[param_1].populationPerQuarry = 9; + this->aics[param_1].populationPerIronmine = 0xd; + this->aics[param_1].populationPerPitchrig = 0xf; + this->aics[param_1].maxQuarries = 6; + this->aics[param_1].maxIronmines = 3; + this->aics[param_1].maxWoodcutters = 0xc; + this->aics[param_1].maxPitchrigs = 2; + this->aics[param_1].maxFarms = 10; + this->aics[param_1].buildInterval = 3; + this->aics[param_1].resourceRebuildDelay = 0x14; + this->aics[param_1].blacksmithSetting = 0x16; + this->aics[param_1].fletcherSetting = 0x12; + this->aics[param_1].poleturnerSetting = 0x14; + this->aics[param_1].sellResource05 = 9; + this->aics[param_1].sellResource07 = 0x10; + this->aics[param_1].sellResource10 = 0x13; + this->aics[param_1].sellResource12 = 0x15; + this->aics[param_1].defWallPatrolRallyTime = 4; + this->aics[param_1].defWallPatrolGroups = 3; + this->aics[param_1].defSiegeEngineGoldThreshold = 0xfa; + this->aics[param_1].defSiegeEngineBuildDelay = 2; + this->aics[param_1].unknown072 = 100; + this->aics[param_1].unknown073 = 0x14; + this->aics[param_1].recruitProbDefWeak = 0x5a; + this->aics[param_1].recruitProbDefDefault = 0x3c; + this->aics[param_1].recruitProbDefStrong = 0x1e; + this->aics[param_1].recruitProbRaidWeak = 10; + this->aics[param_1].recruitProbRaidDefault = 0x1e; + this->aics[param_1].recruitProbRaidStrong = 10; + this->aics[param_1].recruitProbAttackDefault = 10; + this->aics[param_1].RecruitInterval = 4; + this->aics[param_1].RecruitIntervalStrong = 4; + this->aics[param_1].OuterPatrolGroupsCount = 4; + this->aics[param_1].HarassingSiegeEnginesMax = 4; + this->aics[param_1].recruitProbAttackWeak = 0; + this->aics[param_1].OuterPatrolRallyDelay = 3; + this->aics[param_1].RaidUnitsRandom = 0x14; + this->aics[param_1].recruitProbAttackStrong = 0x3c; + this->aics[param_1].RecruitIntervalWeak = 1; + this->aics[param_1].SortieUnitRangedMin = 8; + this->aics[param_1].SortieUnitRanged = 0x46; + this->aics[param_1].SortieUnitMeleeMin = 6; + this->aics[param_1].DefDiggingUnitMax = 8; + this->aics[param_1].DefWalls = 0x50; + this->aics[param_1].DefTotal = 100; + this->aics[param_1].OuterPatrolGroupsMove = 1; + this->aics[param_1].DefUnit1 = 0x17; + this->aics[param_1].DefUnit2 = 0x17; + this->aics[param_1].DefUnit3 = 0x16; + this->aics[param_1].DefUnit4 = 0x16; + this->aics[param_1].RaidUnitsBase = 5; + this->aics[param_1].RaidUnit1 = 0x4a; + this->aics[param_1].RaidUnit2 = 0x4a; + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + this->aics[param_1].RaidRetargetDelay = 5; + this->aics[param_1].AttForceRandom = 0xf; + this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; + this->aics[param_1].SortieUnitMelee = 0x19; + this->aics[param_1].DefDiggingUnit = 0x19; + this->aics[param_1].AttForceBase = 0x28; + this->aics[param_1].AttForceRallyPercentage = 0x50; + this->aics[param_1].AttMovingTribesThreshold = 100; + this->aics[param_1].AttAssaultDelay = 0xc; + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + this->aics[param_1].AttCoordinationPreference = 0x32; + this->aics[param_1].CowThrowInterval = 8; + this->aics[param_1].SiegeEngine1 = 0x27; + this->aics[param_1].SiegeEngine2 = 0x28; + this->aics[param_1].SiegeEngine3 = 0x4d; + this->aics[param_1].SiegeEngine4 = 0x28; + this->aics[param_1].AttMaxEngineers = 0xc; + this->aics[param_1].AttDiggingUnit = 0x19; + this->aics[param_1].AttDiggingUnitMax = 0x14; + this->aics[param_1].AttMaxAssassins = 0; + this->aics[param_1].AttUnit2 = 0; + this->aics[param_1].AttUnit2Max = 0; + this->aics[param_1].AttMaxLaddermen = 0; + this->aics[param_1].AttMaxTunnelers = 0; + this->aics[param_1].AttUnitPatrol = 0; + this->aics[param_1].AttUnitPatrolMax = 0; + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + this->aics[param_1].AttUnitBackup = 0x17; + this->aics[param_1].AttUnitBackupMax = 0x1e; + this->aics[param_1].AttUnitBackupGroupsCount = 3; + this->aics[param_1].AttUnitEngageMax = 0; + this->aics[param_1].AttUnitEngage = 0; + this->aics[param_1].AttUnitSiegeDef = 0x1b; + this->aics[param_1].AttUnitSiegeDefMax = 5; + this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; + this->aics[param_1].AttUnitMain1 = 0x1b; + this->aics[param_1].AttUnitMain2 = 0x19; + this->aics[param_1].AttUnitMain3 = 0x19; + this->aics[param_1].AttMaxDefault = 200; + this->aics[param_1].AttMainGroupsCount = 3; + this->aics[param_1].TargetChoice = AITC_CLOSEST; + } +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_05.cpp b/src/OpenSHC/AI/AICState/setAICParameters_05.cpp new file mode 100644 index 000000000..b3958aa09 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_05.cpp @@ -0,0 +1,148 @@ +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AICState.hpp" + +namespace OpenSHC { +namespace AI { + + using AIC::AITC_ANY; + using AIC::AITC_BALANCED; + using AIC::AITC_CLOSEST; + using AIC::AITC_GOLD; + using AIC::AITC_PLAYER; + + // FUNCTION: STRONGHOLDCRUSADER 0x004C7D20 + void AICState::setAICParameters_05(int param_1) + { + this->aics[param_1].maxFood = 0x32; + this->aics[param_1].maxStone = 0x32; + this->aics[param_1].taxesMin = 3; + this->aics[param_1].taxesMax = 0xc; + this->aics[param_1].farm2 = 0x1e; + this->aics[param_1].farm3 = 0x1e; + this->aics[param_1].populationPerFarm = 3; + this->aics[param_1].populationPerIronmine = 0xc; + this->aics[param_1].maxQuarries = 4; + this->aics[param_1].maxIronmines = 4; + this->aics[param_1].defWallPatrolGroups = 4; + this->aics[param_1].flagType = 10; + this->aics[param_1].unknown002 = 0; + this->aics[param_1].unknown001 = 0; + this->aics[param_1].unknown003 = 0; + this->aics[param_1].unknown004 = 0; + this->aics[param_1].unknown005 = 0; + this->aics[param_1].criticalPopularity = 4000; + this->aics[param_1].lowestPopularity = 5000; + this->aics[param_1].highestPopularity = 8000; + this->aics[param_1].farm1 = 0x1f; + this->aics[param_1].farm4 = 0x20; + this->aics[param_1].unknown011 = 0x14; + this->aics[param_1].minimumApples = 5; + this->aics[param_1].minimumCheese = 5; + this->aics[param_1].minimumBread = 5; + this->aics[param_1].minimumWheat = 5; + this->aics[param_1].minimumHop = 5; + this->aics[param_1].tradeAmountFood = 10; + this->aics[param_1].tradeAmountEquipment = 0; + this->aics[param_1].aiRequestDelay = 0x28; + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x14; + this->aics[param_1].doubleRationsFoodThreshold = 0x14; + this->aics[param_1].maxWood = 0x3c; + this->aics[param_1].maxResourceOther = 10; + this->aics[param_1].maxEquipment = 5; + this->aics[param_1].maxBeer = 10; + this->aics[param_1].maxResourceVariance = 2; + this->aics[param_1].recruitGoldThreshold = 200; + this->aics[param_1].populationPerWoodcutter = 6; + this->aics[param_1].populationPerQuarry = 10; + this->aics[param_1].populationPerPitchrig = 0x14; + this->aics[param_1].maxWoodcutters = 0xe; + this->aics[param_1].maxPitchrigs = 1; + this->aics[param_1].maxFarms = 0xf; + this->aics[param_1].buildInterval = 2; + this->aics[param_1].resourceRebuildDelay = 0x28; + this->aics[param_1].blacksmithSetting = 0x16; + this->aics[param_1].fletcherSetting = 0x12; + this->aics[param_1].poleturnerSetting = 0x14; + this->aics[param_1].defWallPatrolRallyTime = 3; + this->aics[param_1].defSiegeEngineGoldThreshold = 0x14; + this->aics[param_1].defSiegeEngineBuildDelay = 8; + this->aics[param_1].sellResource08 = 0x11; + this->aics[param_1].sellResource09 = 0x12; + this->aics[param_1].sellResource11 = 0x14; + this->aics[param_1].sellResource12 = 0x15; + this->aics[param_1].sellResource14 = 0x17; + this->aics[param_1].unknown072 = 100; + this->aics[param_1].unknown073 = 0x14; + this->aics[param_1].recruitProbDefWeak = 100; + this->aics[param_1].recruitProbDefDefault = 0x22; + this->aics[param_1].recruitProbDefStrong = 0x19; + this->aics[param_1].RaidUnitsRandom = 5; + this->aics[param_1].HarassingSiegeEnginesMax = 5; + this->aics[param_1].RecruitIntervalWeak = 1; + this->aics[param_1].RecruitInterval = 1; + this->aics[param_1].RecruitIntervalStrong = 1; + this->aics[param_1].SortieUnitRangedMin = 10; + this->aics[param_1].OuterPatrolGroupsMove = 1; + this->aics[param_1].OuterPatrolRallyDelay = 10; + this->aics[param_1].RaidUnitsBase = 10; + this->aics[param_1].AttForceRandom = 10; + this->aics[param_1].recruitProbRaidWeak = 0; + this->aics[param_1].recruitProbRaidStrong = 0x19; + this->aics[param_1].recruitProbAttackWeak = 0; + this->aics[param_1].recruitProbAttackStrong = 0x32; + this->aics[param_1].SortieUnitMeleeMin = 7; + this->aics[param_1].SortieUnitMelee = 0x4b; + this->aics[param_1].DefDiggingUnitMax = 4; + this->aics[param_1].DefDiggingUnit = 0x47; + this->aics[param_1].DefWalls = 0x32; + this->aics[param_1].OuterPatrolGroupsCount = 2; + this->aics[param_1].DefUnit1 = 0x4b; + this->aics[param_1].DefUnit5 = 0x4c; + this->aics[param_1].RaidUnit1 = 0x4a; + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + this->aics[param_1].RaidRetargetDelay = 3; + this->aics[param_1].AttForceBase = 0x32; + this->aics[param_1].recruitProbRaidDefault = 0x21; + this->aics[param_1].recruitProbAttackDefault = 0x21; + this->aics[param_1].SortieUnitRanged = 0x46; + this->aics[param_1].DefTotal = 0x46; + this->aics[param_1].DefUnit2 = 0x46; + this->aics[param_1].DefUnit3 = 0x46; + this->aics[param_1].DefUnit4 = 0x46; + this->aics[param_1].AttForceSupportAllyThreshold = 8; + this->aics[param_1].AttForceRallyPercentage = 0x50; + this->aics[param_1].AttMovingTribesThreshold = 100; + this->aics[param_1].AttAssaultDelay = 4; + this->aics[param_1].AttUnitPatrolRecommandDelay = 1; + this->aics[param_1].AttCoordinationPreference = 0x3c; + this->aics[param_1].CowThrowInterval = 2000; + this->aics[param_1].SiegeEngine1 = 0x4d; + this->aics[param_1].SiegeEngine2 = 0x4d; + this->aics[param_1].SiegeEngine3 = 0x27; + this->aics[param_1].SiegeEngine4 = 0x27; + this->aics[param_1].AttMaxEngineers = 10; + this->aics[param_1].AttDiggingUnit = 0x47; + this->aics[param_1].AttDiggingUnitMax = 0x14; + this->aics[param_1].AttMaxAssassins = 5; + this->aics[param_1].AttUnit2 = 0x4a; + this->aics[param_1].AttUnit2Max = 0x14; + this->aics[param_1].AttMaxLaddermen = 0; + this->aics[param_1].AttMaxTunnelers = 0; + this->aics[param_1].AttUnitPatrol = 0x4a; + this->aics[param_1].AttUnitPatrolMax = 0x14; + this->aics[param_1].AttUnitPatrolGroupsCount = 1; + this->aics[param_1].AttUnitBackup = 0x46; + this->aics[param_1].AttUnitBackupMax = 0x14; + this->aics[param_1].AttUnitBackupGroupsCount = 3; + this->aics[param_1].AttUnitEngageMax = 0; + this->aics[param_1].AttUnitEngage = 0x4c; + this->aics[param_1].AttUnitSiegeDef = 0x4c; + this->aics[param_1].AttUnitSiegeDefMax = 6; + this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; + this->aics[param_1].AttUnitMain1 = 0x4b; + this->aics[param_1].AttMaxDefault = 200; + this->aics[param_1].AttMainGroupsCount = 3; + this->aics[param_1].TargetChoice = AITC_GOLD; + } +} +} From 67e71789074ba262d7fedac77a9d5b8fffce0d8d Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 20 Jul 2026 16:50:53 +0200 Subject: [PATCH 032/242] clang-formatting --- src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp | 8 +- .../addUnitToSmallestBehaviourTypeTribe.cpp | 38 ++++--- .../AICState/addUnitToSmallestPatrolTribe.cpp | 8 +- .../AI/AICState/addUnitsToTribe166.cpp | 16 +-- .../AICState/aiAddUnitToMoatDiggerTribe.cpp | 13 +-- .../AI/AICState/aiAssignMoatDiggers.cpp | 39 +++---- .../AICState/aiAssignUnitToDefensiveTribe.cpp | 5 +- .../aiCommandTribe11StandGroundToGate.cpp | 18 ++-- .../aiCommandTribe13DefensiveWave.cpp | 17 +-- .../AICState/aiCommandWallAssaultTribes.cpp | 15 +-- .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 66 +++++++----- .../AICState/aiReassignTunnelersToTribe.cpp | 12 +-- .../AICState/aiRecruitEngineerForOilDuty.cpp | 62 ++++++----- .../AI/AICState/aiRecruitEngineers.cpp | 25 ++--- .../assignRequiredIdleEngineersToNewTribe.cpp | 27 ++--- .../AI/AICState/assignUnitToATribe.cpp | 18 ++-- src/OpenSHC/AI/AICState/buyGoods.cpp | 1 + .../canNavigateUnitsFromTileToTargetTile.cpp | 16 +-- .../AI/AICState/createTribeForUnitType.cpp | 11 +- .../AICState/destroyAnyBuildingInCategory.cpp | 102 ++++++++++-------- .../AI/AICState/destroyBuildingIfNoWorker.cpp | 22 ++-- src/OpenSHC/AI/AICState/digNearestMoat.cpp | 32 +++--- .../AI/AICState/getDefensiveTribeForUnit.cpp | 51 +++++---- .../AICState/hasNoTroopsOrAllAreDiggers.cpp | 32 +++--- .../AI/AICState/hasNotEnoughSupplies.cpp | 22 ++-- .../AICState/ifHasTribe0SendUnitsToKeep.cpp | 5 +- ...qualThanMinimumGoodsRequiredAfterTrade.cpp | 7 +- .../AI/AICState/playAnger1BikFromPlayer.cpp | 19 ++-- .../playAnger2BikFromPlayerToPlayer.cpp | 17 +-- .../playFriendlyVictoryBikFromPlayer.cpp | 9 +- .../playGoodsNotSentBikFromPlayer.cpp | 9 +- .../playGoodsRequestBikFromPlayerToPlayer.cpp | 14 ++- .../playGoodsSentBikFromPlayerToPlayer.cpp | 9 +- .../AI/AICState/playJokeBikFromAIToHuman.cpp | 9 +- .../AI/AICState/playNervous1BikFromPlayer.cpp | 9 +- .../AI/AICState/playNervous2BikFromPlayer.cpp | 12 ++- .../AI/AICState/playNoHelpBikFromPlayer.cpp | 9 +- ...yerKilledBiksFromKilledAndKillerPlayer.cpp | 49 ++++++--- .../AICState/playRequestHelpBikFromPlayer.cpp | 13 ++- ...playTauntToAttackedPlayerBikFromPlayer.cpp | 16 +-- .../AICState/playTeamWinningBikFromPlayer.cpp | 12 ++- .../playThanksBikFromPlayerToPlayer.cpp | 18 ++-- .../playVictory2BikFromPlayerToPlayer.cpp | 25 +++-- .../AI/AICState/recreateEngineersTribe.cpp | 5 +- .../sendAITribe_0xf_toAttackPatrol.cpp | 15 +-- .../AICState/sendTribeAtOffset1ToCampfire.cpp | 5 +- src/OpenSHC/AI/AICState/sendTribeToAttack.cpp | 17 +-- .../AI/AICState/sendUnitsToCampfire.cpp | 7 +- src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp | 9 +- .../AI/AICState/setAttackPrimeInfo.cpp | 15 ++- ...htTribe0xc0TribesToAggressiveAndAttack.cpp | 15 +-- ...x11ToAggressiveAndAttackIfConditionMet.cpp | 19 ++-- .../setTribe0xCtoAggressiveAndAttack.cpp | 17 +-- .../setTribe0xbToAggressiveAndAttack.cpp | 17 +-- .../AICState/shouldDestroyWoodCutterUnk.cpp | 22 ++-- ...rketArmoryGranaryBarracksMercenarypost.cpp | 12 ++- .../AI/AICState/smallestTribeOfUnitType.cpp | 22 ++-- .../AICState/syncBehaviourType7UnitTribes.cpp | 16 +-- .../AI/AICState/teamIsWeakRelativeToEnemy.cpp | 20 ++-- src/OpenSHC/AI/AICState/wipeAICMemory.cpp | 6 +- 60 files changed, 651 insertions(+), 525 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp index 2dcf5a1a0..216be457c 100644 --- a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp @@ -1,11 +1,10 @@ #include "OpenSHC/AI/AICState.func.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -16,7 +15,8 @@ namespace AI { int iVar1 = (int)DAT_UnitsState::instance.units[unitID].owner; if (DAT_GameState::instance.playerDataArray[iVar1].aiType != AITA_NULL) { DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = (short)aiUnitBehaviourType; - iVar1 = MACRO_CALL_MEMBER(AICState_Func::addUnitToSmallestBehaviourTypeTribe, this)(iVar1, unitID, aiUnitBehaviourType); + iVar1 = MACRO_CALL_MEMBER(AICState_Func::addUnitToSmallestBehaviourTypeTribe, this)( + iVar1, unitID, aiUnitBehaviourType); if (iVar1 != 0) { MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); } diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp index 9c0cb83fb..fb1ce9974 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp @@ -1,24 +1,25 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" -#include "OpenSHC/Map/Units/TribesState.func.hpp" - #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CCD20 - int AICState::addUnitToSmallestBehaviourTypeTribe(undefined4 playerID, undefined4 param_2, undefined4 aiUnitBehaviourType) + int AICState::addUnitToSmallestBehaviourTypeTribe( + undefined4 playerID, undefined4 param_2, undefined4 aiUnitBehaviourType) { int _playerID = (int)playerID; int AVar1 = DAT_GameState::instance.playerDataArray[_playerID].aiType; if (AVar1 == AITA_NULL) { return 0; } - int _tribeTypeOffset = DAT_SkirmishDefinedData::instance.DAT_AIUnitBehaviourTypeMapping[(int)aiUnitBehaviourType + -10]; + int _tribeTypeOffset + = DAT_SkirmishDefinedData::instance.DAT_AIUnitBehaviourTypeMapping[(int)aiUnitBehaviourType + -10]; int _smallestTribe = 0; int _smallestTribeOffset = 0; short _smallestTribeSize = 1000; @@ -41,16 +42,18 @@ namespace AI { int _selectedTribe; int _selectedSlot; if (((int)_groupsCount < 1) || (_groupsCount == 1)) { -switchD_004ccd78_caseD_10: - int _tribeID_groupsCount1 = (int)DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_tribeTypeOffset]; - if ((_tribeID_groupsCount1 != 0) && - (DAT_TribesState::instance.tribes[_tribeID_groupsCount1].uid == DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { + switchD_004ccd78_caseD_10: + int _tribeID_groupsCount1 + = (int)DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_tribeTypeOffset]; + if ((_tribeID_groupsCount1 != 0) + && (DAT_TribesState::instance.tribes[_tribeID_groupsCount1].uid + == DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { return _tribeID_groupsCount1; } - _selectedTribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); + _selectedTribe = MACRO_CALL_MEMBER( + Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); _selectedSlot = _tribeTypeOffset; - } - else { + } else { int _maxOffset = _groupsCount + _tribeTypeOffset; _selectedTribe = 0; _selectedSlot = 0; @@ -58,9 +61,11 @@ namespace AI { if (_tribeTypeOffset < _maxOffset) { do { int _tribeID_2 = (int)*_pTribeIDs; - if ((_tribeID_2 == 0) || - (DAT_TribesState::instance.tribes[_tribeID_2].uid != DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { - _selectedTribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); + if ((_tribeID_2 == 0) + || (DAT_TribesState::instance.tribes[_tribeID_2].uid + != DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { + _selectedTribe = MACRO_CALL_MEMBER( + Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); _selectedSlot = _tribeTypeOffset; break; } @@ -79,7 +84,8 @@ namespace AI { } if (0 < _selectedTribe) { DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_selectedSlot] = (short)_selectedTribe; - DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_selectedSlot] = DAT_TribesState::instance.tribes[_selectedTribe].uid; + DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_selectedSlot] + = DAT_TribesState::instance.tribes[_selectedTribe].uid; return _selectedTribe; } return 0; diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp index ef1b52ec1..9a2d04fed 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp @@ -1,11 +1,10 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" -#include "OpenSHC/Map/Units/TribesState.func.hpp" - #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -17,7 +16,8 @@ namespace AI { int _aiType = DAT_GameState::instance.playerDataArray[iVar1].aiType; if (_aiType != AITA_NULL) { DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 4; - iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::getSmallestPatrolTribe, DAT_TribesState::ptr)(iVar1, (int)this->aics[_aiType - 1].OuterPatrolGroupsCount); + iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::getSmallestPatrolTribe, DAT_TribesState::ptr)( + iVar1, (int)this->aics[_aiType - 1].OuterPatrolGroupsCount); MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); } } diff --git a/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp b/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp index 7eedbe481..fa55cb886 100644 --- a/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp +++ b/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp @@ -1,11 +1,10 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -18,12 +17,15 @@ namespace AI { if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { Map::Units::Unit* pUVar1 = &DAT_UnitsState::instance.units[1]; do { - if ((((pUVar1->owner == playerID) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) && - (pUVar1->dying == 0)) && (pUVar1->aiUnitBehaviourType == 6)) { + if ((((pUVar1->owner == playerID) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) + && (pUVar1->dying == 0)) + && (pUVar1->aiUnitBehaviourType == 6)) { tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; if (pUVar1->tribeID != tribeID) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)pUVar1->tribeID); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, (int)pUVar1->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, tribeID); } } unitID = unitID + 1; diff --git a/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp index 857e55933..c9a91b8db 100644 --- a/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp @@ -1,11 +1,10 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -16,9 +15,11 @@ namespace AI { int _owner = (int)DAT_UnitsState::instance.units[unitID].owner; DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 5; int _tribe = (int)DAT_GameState::instance.playerDataArray[_owner].aiTribeIDs[10]; - if ((_tribe == 0) || - (DAT_TribesState::instance.tribes[_tribe].uid != DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10])) { - _tribe = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_owner); + if ((_tribe == 0) + || (DAT_TribesState::instance.tribes[_tribe].uid + != DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10])) { + _tribe + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_owner); int _uid = DAT_TribesState::instance.tribes[_tribe].uid; DAT_GameState::instance.playerDataArray[_owner].aiTribeIDs[10] = (short)_tribe; DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10] = _uid; diff --git a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp index 037a2f2fe..0cc811666 100644 --- a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp +++ b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp @@ -1,8 +1,7 @@ #include "OpenSHC/AI/AICState.func.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -16,26 +15,28 @@ namespace AI { int _unitID; int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; Map::Units::UnitTypeShort _unitType; - if (((_aiType != AITA_NULL) && (0 < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType0)) && - (_unitID = 1, 1 < (int)DAT_UnitsState::instance.maxUnitCount)) { + if (((_aiType != AITA_NULL) && (0 < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType0)) + && (_unitID = 1, 1 < (int)DAT_UnitsState::instance.maxUnitCount)) { Map::Units::Unit* _ptrUnit = &DAT_UnitsState::instance.units[1]; do { - if ((((((_ptrUnit->logicalState != Map::Units::ULS_INVISIBLE) && (_ptrUnit->owner == playerID)) && - ((_ptrUnit->isSelectable_OR_matchTime != 0 && - ((_ptrUnit->aiUnitBehaviourType == 0 && (_ptrUnit->dying == 0)))))) && - (_unitType = _ptrUnit->unitType, _unitType != Map::Units::UT_LORD)) && - ((((_unitType != Map::Units::UT_E_ENGINEER && (_unitType != Map::Units::UT_TUNNELER)) && - (_unitType != Map::Units::UT_S_CATAPULT)) && - ((_unitType != Map::Units::UT_S_TREBUCHET && (_unitType != Map::Units::UT_S_MANGONEL)))))) && - (((_unitType != Map::Units::UT_S_TOWER && - ((_unitType != Map::Units::UT_S_BATTERINGRAM && (_unitType != Map::Units::UT_S_SHIELD)))) && - ((_unitType != Map::Units::UT_S_BALLISTA && (_unitType != Map::Units::UT_S_FBALLISTA)))))) { - if (((((int)this->aics[_aiType - 1].DefDiggingUnitMax == 0) || - (_unitType == Map::Units::UT_E_ARCHER)) || (_unitType == Map::Units::UT_E_XBOW)) || - (_ptrUnit->someUnitStat4 == 0)) { + if ((((((_ptrUnit->logicalState != Map::Units::ULS_INVISIBLE) && (_ptrUnit->owner == playerID)) + && ((_ptrUnit->isSelectable_OR_matchTime != 0 + && ((_ptrUnit->aiUnitBehaviourType == 0 && (_ptrUnit->dying == 0)))))) + && (_unitType = _ptrUnit->unitType, _unitType != Map::Units::UT_LORD)) + && ((((_unitType != Map::Units::UT_E_ENGINEER && (_unitType != Map::Units::UT_TUNNELER)) + && (_unitType != Map::Units::UT_S_CATAPULT)) + && (( + _unitType != Map::Units::UT_S_TREBUCHET && (_unitType != Map::Units::UT_S_MANGONEL)))))) + && (( + (_unitType != Map::Units::UT_S_TOWER + && ((_unitType != Map::Units::UT_S_BATTERINGRAM && (_unitType != Map::Units::UT_S_SHIELD)))) + && ((_unitType != Map::Units::UT_S_BALLISTA && (_unitType != Map::Units::UT_S_FBALLISTA)))))) { + if (((((int)this->aics[_aiType - 1].DefDiggingUnitMax == 0) + || (_unitType == Map::Units::UT_E_ARCHER)) + || (_unitType == Map::Units::UT_E_XBOW)) + || (_ptrUnit->someUnitStat4 == 0)) { MACRO_CALL_MEMBER(AICState_Func::assignUnitToATribe, this)(_unitID); - } - else { + } else { MACRO_CALL_MEMBER(AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); } } diff --git a/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp index 22cda9ad7..cd5bb7b90 100644 --- a/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp @@ -1,11 +1,10 @@ #include "OpenSHC/AI/AICState.func.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp index 6057d9080..7001fe9cf 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp @@ -1,7 +1,6 @@ +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TroopValueState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -16,14 +15,17 @@ namespace AI { { int iVar1; int iVar2; - if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], iVar2 != 0)) && - (DAT_TribesState::instance.tribes[iVar2].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb])) && - (DAT_TribesState::instance.tribes[iVar2].selectionTargetUnitID != 0)) { + if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], iVar2 != 0)) + && (DAT_TribesState::instance.tribes[iVar2].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb])) + && (DAT_TribesState::instance.tribes[iVar2].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[iVar2].unitStance = Map::Units::Behavior::USE_STAND_GROUND; - iVar1 = MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)(iVar2); + iVar1 = MACRO_CALL_MEMBER( + Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)(iVar2); if (iVar1 == 0) { - MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)(iVar2); + MACRO_CALL_MEMBER( + Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)(iVar2); } } } diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp index 5f9524b07..c28d2776b 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -15,12 +14,14 @@ namespace AI { void AICState::aiCommandTribe13DefensiveWave(int param_1) { int tribeID; - if ((DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) && - (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xd], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xd]) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if ((DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xd], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xd]) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f4); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f4); } } } diff --git a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp index 55c81532f..fe11b9a93 100644 --- a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -22,11 +21,13 @@ namespace AI { psVar2 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + 0xbe; do { tribeID = (int)*psVar2; - if (((tribeID != 0) && - (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar1 + 0xbe])) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if (((tribeID != 0) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar1 + 0xbe])) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f2); } iVar1 = iVar1 + 1; psVar2 = psVar2 + 1; diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp index 75dc1e348..20b5496f0 100644 --- a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -1,11 +1,10 @@ #include "OpenSHC/AI/AICState.func.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" -#include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" namespace OpenSHC { @@ -31,45 +30,56 @@ namespace AI { _aicOffset = (_aiType + -1) * 0x2a4; _count = (int)this->aics[_aiType - 1].OuterPatrolGroupsCount; _index = 0; - if (((0 < _count) && - (piVar1 = &DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker, - *piVar1 = *piVar1 + 1, - (int)this->aics[_aiType - 1].OuterPatrolRallyDelay <= DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker)) && - (DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker = 0, 0 < _count)) { + if (((0 < _count) + && (piVar1 = &DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker, + *piVar1 = *piVar1 + 1, + (int)this->aics[_aiType - 1].OuterPatrolRallyDelay + <= DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker)) + && (DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker = 0, 0 < _count)) { psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; do { _tribeID = (int)*psVar4; DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - if (((_tribeID != 0) && - (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0xaa])) && - ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0xb && - ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk < 0xb && - (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk < 0xb)))))) { - if (((int)this->aics[_aiType - 1].OuterPatrolGroupsMove == 0) || - (_buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)(playerID, _index), - _buildingID == 0)) { - _buildingID2 = MACRO_CALL_MEMBER(AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); - if (_buildingID2 == 0) goto LAB_004d2a44; - _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryX + - DAT_ViewportRenderState::instance.translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryY].addXgetTile; - } - else { - _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + - DAT_ViewportRenderState::instance.translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryY].addXgetTile; + if (((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0xaa])) + && ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0xb + && ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk < 0xb + && (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk < 0xb)))))) { + if (((int)this->aics[_aiType - 1].OuterPatrolGroupsMove == 0) + || (_buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)( + playerID, _index), + _buildingID == 0)) { + _buildingID2 = MACRO_CALL_MEMBER( + AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + if (_buildingID2 == 0) + goto LAB_004d2a44; + _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID2] + .buildingEntryY] + .addXgetTile; + } else { + _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] + .buildingEntryY] + .addXgetTile; } if (_tile != 0) { sVar2 = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; iVar3 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; - _canNavigate = MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(_tribeID, _tile); + _canNavigate = MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( + _tribeID, _tile); if (_canNavigate == FALSE) { MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); - } - else { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(_tribeID, _tile - iVar3, (int)sVar2, 0); + } else { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, + DAT_TribesState::ptr)(_tribeID, _tile - iVar3, (int)sVar2, 0); } } } -LAB_004d2a44: + LAB_004d2a44: _index = _index + 1; psVar4 = psVar4 + 1; } while (_index < _count); diff --git a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp index 640f619e3..3c745352a 100644 --- a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp @@ -1,12 +1,11 @@ #include "OpenSHC/AI/AICState.func.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -18,11 +17,12 @@ namespace AI { if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { Map::Units::Unit* psVar1 = &DAT_UnitsState::instance.units[1]; do { - if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == param_1)) && - (psVar1->dying == 0)) && - ((psVar1->unitType == Map::Units::UT_TUNNELER && (psVar1->aiUnitBehaviourType == 0xf)))) { + if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == param_1)) + && (psVar1->dying == 0)) + && ((psVar1->unitType == Map::Units::UT_TUNNELER && (psVar1->aiUnitBehaviourType == 0xf)))) { if (psVar1->tribeID != 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)psVar1->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, (int)psVar1->tribeID); } MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 0xf); } diff --git a/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp index 7379a3ed6..c96ca96b9 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp @@ -1,20 +1,19 @@ +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" - -#include "OpenSHC/Global.func.hpp" -#include "OpenSHC/Map/Units/UnitsState.func.hpp" -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Map/Units/UnitInstructionType.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" -#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -28,31 +27,44 @@ namespace AI { int _amount; int _oilSmelter; int _buildingUID; - if (((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (_newTribe = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, - DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) && - (29 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf])) && - ((0 < _newTribe && (DAT_BuildingsState::instance.buildings[_newTribe].buildingType == Map::Buildings::BT_ENGINEERSGUILD)))) && - ((_oilSmelter = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id, 0 < _oilSmelter && - ((DAT_BuildingsState::instance.buildings[_oilSmelter].buildingType == Map::Buildings::BT_OILSMELTER && - (_amount = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1] + 1, 1 < _amount)))))) { - if ((DAT_BuildingsState::instance.buildings[_oilSmelter].resourcePitch < 1) && - (DAT_GameState::instance.playerDataArray[playerID].currentResources[7] < 1)) { + if (((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (_newTribe = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, + DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) + && (29 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf])) + && ((0 < _newTribe + && (DAT_BuildingsState::instance.buildings[_newTribe].buildingType + == Map::Buildings::BT_ENGINEERSGUILD)))) + && ((_oilSmelter = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id, + 0 < _oilSmelter + && ((DAT_BuildingsState::instance.buildings[_oilSmelter].buildingType + == Map::Buildings::BT_OILSMELTER + && (_amount + = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1] + 1, + 1 < _amount)))))) { + if ((DAT_BuildingsState::instance.buildings[_oilSmelter].resourcePitch < 1) + && (DAT_GameState::instance.playerDataArray[playerID].currentResources[7] < 1)) { DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[7] = 4; return; } - _hasTribes = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)(playerID, _amount, TRUE); + _hasTribes + = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)(playerID, _amount, TRUE); if (_hasTribes != FALSE) { - _newTribe = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)(playerID, _amount, FALSE); - _unitID = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)(Map::Units::UT_E_ENGINEER, DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, playerID, 0); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(_unitID, _newTribe); + _newTribe = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)( + playerID, _amount, FALSE); + _unitID = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + Map::Units::UT_E_ENGINEER, DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, + playerID, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + _unitID, _newTribe); if (_unitID != 0) { DAT_UnitsState::instance.units[_unitID].engineerRelatedUnk = 1; DAT_TribesState::instance.tribes[_newTribe].unitStance = Map::Units::Behavior::USE_DEFENSIVE; _buildingUID = DAT_BuildingsState::instance.buildings[_oilSmelter].uid; DAT_TribesState::instance.tribes[_newTribe].tribeType = Tribes::AITT_ENGINEERS; DAT_TribesState::instance.tribes[_newTribe].tribeBehaviorType = Map::Units::STBT_0x41d; - MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(_newTribe, Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _oilSmelter, _buildingUID, 0); + MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + _newTribe, Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _oilSmelter, + _buildingUID, 0); } } } diff --git a/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp b/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp index 7af062fb0..c42651eeb 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp @@ -1,12 +1,11 @@ +#include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/UnitsState.func.hpp" -#include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { @@ -17,14 +16,16 @@ namespace AI { { int recruitmentBuilding; int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if ((((_aiType != AITA_NULL) && - (DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired != FALSE)) && - (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) && - (((0x1d < (int)this->aics[_aiType - 1].recruitGoldThreshold + DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] && - (recruitmentBuilding = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, - 0 < recruitmentBuilding)) && - (DAT_BuildingsState::instance.buildings[recruitmentBuilding].buildingType == Map::Buildings::BT_ENGINEERSGUILD)))) { - MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)(Map::Units::UT_E_ENGINEER, recruitmentBuilding, playerID, 0); + if ((((_aiType != AITA_NULL) && (DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired != FALSE)) + && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) + && (((0x1d < (int)this->aics[_aiType - 1].recruitGoldThreshold + + DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] + && (recruitmentBuilding = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, + 0 < recruitmentBuilding)) + && (DAT_BuildingsState::instance.buildings[recruitmentBuilding].buildingType + == Map::Buildings::BT_ENGINEERSGUILD)))) { + MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + Map::Units::UT_E_ENGINEER, recruitmentBuilding, playerID, 0); DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = FALSE; } } diff --git a/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp index aeb6e8986..d1f3f4888 100644 --- a/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp +++ b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp @@ -1,13 +1,12 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Map/Units/States/UnitState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -16,7 +15,8 @@ namespace AI { int AICState::assignRequiredIdleEngineersToNewTribe(int playerID, int count) { Map::Units::States::UnitStateShort UVar1; - int tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + int tribeID + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); uint unitID = 1; if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { Map::Units::Unit* psVar2 = &DAT_UnitsState::instance.units[1]; @@ -24,15 +24,18 @@ namespace AI { if (count < 1) { return tribeID; } - if (((((psVar2->logicalState == Map::Units::ULS_NORMAL) && (psVar2->owner == playerID)) && - (psVar2->dying == 0)) && - ((psVar2->unitType == Map::Units::UT_E_ENGINEER && (psVar2->aiUnitBehaviourType != 0x16)))) && - ((psVar2->aiUnitBehaviourType != 10 && (psVar2->engineerRelatedUnk == 0))) && - (((UVar1 = (psVar2->state).generic, UVar1 == 0x69 || (UVar1 == 2)) || (UVar1 == Map::Units::States::US_IDLEUnk)))) { + if (((((psVar2->logicalState == Map::Units::ULS_NORMAL) && (psVar2->owner == playerID)) + && (psVar2->dying == 0)) + && ((psVar2->unitType == Map::Units::UT_E_ENGINEER && (psVar2->aiUnitBehaviourType != 0x16)))) + && ((psVar2->aiUnitBehaviourType != 10 && (psVar2->engineerRelatedUnk == 0))) + && (((UVar1 = (psVar2->state).generic, UVar1 == 0x69 || (UVar1 == 2)) + || (UVar1 == Map::Units::States::US_IDLEUnk)))) { if (psVar2->tribeID != 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)psVar2->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, (int)psVar2->tribeID); } - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, tribeID); count = count + -1; } unitID = unitID + 1; diff --git a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp index 383a4e51c..5cbcef48a 100644 --- a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp +++ b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp @@ -1,12 +1,11 @@ #include "OpenSHC/AI/AICState.func.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Global.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -20,21 +19,22 @@ namespace AI { int _playerID = (int)DAT_UnitsState::instance.units[unitID].owner; if (DAT_GameState::instance.playerDataArray[_playerID].aiType != AITA_NULL) { int iVar1; - if ((DAT_GameState::instance.playerDataArray[_playerID].aivCurrentPauseIndex == 1) && - (0 < DAT_GameState::instance.playerDataArray[_playerID].aivPauses[1])) { + if ((DAT_GameState::instance.playerDataArray[_playerID].aivCurrentPauseIndex == 1) + && (0 < DAT_GameState::instance.playerDataArray[_playerID].aivPauses[1])) { iVar1 = 1; - } - else { + } else { iVar1 = 0; } _unitTypeIndex = (short*)MACRO_CALL(Global_Func::GetUnitTypeIndexForUnitID)(unitID, iVar1); - int _tribeSize = DAT_GameState::instance.playerDataArray[_playerID].aivUnitLocationSlotLocationCount[(int)_unitTypeIndex]; + int _tribeSize = DAT_GameState::instance.playerDataArray[_playerID] + .aivUnitLocationSlotLocationCount[(int)_unitTypeIndex]; DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 1; if (_tribeSize < 1) { _isOfType = MACRO_CALL_MEMBER(AICState_Func::unitIDIsRangedOrArmored, this)(unitID); if (_isOfType != 0) { _tribeID = MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(_playerID, 0); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, _tribeID); return; } _tribeID = MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(_playerID, 1); diff --git a/src/OpenSHC/AI/AICState/buyGoods.cpp b/src/OpenSHC/AI/AICState/buyGoods.cpp index e79ac2405..288fea7b5 100644 --- a/src/OpenSHC/AI/AICState/buyGoods.cpp +++ b/src/OpenSHC/AI/AICState/buyGoods.cpp @@ -2,6 +2,7 @@ #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" diff --git a/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp index 8b18080b6..b68d96055 100644 --- a/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp +++ b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp @@ -1,10 +1,9 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_PathFindingState.hpp" -#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { @@ -13,11 +12,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CD250 BOOLEnum AICState::canNavigateUnitsFromTileToTargetTile(int tribeID, int tile) { - int iVar1 = MACRO_CALL_MEMBER(Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)( - DAT_TribesState::instance.tribes[tribeID].owner, - (int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID].tile], - (int)(short)DAT_TileMapState::instance.PathConnectionLayer[tile], - 0); + int iVar1 = MACRO_CALL_MEMBER( + Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[tribeID].owner, + (int)(short)DAT_TileMapState::instance.PathConnectionLayer + [DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID].tile], + (int)(short)DAT_TileMapState::instance.PathConnectionLayer[tile], 0); return (uint)(iVar1 != 0); } } diff --git a/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp b/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp index 11260ee9e..f161e8f1d 100644 --- a/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp +++ b/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp @@ -1,6 +1,5 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -13,9 +12,11 @@ namespace AI { { short* psVar1 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + unitSelectionTypeIndex; int _tribeID = (int)*psVar1; - if ((_tribeID == 0) || - (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex])) { - _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + if ((_tribeID == 0) + || (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex])) { + _tribeID + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; *psVar1 = (short)_tribeID; DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex] = _tribeUID; diff --git a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp index 88bab103f..55622a561 100644 --- a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp +++ b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp @@ -1,8 +1,7 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" -#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Buildings/BuildingLogicalState.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" @@ -20,79 +19,90 @@ namespace AI { if (1 < DAT_BuildingsState::instance.maxBuildingsCount) { Map::Buildings::Building* pBVar2 = &DAT_BuildingsState::instance.buildings[1]; do { - if (((pBVar2->logicalState != 0) && (pBVar2->logicalState != Map::Buildings::BLS_REMOVE)) && - (pBVar2->owner == playerID)) { + if (((pBVar2->logicalState != 0) && (pBVar2->logicalState != Map::Buildings::BLS_REMOVE)) + && (pBVar2->owner == playerID)) { if (buildingCategory == AINDBC_FEAR_FACTOR_BUILDINGS) { BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_CESSPIT) && (BVar1 != Map::Buildings::BT_BURNINGSTAKE)) && - (((BVar1 != Map::Buildings::BT_GIBBET && - (((BVar1 != Map::Buildings::BT_DUNGEON && (BVar1 != Map::Buildings::BT_STRETCHINGRACK)) && (BVar1 != Map::Buildings::BT_RACKFLOGGING)))) && - (((BVar1 != Map::Buildings::BT_CHOPPINGBLOCK && (BVar1 != Map::Buildings::BT_DUNKINGSTOOL)) && - ((BVar1 != Map::Buildings::BT_DOGCAGE && - (((BVar1 != Map::Buildings::BT_STATUE && (BVar1 != Map::Buildings::BT_SHRINE)) && - ((BVar1 != Map::Buildings::BT_DANCINGBEAR && - ((((BVar1 != Map::Buildings::BT_POND && (BVar1 != Map::Buildings::BT_GALLOWS)) && (BVar1 != Map::Buildings::BT_STOCKS)) && - ((BVar1 != Map::Buildings::BT_WITCHHOIST && (BVar1 != Map::Buildings::BT_MAYPOLE)))))))))))))))) { + if (((BVar1 != Map::Buildings::BT_CESSPIT) && (BVar1 != Map::Buildings::BT_BURNINGSTAKE)) + && (((BVar1 != Map::Buildings::BT_GIBBET + && (((BVar1 != Map::Buildings::BT_DUNGEON + && (BVar1 != Map::Buildings::BT_STRETCHINGRACK)) + && (BVar1 != Map::Buildings::BT_RACKFLOGGING)))) + && (((BVar1 != Map::Buildings::BT_CHOPPINGBLOCK + && (BVar1 != Map::Buildings::BT_DUNKINGSTOOL)) + && ((BVar1 != Map::Buildings::BT_DOGCAGE + && (( + (BVar1 != Map::Buildings::BT_STATUE && (BVar1 != Map::Buildings::BT_SHRINE)) + && ((BVar1 != Map::Buildings::BT_DANCINGBEAR + && ((((BVar1 != Map::Buildings::BT_POND + && (BVar1 != Map::Buildings::BT_GALLOWS)) + && (BVar1 != Map::Buildings::BT_STOCKS)) + && ((BVar1 != Map::Buildings::BT_WITCHHOIST + && (BVar1 != Map::Buildings::BT_MAYPOLE)))))))))))))))) { bVar2 = BVar1 == Map::Buildings::BT_GARDEN; goto LAB_004d04de; } - } - else if (buildingCategory == AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS) { + } else if (buildingCategory == AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS) { BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_FLETCHER) && (BVar1 != Map::Buildings::BT_BLACKSMITH)) && - (((BVar1 != Map::Buildings::BT_POLETURNER && - (((BVar1 != Map::Buildings::BT_ARMOURER && (BVar1 != Map::Buildings::BT_TANNER)) && (BVar1 != Map::Buildings::BT_INN)))) && - (((BVar1 != Map::Buildings::BT_APOTHECARY && (BVar1 != Map::Buildings::BT_CHAPEL)) && (BVar1 != Map::Buildings::BT_CHURCH)))))) { + if (((BVar1 != Map::Buildings::BT_FLETCHER) && (BVar1 != Map::Buildings::BT_BLACKSMITH)) + && (((BVar1 != Map::Buildings::BT_POLETURNER + && (((BVar1 != Map::Buildings::BT_ARMOURER && (BVar1 != Map::Buildings::BT_TANNER)) + && (BVar1 != Map::Buildings::BT_INN)))) + && (((BVar1 != Map::Buildings::BT_APOTHECARY && (BVar1 != Map::Buildings::BT_CHAPEL)) + && (BVar1 != Map::Buildings::BT_CHURCH)))))) { bVar2 = BVar1 == Map::Buildings::BT_CATHEDRAL; goto LAB_004d04de; } - } - else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) { + } else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) { BVar1 = pBVar2->buildingType; - if (((((BVar1 != Map::Buildings::BT_GATEHOUSELARGE) && (BVar1 != Map::Buildings::BT_GATEHOUSESMALL)) && - ((BVar1 != Map::Buildings::BT_DRAWBRIDGE && - ((((BVar1 != Map::Buildings::BT_TOWER1 && (BVar1 != Map::Buildings::BT_TOWER2)) && (BVar1 != Map::Buildings::BT_TOWER3)) && - ((BVar1 != Map::Buildings::BT_TOWER4 && (BVar1 != Map::Buildings::BT_TOWER5)))))))) && (BVar1 != Map::Buildings::BT_ENGINEERSGUILD)) && - (BVar1 != Map::Buildings::BT_TUNNELERSGUILD)) { + if (((((BVar1 != Map::Buildings::BT_GATEHOUSELARGE) + && (BVar1 != Map::Buildings::BT_GATEHOUSESMALL)) + && ((BVar1 != Map::Buildings::BT_DRAWBRIDGE + && ((((BVar1 != Map::Buildings::BT_TOWER1 && (BVar1 != Map::Buildings::BT_TOWER2)) + && (BVar1 != Map::Buildings::BT_TOWER3)) + && ((BVar1 != Map::Buildings::BT_TOWER4 + && (BVar1 != Map::Buildings::BT_TOWER5)))))))) + && (BVar1 != Map::Buildings::BT_ENGINEERSGUILD)) + && (BVar1 != Map::Buildings::BT_TUNNELERSGUILD)) { bVar2 = BVar1 == Map::Buildings::BT_OILSMELTER; goto LAB_004d04de; } - } - else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) { + } else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) { BVar1 = pBVar2->buildingType; if ((BVar1 != Map::Buildings::BT_MERCENARYPOST) && (BVar1 != Map::Buildings::BT_BARRACKS)) { bVar2 = BVar1 == Map::Buildings::BT_STABLES; goto LAB_004d04de; } - } - else if (buildingCategory == AINDBC_WATER_BUILDINGS) { + } else if (buildingCategory == AINDBC_WATER_BUILDINGS) { if (pBVar2->buildingType != Map::Buildings::BT_WELL) { bVar2 = pBVar2->buildingType == Map::Buildings::BT_WATERPOT; goto LAB_004d04de; } - } - else if (buildingCategory == AINDBC_RESOURCE_BUILDINGS) { + } else if (buildingCategory == AINDBC_RESOURCE_BUILDINGS) { BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_OXTETHER) && (BVar1 != Map::Buildings::BT_IRONMINE)) && - ((BVar1 != Map::Buildings::BT_PITCHRIG && - (((BVar1 != Map::Buildings::BT_BAKERY && (BVar1 != Map::Buildings::BT_BREWERY)) && (BVar1 != Map::Buildings::BT_QUARRY)))))) { + if (((BVar1 != Map::Buildings::BT_OXTETHER) && (BVar1 != Map::Buildings::BT_IRONMINE)) + && ((BVar1 != Map::Buildings::BT_PITCHRIG + && (((BVar1 != Map::Buildings::BT_BAKERY && (BVar1 != Map::Buildings::BT_BREWERY)) + && (BVar1 != Map::Buildings::BT_QUARRY)))))) { bVar2 = BVar1 == Map::Buildings::BT_MILL; -LAB_004d04de: - if (!bVar2) goto LAB_004d04f9; + LAB_004d04de: + if (!bVar2) + goto LAB_004d04f9; } - } - else { - if (((buildingCategory == AINDBC_FARMS) && - (BVar1 = pBVar2->buildingType, BVar1 != Map::Buildings::BT_WHEATFARM)) && - ((BVar1 != Map::Buildings::BT_HOPFARM && (BVar1 != Map::Buildings::BT_APPLEFARM)))) { + } else { + if (((buildingCategory == AINDBC_FARMS) + && (BVar1 = pBVar2->buildingType, BVar1 != Map::Buildings::BT_WHEATFARM)) + && ((BVar1 != Map::Buildings::BT_HOPFARM && (BVar1 != Map::Buildings::BT_APPLEFARM)))) { bVar2 = BVar1 == Map::Buildings::BT_DAIRYFARM; goto LAB_004d04de; } } - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_buildingID); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( + _buildingID); } -LAB_004d04f9: + LAB_004d04f9: _buildingID = _buildingID + 1; pBVar2 = pBVar2 + 1; } while (_buildingID < DAT_BuildingsState::instance.maxBuildingsCount); diff --git a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp index 97c182d7a..85d25c03d 100644 --- a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp +++ b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp @@ -1,13 +1,12 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/AI/AIVState.func.hpp" #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Globals/DAT_AIVState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" -#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" namespace OpenSHC { namespace AI { @@ -17,20 +16,21 @@ namespace AI { { short _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; int _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; - if ((((0 < _value) && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1)) && - (DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0)) && - (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY)) { + if ((((0 < _value) && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1)) + && (DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0)) + && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY)) { if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] == 0) { if (0x13 < _value) { MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(buildingID); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( + buildingID); return 1; } - } - else if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { + } else if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = _value + -1; } } diff --git a/src/OpenSHC/AI/AICState/digNearestMoat.cpp b/src/OpenSHC/AI/AICState/digNearestMoat.cpp index c734a3ff9..9187b70c5 100644 --- a/src/OpenSHC/AI/AICState/digNearestMoat.cpp +++ b/src/OpenSHC/AI/AICState/digNearestMoat.cpp @@ -1,13 +1,12 @@ #include "OpenSHC/AI/AICState.func.hpp" - +#include "OpenSHC/Map/TileMapState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/UnitInstructionType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" -#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { @@ -19,22 +18,29 @@ namespace AI { int iVar1; BOOLEnum tile; int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10]; - if ((((tribeID != 0) && - (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10])) && - (0 < DAT_TribesState::instance.tribes[tribeID].size)) && - (DAT_TribesState::instance.tribes[tribeID].percentageSomething < 0x51)) { - iVar1 = MACRO_CALL_MEMBER(Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)(playerID); + if ((((tribeID != 0) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10])) + && (0 < DAT_TribesState::instance.tribes[tribeID].size)) + && (DAT_TribesState::instance.tribes[tribeID].percentageSomething < 0x51)) { + iVar1 = MACRO_CALL_MEMBER(Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)( + playerID); if (iVar1 < 1) { MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); return; } iVar1 = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; - tile = MACRO_CALL_MEMBER(Map::TileMapState_Func::findNearestFriendlyMoatTileForDigging, DAT_TileMapState::ptr)(playerID, iVar1, 1); + tile = MACRO_CALL_MEMBER(Map::TileMapState_Func::findNearestFriendlyMoatTileForDigging, + DAT_TileMapState::ptr)(playerID, iVar1, 1); if (-1 < (int)tile) { - MACRO_CALL_MEMBER(Map::TileMapState_Func::setXYBasedOnMoatID, DAT_TileMapState::ptr)(tile, 1, (int)DAT_UnitsState::instance.units[iVar1].x, (int)DAT_UnitsState::instance.units[iVar1].y); - iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::updateTribeRallyFlags, DAT_TribesState::ptr)(tribeID); + MACRO_CALL_MEMBER(Map::TileMapState_Func::setXYBasedOnMoatID, DAT_TileMapState::ptr)(tile, 1, + (int)DAT_UnitsState::instance.units[iVar1].x, (int)DAT_UnitsState::instance.units[iVar1].y); + iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::updateTribeRallyFlags, DAT_TribesState::ptr)( + tribeID); if (iVar1 == 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(tribeID, Map::Units::UIT_DIG_MOAT, DAT_TileMapState::instance.ALG_MoatXResult, DAT_TileMapState::instance.ALG_MoatYResult, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( + tribeID, Map::Units::UIT_DIG_MOAT, DAT_TileMapState::instance.ALG_MoatXResult, + DAT_TileMapState::instance.ALG_MoatYResult, 0); DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_STAND_GROUND; } } diff --git a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp index 7aaa535d8..0007cf995 100644 --- a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp +++ b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp @@ -1,12 +1,11 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" -#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" namespace OpenSHC { namespace AI { @@ -18,26 +17,27 @@ namespace AI { int _unitType = (int)(short)DAT_UnitsState::instance.units[unitID].unitType; int _unitType2; do { - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index]) || - (_unitType2 = (int)(short)DAT_UnitsState::instance.units[unitID].unitTypeToChangeInto, - _unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index])) break; - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1]) || - (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1])) { + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index]) + || (_unitType2 = (int)(short)DAT_UnitsState::instance.units[unitID].unitTypeToChangeInto, + _unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index])) + break; + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1]) + || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1])) { _index = _index + 1; break; } - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2]) || - (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2])) { + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2]) + || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2])) { _index = _index + 2; break; } - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3]) || - (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3])) { + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3]) + || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3])) { _index = _index + 3; break; } - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4]) || - (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4])) { + if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4]) + || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4])) { _index = _index + 4; break; } @@ -46,20 +46,15 @@ namespace AI { int _tribeIndex; if (_index < 1) { _tribeIndex = 0xb4; - } - else if (_index < 2) { + } else if (_index < 2) { _tribeIndex = 0xb5; - } - else if (_index < 7) { + } else if (_index < 7) { _tribeIndex = 0xb6; - } - else if (_index < 0xc) { + } else if (_index < 0xc) { _tribeIndex = 0xb7; - } - else if (_index < 0xf) { + } else if (_index < 0xf) { _tribeIndex = 0xb8; - } - else { + } else { if (19 < _index) { return 0; } @@ -67,9 +62,11 @@ namespace AI { } short* _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeIndex; int _tribeID = (int)*_pTribeID; - if ((_tribeID == 0) || - (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex])) { - _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + if ((_tribeID == 0) + || (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex])) { + _tribeID + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; *_pTribeID = (short)_tribeID; DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex] = _tribeUID; diff --git a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp index b4f0895ac..32fca0836 100644 --- a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp +++ b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp @@ -16,37 +16,33 @@ namespace AI { int _totalBackupLate; int _totalBackupLate2; - _total1 = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + - DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + - DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops; + _total1 = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + + DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops; _halfOfDiggingTroops = 0; if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState == 6) { if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 17) { _totalBackup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - } - else { + } else { _totalBackupLate = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; _totalBackup = (int)(_totalBackupLate + (_totalBackupLate >> 0x1f & 7U)) >> 3; } - _totalTroops = _total1 + DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops + - _totalBackup + - DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + - DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + - DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; - } - else { + _totalTroops = _total1 + DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops + + _totalBackup + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + } else { _halfOfDiggingTroops = DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops / 2; if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 13) { _totalBackup2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - } - else { + } else { _totalBackupLate2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; _totalBackup2 = (int)(_totalBackupLate2 + (_totalBackupLate2 >> 0x1f & 7U)) >> 3; } - _totalTroops = _total1 + _totalBackup2 + - DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + - DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + - DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + _totalTroops = _total1 + _totalBackup2 + + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; } if ((1 < _totalTroops) && ((4 < _totalTroops || (_halfOfDiggingTroops <= _totalTroops * 2)))) { return FALSE; diff --git a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp index 0f772a912..8a56546ea 100644 --- a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp +++ b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp @@ -1,7 +1,7 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { @@ -10,15 +10,17 @@ namespace AI { BOOLEnum AICState::hasNotEnoughSupplies(int playerID) { BOOLEnum BVar1 = TRUE; - if (((((DAT_GameState::instance.playerDataArray[playerID].marketplace.id != 0) || - (DAT_BuildingsState::instance.buildingCosts[0x1a].requiredWood <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) || - (0 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)) && - (((DAT_GameState::instance.playerDataArray[playerID].granary.id != 0 || - (DAT_BuildingsState::instance.buildingCosts[0x13].requiredWood <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) || - (1 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)))) && - (((0 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] || - (25 < DAT_GameState::instance.playerDataArray[playerID].popularity)) || - (0 < DAT_GameState::instance.playerDataArray[playerID].totalFood)))) { + if (((((DAT_GameState::instance.playerDataArray[playerID].marketplace.id != 0) + || (DAT_BuildingsState::instance.buildingCosts[0x1a].requiredWood + <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) + || (0 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)) + && (((DAT_GameState::instance.playerDataArray[playerID].granary.id != 0 + || (DAT_BuildingsState::instance.buildingCosts[0x13].requiredWood + <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) + || (1 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)))) + && (((0 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] + || (25 < DAT_GameState::instance.playerDataArray[playerID].popularity)) + || (0 < DAT_GameState::instance.playerDataArray[playerID].totalFood)))) { BVar1 = FALSE; } return BVar1; diff --git a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp index fb68e2842..b118a2cce 100644 --- a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp +++ b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp @@ -10,8 +10,9 @@ namespace AI { void AICState::ifHasTribe0SendUnitsToKeep(int playerID) { int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0]; - if ((0 < tribeID) && - (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0])) { + if ((0 < tribeID) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0])) { MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); } } diff --git a/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp b/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp index 6dd67d991..9b2058928 100644 --- a/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp +++ b/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp @@ -1,6 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Game/Resources/ResourceType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -9,7 +8,8 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0520 - BOOLEnum AICState::isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade(int playerID, ResourceType resourceType, int buffer) + BOOLEnum AICState::isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade( + int playerID, ResourceType resourceType, int buffer) { int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (_aiType == AITA_NULL) { @@ -18,7 +18,8 @@ namespace AI { if (resourceType == Game::Resources::RT_GOLD) { return FALSE; } - return (int)this->aics[_aiType - 1].minimumGoodsRequiredAfterTrade + buffer <= DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType]; + return (int)this->aics[_aiType - 1].minimumGoodsRequiredAfterTrade + buffer + <= DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType]; } } } diff --git a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp index 4f4662e1d..d544ada7d 100644 --- a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -15,15 +14,21 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0830 void AICState::playAnger1BikFromPlayer(int playerID) { - int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar2 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar2 != 0) { int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] != DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) && - (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { + if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] + != DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) + && (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID + == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { DWORD DVar3 = timeGetTime(); - if ((INT_ARRAY_00eb0af0::instance[playerID] == 0) || (599999 < DVar3 - INT_ARRAY_00eb0af0::instance[playerID])) { + if ((INT_ARRAY_00eb0af0::instance[playerID] == 0) + || (599999 < DVar3 - INT_ARRAY_00eb0af0::instance[playerID])) { INT_ARRAY_00eb0af0::instance[playerID] = DVar3; - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 5); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, + DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 5); } } } diff --git a/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp index b235964f5..dbef793fc 100644 --- a/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp @@ -1,8 +1,7 @@ -#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -16,12 +15,14 @@ namespace AI { void AICState::playAnger2BikFromPlayerToPlayer(int playerID, int targetPlayerID) { if (DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); bool bVar2; - if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 == 0)) && - (bVar2 = targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, - DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 = 0x60, bVar2)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 6); + if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 == 0)) + && (bVar2 = targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, + DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 = 0x60, bVar2)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 6); } } } diff --git a/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp index 2d99ef4d8..ea8497a85 100644 --- a/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -13,9 +12,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0FC0 void AICState::playFriendlyVictoryBikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 10); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 10); } } } diff --git a/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp index d3d56f13d..62fd7fb60 100644 --- a/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -13,9 +12,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0B70 void AICState::playGoodsNotSentBikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1c); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1c); } } } diff --git a/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp index 8aec4a1c2..484a7fbbb 100644 --- a/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -14,9 +13,14 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0A20 void AICState::playGoodsRequestBikFromPlayerToPlayer(int playerID, int targetPlayerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) && (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID].lordKilledByPlayerID == 0)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0xe); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) + && (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .lordKilledByPlayerID + == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0xe); } } } diff --git a/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp index fbab88edc..b9afb8833 100644 --- a/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -14,9 +13,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0BB0 void AICState::playGoodsSentBikFromPlayerToPlayer(int playerID, int targetPlayerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if ((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1d); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1d); } } } diff --git a/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp b/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp index b976cc78c..e6528e25b 100644 --- a/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp +++ b/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_VideoBikQueue.hpp" @@ -12,9 +11,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0F90 void AICState::playJokeBikFromAIToHuman(int playerID, int aiType) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, aiType, 0x14); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, aiType, 0x14); } } } diff --git a/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp index 28e61efb1..93c274c9b 100644 --- a/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -13,10 +12,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0CF0 void AICState::playNervous1BikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if ((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 == 0)) { DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 = 0x30; - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 8); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 8); } } } diff --git a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp index 4d3b6da36..a2b044f24 100644 --- a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -14,13 +13,16 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0B10 void AICState::playNervous2BikFromPlayer(int playerID) { - int iVar3 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar3 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); int iVar2 = DAT_GameSynchronyState::instance.currentPlayerSlotID; if ((iVar3 != 0) && (DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown == 0)) { int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown = 48; - if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] != DAT_GameState::instance.mapAndTime.playerTeams[iVar2]) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 9); + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] + != DAT_GameState::instance.mapAndTime.playerTeams[iVar2]) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, AVar1 - 1, 9); } } } diff --git a/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp index d8ca73671..2a4c11018 100644 --- a/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -13,9 +12,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D1050 void AICState::playNoHelpBikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1f); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1f); } } } diff --git a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp index b9bf203fe..a0679b77a 100644 --- a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp @@ -1,8 +1,7 @@ -#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -15,41 +14,57 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D08B0 void AICState::playPlayerKilledBiksFromKilledAndKillerPlayer(int killerPlayerID, int killedPlayerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(killerPlayerID); + int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + killerPlayerID); if (iVar1 != 0) { if (killedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { iVar1 = 0xc; - } - else { + } else { if (killerPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER( + Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); int i = 1; do { - if ((DAT_GameState::instance.playerDataArray[i].aiType != AITA_NULL) && - (DAT_GameState::instance.mapAndTime.playerTeams[i] == DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { - int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i); + if ((DAT_GameState::instance.playerDataArray[i].aiType != AITA_NULL) + && (DAT_GameState::instance.mapAndTime.playerTeams[i] + == DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + int iVar2 = MACRO_CALL_MEMBER( + Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i); if (iVar2 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(i, (int)DAT_GameState::instance.playerDataArray[i].aiType - 1, 0x11); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, + DAT_VideoBikQueue::ptr)( + i, (int)DAT_GameState::instance.playerDataArray[i].aiType - 1, 0x11); } } i = i + 1; } while (i < 9); return; } - iVar1 = DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]; + iVar1 = DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]; if (iVar1 == DAT_GameState::instance.mapAndTime.playerTeams[killedPlayerID]) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 0x10); + MACRO_CALL_MEMBER( + Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 0x10); return; } if (DAT_GameState::instance.mapAndTime.playerTeams[killerPlayerID] == iVar1) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 0x12); + MACRO_CALL_MEMBER( + Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER( + Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 0x12); return; } - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); iVar1 = 0xd; } - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, iVar1); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, iVar1); } } } diff --git a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp index 1dc39d4bf..fc2a1bac2 100644 --- a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -14,12 +13,16 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0D40 void AICState::playRequestHelpBikFromPlayer(int playerID) { - int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar2 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); int iVar1 = DAT_GameSynchronyState::instance.currentPlayerSlotID; if ((iVar2 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 == 0)) { DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 = 0x30; - if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[iVar1]) && (DAT_GameState::instance.playerDataArray[iVar1].lordKilledByPlayerID == 0)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x13); + if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] + == DAT_GameState::instance.mapAndTime.playerTeams[iVar1]) + && (DAT_GameState::instance.playerDataArray[iVar1].lordKilledByPlayerID == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x13); } } } diff --git a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp index 89cacc944..e95658878 100644 --- a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -15,17 +14,22 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D07C0 void AICState::playTauntToAttackedPlayerBikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { iVar1 = 0; - if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] + == DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { iVar1 = 0x17; } - if (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID + == DAT_GameSynchronyState::instance.currentPlayerSlotID) { if (iVar1 == 0) { iVar1 = ((byte)SEC_RNG::instance.currentNumber2 & 3) + 1; } - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, iVar1); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, iVar1); } } } diff --git a/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp index e27c7b599..02745d879 100644 --- a/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -13,9 +12,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D1000 void AICState::playTeamWinningBikFromPlayer(int playerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker == 0)) && (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker == 0)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1e); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker == 0)) + && (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker == 0)) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1e); } } } diff --git a/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp index e216c8c1f..110bb9381 100644 --- a/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -16,15 +15,20 @@ namespace AI { void AICState::playThanksBikFromPlayerToPlayer(int playerID, int targetPlayerID) { DWORD DVar2; - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + int iVar1 + = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { iVar1 = (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1; DAT_GameState::instance.playerDataArray[playerID].aiRequestDelay = this->aics[iVar1].aiRequestDelay; - if (((targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) && - (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID].lordKilledByPlayerID == 0)) && - ((DVar2 = timeGetTime(), DWORD_00eb0b18::instance == 0 || (1199999 < DVar2 - DWORD_00eb0b18::instance)))) { + if (((targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) + && (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .lordKilledByPlayerID + == 0)) + && ((DVar2 = timeGetTime(), + DWORD_00eb0b18::instance == 0 || (1199999 < DVar2 - DWORD_00eb0b18::instance)))) { DWORD_00eb0b18::instance = DVar2; - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(playerID, iVar1, 0xf); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, iVar1, 0xf); } } } diff --git a/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp index 5fb4e29cf..97437bc36 100644 --- a/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp @@ -1,8 +1,7 @@ -#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Rendering/Bink/AIMessageQueue.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -17,14 +16,18 @@ namespace AI { { int iVar1; bool bVar2; - if ((((DAT_GameState::instance.playerDataArray[targetPlayerID].aiType != AITA_NULL) && - (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] != -1)) && - (iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(targetPlayerID), iVar1 != 0)) && - (((iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID), iVar1 != 0 && - (DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 == 0)) && - (bVar2 = playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, - DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 = 0x30, bVar2)))) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)(targetPlayerID, (int)DAT_GameState::instance.playerDataArray[targetPlayerID].aiType - 1, 0xb); + if ((((DAT_GameState::instance.playerDataArray[targetPlayerID].aiType != AITA_NULL) + && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] != -1)) + && (iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + targetPlayerID), + iVar1 != 0)) + && (((iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + playerID), + iVar1 != 0 && (DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 == 0)) + && (bVar2 = playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, + DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 = 0x30, bVar2)))) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + targetPlayerID, (int)DAT_GameState::instance.playerDataArray[targetPlayerID].aiType - 1, 0xb); } } } diff --git a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp index ad2cf43b2..a733ce5f7 100644 --- a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp +++ b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp @@ -11,8 +11,9 @@ namespace AI { { if (0 < DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops) { int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; - if ((_tribeID != 0) && - (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12] = 0; } MACRO_CALL_MEMBER(AICState_Func::addEngineersToTribe, this)(playerID); diff --git a/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp b/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp index e39cd8bcd..791472b60 100644 --- a/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp +++ b/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp @@ -1,7 +1,6 @@ +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TroopValueState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -16,12 +15,14 @@ namespace AI { { int _tribeID; /* bug: only sends 0xf, while 0xf+1 could also be send if defined by 'AIC: AttUnitPatrolGroupsCount' */ - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (_tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xf], _tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xf]) && - (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (_tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xf], _tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xf]) + && (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; - MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::sendAttackingPatrolTribeToComputedDestination, DAT_TroopValueState::ptr)(_tribeID); + MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::sendAttackingPatrolTribeToComputedDestination, + DAT_TroopValueState::ptr)(_tribeID); return; } } diff --git a/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp index d54d90ecd..f595abbde 100644 --- a/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp @@ -10,8 +10,9 @@ namespace AI { void AICState::sendTribeAtOffset1ToCampfire(int playerID) { int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[1]; - if ((0 < _tribeID) && - (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[1])) { + if ((0 < _tribeID) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[1])) { MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); } } diff --git a/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp b/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp index 70816a822..86bc99714 100644 --- a/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -15,12 +14,14 @@ namespace AI { void AICState::sendTribeToAttack(int playerID) { int tribeID; - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbd], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbd]) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbd], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbd]) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3fb); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3fb); } } } diff --git a/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp b/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp index 3438b8701..b81436f3d 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp @@ -1,6 +1,5 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -13,7 +12,9 @@ namespace AI { void AICState::sendUnitsToCampfire(int tribeID, int playerID) { if (0 < DAT_GameState::instance.playerDataArray[playerID].campground.id) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, DAT_GameState::instance.playerDataArray[playerID].campground.xEntry, DAT_GameState::instance.playerDataArray[playerID].campground.yEntry, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, + DAT_GameState::instance.playerDataArray[playerID].campground.xEntry, + DAT_GameState::instance.playerDataArray[playerID].campground.yEntry, 0); DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; } } diff --git a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp index 79a4d2d29..8b0339efc 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp @@ -1,9 +1,8 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" namespace OpenSHC { @@ -14,7 +13,9 @@ namespace AI { { int iVar1 = DAT_GameState::instance.playerDataArray[playerID].keep.id; if (0 < iVar1) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, (int)(short)DAT_BuildingsState::instance.buildings[iVar1].x + 3, (int)(short)DAT_BuildingsState::instance.buildings[iVar1].y + 4, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, + (int)(short)DAT_BuildingsState::instance.buildings[iVar1].x + 3, + (int)(short)DAT_BuildingsState::instance.buildings[iVar1].y + 4, 0); } } } diff --git a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp index 172e3b81c..0689b2419 100644 --- a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp +++ b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp @@ -1,9 +1,9 @@ #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_TroopValueState.hpp" -#include "OpenSHC/Globals/DAT_TileMapState.hpp" #include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" namespace OpenSHC { namespace AI { @@ -12,11 +12,16 @@ namespace AI { void AICState::setAttackPrimeInfo(int playerID, int attackedPlayerID) { int _tile = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile; - DAT_TroopValueState::instance.attackInfo.startCon = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; + DAT_TroopValueState::instance.attackInfo.startCon + = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; DAT_TroopValueState::instance.attackInfo.startZone = (int)(char)DAT_TileMapState::instance.AIZoneLayer[_tile]; - DAT_TroopValueState::instance.attackInfo.zoneSize = DAT_PathFindingState::instance.zoneSizesArray[(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]]; + DAT_TroopValueState::instance.attackInfo.zoneSize + = DAT_PathFindingState::instance + .zoneSizesArray[(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]]; DAT_TroopValueState::instance.attackInfo.unknownOne_0x20f90 = 1; - DAT_TroopValueState::instance.attackInfo.keepCon = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry]; + DAT_TroopValueState::instance.attackInfo.keepCon + = (int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry]; } } } diff --git a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp index 16bce6ec3..772489730 100644 --- a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp +++ b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -22,11 +21,13 @@ namespace AI { psVar2 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xc0; do { _tribeID = (int)*psVar2; - if (((_tribeID != 0) && - (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar1 + 0xc0])) && - (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { + if (((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar1 + 0xc0])) + && (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(_tribeID, Map::Units::STBT_0x3f2); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + _tribeID, Map::Units::STBT_0x3f2); } iVar1 = iVar1 + 1; psVar2 = psVar2 + 1; diff --git a/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp b/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp index c92c7b451..b44d4a6c2 100644 --- a/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp +++ b/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -16,13 +15,15 @@ namespace AI { void AICState::setTribe0x11ToAggressiveAndAttackIfConditionMet(int param_1) { int tribeID; - if (((0 < *(int*)((int)DAT_TroopValueState::instance.attackInfo.moatValuesArray + param_1 * 0x177bc + -4)) && - (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL)) && - (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0x11], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0x11]) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if (((0 < *(int*)((int)DAT_TroopValueState::instance.attackInfo.moatValuesArray + param_1 * 0x177bc + -4)) + && (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL)) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0x11], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0x11]) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f7); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f7); } } } diff --git a/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp index 45520c9d5..2290c59f5 100644 --- a/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp +++ b/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -15,12 +14,14 @@ namespace AI { void AICState::setTribe0xCtoAggressiveAndAttack(int playerID) { int tribeID; - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xc], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xc]) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xc], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xc]) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f2); } } } diff --git a/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp index 259138f45..87e451e47 100644 --- a/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp +++ b/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp @@ -1,9 +1,8 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" - -#include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" @@ -15,12 +14,14 @@ namespace AI { void AICState::setTribe0xbToAggressiveAndAttack(int playerID) { int tribeID; - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) && - (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb]) && - (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], tribeID != 0)) { + if ((DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb]) + && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(tribeID, Map::Units::STBT_0x3f2); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f2); } } } diff --git a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp index 68feb468c..d374436ea 100644 --- a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp +++ b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp @@ -1,13 +1,12 @@ -#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/AI/AITypeA.hpp" - #include "OpenSHC/AI/AIVState.func.hpp" #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { @@ -20,9 +19,9 @@ namespace AI { return FALSE; } if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 1) { - _hut = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT); - } - else { + _hut = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT); + } else { if (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] < 0x15) { return FALSE; } @@ -37,8 +36,11 @@ namespace AI { if (_hut == 0) { return FALSE; } - MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)((int)(short)DAT_BuildingsState::instance.buildings[_hut].x, (int)(short)DAT_BuildingsState::instance.buildings[_hut].y); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(_hut, playerID, 50); + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + (int)(short)DAT_BuildingsState::instance.buildings[_hut].x, + (int)(short)DAT_BuildingsState::instance.buildings[_hut].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(_hut, playerID, 50); MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hut); return TRUE; } diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp index 3a98835e1..52613f2ef 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp @@ -1,5 +1,4 @@ #include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Commands/CommandBuildingType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -8,14 +7,17 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB9F0 - BOOLEnum AICState::shouldNotBuildMarketArmoryGranaryBarracksMercenarypost(int playerID, Commands::CommandBuildingType param_2) + BOOLEnum AICState::shouldNotBuildMarketArmoryGranaryBarracksMercenarypost( + int playerID, Commands::CommandBuildingType param_2) { if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) { - if ((0 < DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker) && (param_2 != Commands::CBT_MARKETPLACE)) { + if ((0 < DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker) + && (param_2 != Commands::CBT_MARKETPLACE)) { return param_2 != Commands::CBT_GRANARY; } - } - else if ((((param_2 != Commands::CBT_MARKETPLACE) && (param_2 != Commands::CBT_MERCENARYPOST)) && (param_2 != Commands::CBT_BARRACKS)) && (param_2 != Commands::CBT_ARMORY)) { + } else if ((((param_2 != Commands::CBT_MARKETPLACE) && (param_2 != Commands::CBT_MERCENARYPOST)) + && (param_2 != Commands::CBT_BARRACKS)) + && (param_2 != Commands::CBT_ARMORY)) { return param_2 != Commands::CBT_GRANARY; } return FALSE; diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp index b1b870c29..a7b0d34e6 100644 --- a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -1,11 +1,10 @@ +#include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" -#include "OpenSHC/Map/Units/TribesState.func.hpp" - #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" namespace OpenSHC { namespace AI { @@ -23,8 +22,8 @@ namespace AI { int _tribeID = 0; int local_c = 0; short sVar4 = 1000; - if ((iVar3 < iVar6) && - (((unitType == (short*)0x8 || (unitType == (short*)0xa)) || (unitType == (short*)0x11)))) { + if ((iVar3 < iVar6) + && (((unitType == (short*)0x8 || (unitType == (short*)0xa)) || (unitType == (short*)0x11)))) { iVar6 = iVar3; } iVar3 = DAT_SkirmishDefinedData::instance.DAT_AiTribeIDOffsetForUnitType[(int)unitType]; @@ -32,9 +31,11 @@ namespace AI { unitType = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar3; do { int iVar5 = (int)*unitType; - if ((iVar5 == 0) || - (DAT_TribesState::instance.tribes[iVar5].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7])) { - _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + if ((iVar5 == 0) + || (DAT_TribesState::instance.tribes[iVar5].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7])) { + _tribeID = MACRO_CALL_MEMBER( + Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); goto LAB_004ccaae; } short sVar1 = DAT_TribesState::instance.tribes[iVar5].size; @@ -48,9 +49,10 @@ namespace AI { } while (iVar7 < iVar6); iVar7 = local_c; if (_tribeID != 0) { -LAB_004ccaae: + LAB_004ccaae: DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[iVar3 + iVar7] = (short)_tribeID; - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] = DAT_TribesState::instance.tribes[_tribeID].uid; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] + = DAT_TribesState::instance.tribes[_tribeID].uid; return _tribeID; } } diff --git a/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp b/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp index 45d773b2c..7cfb1dbdf 100644 --- a/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp +++ b/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp @@ -1,11 +1,10 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" -#include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { @@ -18,12 +17,15 @@ namespace AI { if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { Map::Units::Unit* pUVar1 = &DAT_UnitsState::instance.units[1]; do { - if ((((pUVar1->owner == param_1) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) && - (pUVar1->dying == 0)) && (pUVar1->aiUnitBehaviourType == 7)) { + if ((((pUVar1->owner == param_1) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) + && (pUVar1->dying == 0)) + && (pUVar1->aiUnitBehaviourType == 7)) { tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xa7]; if (pUVar1->tribeID != tribeID) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)(unitID, (int)pUVar1->tribeID); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, (int)pUVar1->tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, tribeID); } } unitID = unitID + 1; diff --git a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp index fb055692e..9633dd0c3 100644 --- a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp +++ b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp @@ -1,9 +1,8 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { @@ -15,16 +14,17 @@ namespace AI { int _totalEnemyTroopValue = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; if (_totalEnemyTroopValue == 0) { _relativeStrength = 100; - } - else { - _relativeStrength = (short)((DAT_GameState::instance.playerDataArray[playerID].totalTeamTroopValue * 100) / _totalEnemyTroopValue); + } else { + _relativeStrength = (short)((DAT_GameState::instance.playerDataArray[playerID].totalTeamTroopValue * 100) + / _totalEnemyTroopValue); } DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy = _relativeStrength; if (param_2 == FALSE) { if (DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue < 100) { return FALSE; } - BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + BOOLEnum BVar2 + = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); if (BVar2 != FALSE) { if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 50) { return TRUE; @@ -40,9 +40,9 @@ namespace AI { if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 75) { return TRUE; } - } - else { - BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + } else { + BOOLEnum BVar2 + = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); if (BVar2 != FALSE) { if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 0x46) { return TRUE; diff --git a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp index 414009e9a..20ee5094d 100644 --- a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp +++ b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp @@ -1,6 +1,5 @@ -#include "OpenSHC/AI/AICState.hpp" - #include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" @@ -13,7 +12,8 @@ namespace AI { AICSpecification* destination = this->aics; int iVar1 = 20; do { - MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)(676, '\0', destination); + MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 676, '\0', destination); destination = destination + 1; iVar1 = iVar1 + -1; } while (iVar1 != 0); From 48b4f4cb2d95989c085a70243079278bca658247 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sun, 26 Jul 2026 23:17:09 +0200 Subject: [PATCH 033/242] ghidra-cpp and claude fixes --- .../AI/AICState/addEngineersToTribe.cpp | 23 +- .../AI/AICState/addRallyPointForTribe.cpp | 101 +++ .../AICState/addUnitToSmallestPatrolTribe.cpp | 4 +- src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp | 53 ++ .../aiChoiceAttForceRallyPercentage.cpp | 93 +++ .../AICState/aiCommandSiegeEngineTribes.cpp | 207 +++++++ .../aiCommandTribe12AggressiveApproach.cpp | 81 +++ .../AICState/aiCommandWallAssaultTribes.cpp | 9 +- .../AI/AICState/aiCreateSiegeUnits.cpp | 514 +++++++++++++++ .../AI/AICState/aiGiveRaidInstructions.cpp | 306 +++++++++ .../AI/AICState/aiOfTypeInCurrentGame.cpp | 55 ++ .../AICState/aiReassignTunnelersToTribe.cpp | 25 +- .../AI/AICState/aiRecruitSortieMeleeUnits.cpp | 113 ++++ .../AICState/aiRecruitSortieRangedUnits.cpp | 117 ++++ src/OpenSHC/AI/AICState/aiRecruitUnits.cpp | 487 +++++++++++++++ .../aiRegisterTribeAndAssignTarget.cpp | 69 +++ .../AI/AICState/aiRequiresExtraOxtethers.cpp | 147 +++++ src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 123 ++++ ...iShouldAttackOrWaitForTeamCoordination.cpp | 112 ++++ .../AI/AICState/aiUpdateTaxesAndRations.cpp | 157 +++++ .../AI/AICState/assignUnitToATribe.cpp | 3 +- src/OpenSHC/AI/AICState/buyRequiredGoods.cpp | 129 ++++ ...mBuildingIDFromPlayersArrayOfBuildings.cpp | 105 ++++ .../AI/AICState/clearOutdatedAITribes.cpp | 67 ++ .../clearPlayerDataInformationChunk.cpp | 52 ++ .../clearRallyFlagOnAllAIAttackTribes.cpp | 89 +++ .../AI/AICState/commandFourTribesToMove.cpp | 68 ++ .../AICState/computeAttackPossibilities.cpp | 60 ++ .../AICState/computeEnemyKeepApproachTile.cpp | 173 ++++++ .../AI/AICState/computeNervousness.cpp | 86 +++ .../AI/AICState/countSiegeEngineUnits.cpp | 63 ++ .../AICState/decideOnTribeAttackLocation.cpp | 287 +++++++++ .../AI/AICState/destroyBuildingIfNoWorker.cpp | 34 +- ...determineAIPlayerAttackRequestResponse.cpp | 55 ++ .../AI/AICState/determineAIPlayerHelp.cpp | 53 ++ .../AI/AICState/disbandAIPlayerSiegeUnits.cpp | 72 +++ ...ndAttackTribePositionAndPathToDefenses.cpp | 117 ++++ .../generateSiegeCreationInformation.cpp | 106 ++++ .../AI/AICState/getSmallestPatrolTribe.cpp | 100 +++ .../getTargetableBuildingForPlayerID.cpp | 116 ++++ .../getUnitTypeForUnitBehaviourType.cpp | 118 ++++ .../giveMoveCommandToAttackTribes.cpp | 106 ++++ .../AICState/giveMoveCommandToSortieUnits.cpp | 105 ++++ .../AI/AICState/giveSomeRaidCommand.cpp | 70 +++ .../AICState/hasNoTroopsOrAllAreDiggers.cpp | 47 +- .../AI/AICState/instructTribe166ToMove.cpp | 116 ++++ .../AI/AICState/makeOutpostTribesAttack.cpp | 12 +- ...eUnitsGoDefensiveAndBackToSomeLocation.cpp | 100 +++ .../AICState/moveAttackTribesToLocations.cpp | 104 ++++ .../moveAttackingUnitsToNextRallyPoint.cpp | 151 +++++ ...rcentageNonMovingTribesGTEAICSpecified.cpp | 96 +++ ...BuyWhenLowOnResourceAndSnoozeBuildings.cpp | 333 ++++++++++ ...yerKilledBiksFromKilledAndKillerPlayer.cpp | 22 +- ...playTauntToAttackedPlayerBikFromPlayer.cpp | 23 +- .../processAttForceRallyPercentage.cpp | 111 ++++ .../randomlySelectAttackUnitTypeToRecruit.cpp | 233 +++++++ .../recomputeAIPathCostToAttackedKeep.cpp | 93 +++ .../AI/AICState/recomputeAIZonerLayer.cpp | 42 ++ .../AI/AICState/recomputeAttackAIZone.cpp | 71 +++ .../AI/AICState/recreateEngineersTribe.cpp | 2 +- .../recruitHarrassingSiegeEngines.cpp | 254 ++++++++ ...oveOrganismsAndSetMoveDestinationPairs.cpp | 66 ++ .../AI/AICState/renderDebugDataAiInfo.cpp | 248 ++++++++ src/OpenSHC/AI/AICState/requestGoods.cpp | 70 +++ .../AI/AICState/selectAttackTarget.cpp | 254 ++++++++ ...selectBuildingFromAListOfBuildingTypes.cpp | 75 +++ ...andomBuildingIDFromListOfBuildingTypes.cpp | 37 ++ src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 147 +++++ ...oAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp | 109 ++++ ...sendOilMenForOilPickupOrToAIVLocations.cpp | 104 ++++ ...gedUnitTribesToAIVSlotsOrKeepIfNervous.cpp | 76 +++ .../AICState/sendTribeToAIVLocationSlot.cpp | 90 +++ .../sendUnitsToAttackBreachedCastle.cpp | 181 ++++++ src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp | 2 +- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 165 +++++ ...sendWallPatrolUnitTribesToAIVLocations.cpp | 155 +++++ .../AI/AICState/setAICParameters_06.cpp | 289 +++++++++ .../AI/AICState/setAICParameters_07.cpp | 283 +++++++++ .../AI/AICState/setAICParameters_08.cpp | 289 +++++++++ .../AI/AICState/setAICParameters_09.cpp | 283 +++++++++ .../AI/AICState/setAICParameters_10.cpp | 283 +++++++++ .../AI/AICState/setAICParameters_11.cpp | 281 +++++++++ .../AI/AICState/setAICParameters_12.cpp | 281 +++++++++ .../AI/AICState/setAICParameters_13.cpp | 275 +++++++++ .../AI/AICState/setAICParameters_14.cpp | 289 +++++++++ .../AI/AICState/setAICParameters_15.cpp | 275 +++++++++ .../AI/AICState/setAICParameters_16.cpp | 277 +++++++++ .../AICState/setAttackCoordinationLevel.cpp | 6 +- ...htTribe0xc0TribesToAggressiveAndAttack.cpp | 9 +- src/OpenSHC/AI/AICState/setInitialAIC.cpp | 52 ++ .../AICState/setNextMoveLocationForUnits.cpp | 52 ++ ...TargetForTribeBasedOnTargetChoiceLogic.cpp | 196 ++++++ .../AICState/setupWorkshopProductionType.cpp | 152 +++++ .../AI/AICState/shareGoldAmongTeamMembers.cpp | 203 ++++++ .../AI/AICState/shouldNotBuildKillingPits.cpp | 5 +- ...uldWaitWithBuildingAPositiveFearFactor.cpp | 4 +- .../AI/AICState/smallestTribeOfUnitType.cpp | 11 +- .../AI/AICState/someChatMessageSelection.cpp | 210 +++++++ .../AI/AICState/teamIsWeakRelativeToEnemy.cpp | 20 +- .../AI/AICState/unitIDIsRangedOrArmored.cpp | 40 ++ src/OpenSHC/AI/AICState/updateAIBehaviour.cpp | 165 +++++ .../AI/AICState/updateAIPlayerState.cpp | 567 +++++++++++++++++ .../AI/AICState/updateAIStrengthState.cpp | 583 ++++++++++++++++++ .../AI/AICState/updateTribeLocations.cpp | 74 +++ ...12_toPlaceSiegeTentsAndAssignEngineers.cpp | 206 +++++++ .../useAITribe_0xe_toPlaceTunnels.cpp | 80 +++ src/OpenSHC/AI/AICState/wipeAICMemory.cpp | 10 +- .../woodCuttersHutWhileNoWoodAvailable.cpp | 7 +- 108 files changed, 14227 insertions(+), 149 deletions(-) create mode 100644 src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp create mode 100644 src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp create mode 100644 src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp create mode 100644 src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp create mode 100644 src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp create mode 100644 src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRecruitUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp create mode 100644 src/OpenSHC/AI/AICState/aiRetreatUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp create mode 100644 src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp create mode 100644 src/OpenSHC/AI/AICState/buyRequiredGoods.cpp create mode 100644 src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp create mode 100644 src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp create mode 100644 src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp create mode 100644 src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp create mode 100644 src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp create mode 100644 src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp create mode 100644 src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp create mode 100644 src/OpenSHC/AI/AICState/computeNervousness.cpp create mode 100644 src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp create mode 100644 src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp create mode 100644 src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp create mode 100644 src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp create mode 100644 src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp create mode 100644 src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp create mode 100644 src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp create mode 100644 src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp create mode 100644 src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp create mode 100644 src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp create mode 100644 src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp create mode 100644 src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp create mode 100644 src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp create mode 100644 src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp create mode 100644 src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp create mode 100644 src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp create mode 100644 src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp create mode 100644 src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp create mode 100644 src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp create mode 100644 src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp create mode 100644 src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp create mode 100644 src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp create mode 100644 src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp create mode 100644 src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp create mode 100644 src/OpenSHC/AI/AICState/requestGoods.cpp create mode 100644 src/OpenSHC/AI/AICState/selectAttackTarget.cpp create mode 100644 src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp create mode 100644 src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp create mode 100644 src/OpenSHC/AI/AICState/sellExcessGoods.cpp create mode 100644 src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp create mode 100644 src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp create mode 100644 src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp create mode 100644 src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp create mode 100644 src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp create mode 100644 src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp create mode 100644 src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_06.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_07.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_08.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_09.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_10.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_11.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_12.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_13.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_14.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_15.cpp create mode 100644 src/OpenSHC/AI/AICState/setAICParameters_16.cpp create mode 100644 src/OpenSHC/AI/AICState/setInitialAIC.cpp create mode 100644 src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp create mode 100644 src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp create mode 100644 src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp create mode 100644 src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp create mode 100644 src/OpenSHC/AI/AICState/someChatMessageSelection.cpp create mode 100644 src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp create mode 100644 src/OpenSHC/AI/AICState/updateAIBehaviour.cpp create mode 100644 src/OpenSHC/AI/AICState/updateAIPlayerState.cpp create mode 100644 src/OpenSHC/AI/AICState/updateAIStrengthState.cpp create mode 100644 src/OpenSHC/AI/AICState/updateTribeLocations.cpp create mode 100644 src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp create mode 100644 src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp diff --git a/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp b/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp index e9c39df1a..2d3d8b873 100644 --- a/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp +++ b/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp @@ -10,24 +10,21 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D4040 void AICState::addEngineersToTribe(int playerID) { - int unitID; - - unitID = 1; + int _unitID = 1; if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { - /* Unit offset 150 */ - Map::Units::Unit* psVar1 = &DAT_UnitsState::instance.units[1]; + Map::Units::Unit* _pUnit = &DAT_UnitsState::instance.units[1]; do { /* if logicalState == normal && owner == playerID && unitType == 0x1e (engineer) && aiUnitBehaviourType == 10 */ - if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == playerID)) - && (psVar1->dying == 0)) - && (((psVar1->unitType == Map::Units::UT_E_ENGINEER) && (psVar1->aiUnitBehaviourType == 10)) - && (psVar1->tribeID == 0))) { - MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 10); + if ((((_pUnit->logicalState == Map::Units::ULS_NORMAL) && (_pUnit->owner == playerID)) + && (_pUnit->dying == 0)) + && (((_pUnit->unitType == Map::Units::UT_E_ENGINEER) && (_pUnit->aiUnitBehaviourType == 10)) + && (_pUnit->tribeID == 0))) { + MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(_unitID, 10); } - unitID = unitID + 1; - psVar1 = psVar1 + 1; - } while (unitID < (int)DAT_UnitsState::instance.maxUnitCount); + _unitID = _unitID + 1; + _pUnit = _pUnit + 1; + } while (_unitID < (int)DAT_UnitsState::instance.maxUnitCount); } } diff --git a/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp b/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp new file mode 100644 index 000000000..1ae3180da --- /dev/null +++ b/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp @@ -0,0 +1,101 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/Unit.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitTypeShort.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Unit; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::UnitTypeShort; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFA10 + void AICState ::addRallyPointForTribe(int tribeID) + + { + + short* psVar1; + + BOOLEnum _areInDifferentTeamsUnk; + + Unit* _ptrUnit; + + UnitTypeShort _unitType; + + DAT_TribesState::instance.tribes[tribeID].rallyPointCount = 0; + + _ptrUnit = &DAT_UnitsState::instance.units[1]; + + do { + + if (_ptrUnit->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) { + + _areInDifferentTeamsUnk = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::getTeamsDifferent, + DAT_GameState::ptr)(DAT_TribesState::instance.tribes[tribeID].owner, (int)((int)(_ptrUnit->owner))); + + if (_areInDifferentTeamsUnk == FALSE) { + + _unitType = _ptrUnit->unitType; + + if ((((_unitType == OpenSHC::Map::Units::UT_S_CATAPULT) + || (_unitType == OpenSHC::Map::Units::UT_S_TREBUCHET)) + || (_unitType == OpenSHC::Map::Units::UT_S_FBALLISTA)) + && (_ptrUnit->unknownSiegeTentRelated02 == 3)) { + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::computeNextRallyPointDestination, + DAT_PathFindingState::ptr)(-1, (int)((int)(_ptrUnit->x)), (int)((int)(_ptrUnit->y))); + + DAT_TribesState::instance.tribes[tribeID] + .rallyPointArray[DAT_TribesState::instance.tribes[tribeID].rallyPointCount][0] + = (short)DAT_PathFindingState::instance.ALG_ResultX; + + DAT_TribesState::instance.tribes[tribeID] + .rallyPointArray[DAT_TribesState::instance.tribes[tribeID].rallyPointCount][1] + = (short)DAT_PathFindingState::instance.ALG_ResultY; + + psVar1 = &DAT_TribesState::instance.tribes[tribeID].rallyPointCount; + + *psVar1 = *psVar1 + 1; + + if (8 < DAT_TribesState::instance.tribes[tribeID].rallyPointCount) + break; + } + } + } + + _ptrUnit = _ptrUnit + 0x248; + + } while ((int)_ptrUnit < 0x165141a); + + if (DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex < 0) { + + DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex = 0; + } + + if (DAT_TribesState::instance.tribes[tribeID].rallyPointCount + <= DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex) { + + DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex = 0; + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp index 9a2d04fed..2939e1589 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp @@ -1,7 +1,9 @@ +#include "OpenSHC/AI/AICState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" +#include "OpenSHC/Globals/DAT_AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -16,7 +18,7 @@ namespace AI { int _aiType = DAT_GameState::instance.playerDataArray[iVar1].aiType; if (_aiType != AITA_NULL) { DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 4; - iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::getSmallestPatrolTribe, DAT_TribesState::ptr)( + iVar1 = MACRO_CALL_MEMBER(AI::AICState_Func::getSmallestPatrolTribe, DAT_AICState::ptr)( iVar1, (int)this->aics[_aiType - 1].OuterPatrolGroupsCount); MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); } diff --git a/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp b/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp new file mode 100644 index 000000000..0181f8255 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp @@ -0,0 +1,53 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Game::Player::PlayerData; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x004D48F0 + void AICState ::aiBuyAndSellGoods(int playerID) + + { + + PlayerData* _pPlayerData; + + int _pMarketID; + + _pMarketID = DAT_GameState::instance.playerDataArray[playerID].marketplace.id; + + DAT_GameState::instance.playerDataArray[playerID].hasMarketUnk = 0; + + if (_pMarketID != 0) { + + DAT_GameState::instance.playerDataArray[playerID].hasMarketUnk = 1; + } + + if (DAT_GameState::instance.playerDataArray[playerID].hasMarketUnk != 0) { + + _pPlayerData = &DAT_GameState::instance.playerDataArray[playerID]; + + _pPlayerData->willBuy = _pPlayerData->willBuy ^ TRUE; + + if (_pPlayerData->willBuy == FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellExcessGoods, this)(playerID); + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::buyRequiredGoods, this)(playerID); + + return; + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp new file mode 100644 index 000000000..46b561d3c --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -0,0 +1,93 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CEC80 + uint AICState ::aiChoiceAttForceRallyPercentage(int param_1) + + { + + AITypeInt AVar1; + + int iVar2; + + int iVar3; + + short* psVar4; + + int local_14; + + int local_10; + + int* local_c; + + AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + + return 0; + } + + local_14 = 0; + + local_10 = 0; + + local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + iVar3 = 0; + + if (0 < *local_c) { + + psVar4 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + (*(int (*)[2])(local_c + -1))[0]; + + do { + + iVar2 = (int)*psVar4; + + if (((iVar2 != 0) + && (DAT_TribesState::instance.tribes[iVar2].uid + == DAT_GameState::instance.playerDataArray[param_1] + .aiTribeUIDs[iVar3 + (*(int (*)[2])(local_c + -1))[0]])) + && (local_14 = local_14 + 1, + DAT_TribesState::instance.tribes[iVar2].percentageMovingUnk < 0x14)) { + + local_10 = local_10 + 1; + } + + iVar3 = iVar3 + 1; + + psVar4 = psVar4 + 1; + + } while (iVar3 < *local_c); + } + + local_c = local_c + 2; + + } while ((int)local_c < 0xb42a2c); + + if (0 < local_14) { + + return (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x200) + <= (local_10 * 100) / local_14); + } + + return 0; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp new file mode 100644 index 000000000..f4a02fbcf --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp @@ -0,0 +1,207 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Unit.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitTypeShort.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::Unit; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::UnitTypeShort; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFCD0 + void AICState ::aiCommandSiegeEngineTribes(int playerID) + + { + + UnitTypeShort UVar1; + + int iVar2; + + uint x1; + + int _sectionID2; + + int iVar3; + + int iVar4; + + uint y1; + + Unit* local_14; + + int local_c[3]; + + int _tile; + + short _sectionID; + + short _targetUnitID; + + iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xba]; + + iVar4 = 0; + + iVar3 = 0; + + local_c[0] = 0; + + local_c[1] = 0; + + local_c[2] = 0; + + if ((iVar2 != 0) + && (DAT_TribesState::instance.tribes[iVar2].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xba])) { + + local_c[0] = iVar2; + + iVar3 = 1; + } + + iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbb]; + + if ((iVar2 != 0) + && (DAT_TribesState::instance.tribes[iVar2].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbb])) { + + local_c[iVar3] = iVar2; + + iVar3 = iVar3 + 1; + } + + iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbc]; + + if ((iVar2 != 0) + && (DAT_TribesState::instance.tribes[iVar2].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbc])) { + + local_c[iVar3] = iVar2; + } + + local_14 = &DAT_UnitsState::instance.units[1]; + + do { + + if ((local_14->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) + && ((((UVar1 = local_14->unitType, + UVar1 == OpenSHC::Map::Units::UT_S_TOWER || (UVar1 == OpenSHC::Map::Units::UT_S_BATTERINGRAM)) + || (UVar1 == OpenSHC::Map::Units::UT_S_SHIELD)) + && ((local_14->unknownSiegeTentRelated02 == 3 && (local_14->aiUnitBehaviourType != 0x15)))))) { + + if (UVar1 == OpenSHC::Map::Units::UT_S_TOWER) { + + if ((local_14->tribeID != 0) + && (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc + + -4) + != 0)) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, + DAT_TribesState::ptr)((int)local_14->tribeID, OpenSHC::Map::Units::STBT_0x414); + } + + } + + else if (UVar1 == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + + iVar3 = (int)local_14->tribeID; + + if (iVar3 != 0) { + + if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.gateValuesArray + playerID * 0x177bc + + -4) + == 0) { + + if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + + playerID * 0x177bc + -4) + != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, + DAT_TribesState::ptr)(iVar3, OpenSHC::Map::Units::STBT_0x413); + } + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, + DAT_TribesState::ptr)(iVar3, OpenSHC::Map::Units::STBT_0x3f6); + } + } + + } + + else if (UVar1 == OpenSHC::Map::Units::UT_S_SHIELD) { + + _sectionID = local_14->tribeID; + + _sectionID2 = (int)_sectionID; + + if ((_sectionID2 != 0) && (iVar4 < 3)) { + + iVar3 = local_c[iVar4]; + + DAT_TribesState::instance.tribes[_sectionID2].field56_0x1f2 = (short)iVar3; + + DAT_TribesState::instance.tribes[_sectionID2].uid2 + = DAT_TribesState::instance.tribes[iVar3].uid; + + _targetUnitID = DAT_TribesState::instance.tribes[iVar3].selectionTargetUnitID; + + DAT_TribesState::instance.tribes[iVar3].tribeID = _sectionID; + + _tile = DAT_UnitsState::instance.units[_targetUnitID].tile; + + iVar4 = iVar4 + 1; + + if (0 < _tile) { + + y1 = (uint)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + + x1 = _tile - DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + _sectionID2, x1, y1, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: + calculatePreferredRelativeOrientation, + DAT_DirectionAlgorithmState::ptr)((int)DAT_UnitsState::instance.units[_targetUnitID].x, + (int)((int)(DAT_UnitsState::instance.units[_targetUnitID].y)), (int)((int)(x1)), + (int)((int)(y1))); + + DAT_TribesState::instance.tribes[_sectionID2].orientation + = (short)DAT_DirectionAlgorithmState::instance.orientation; + } + } + } + } + + local_14 = local_14 + 0x248; + + } while ((int)local_14 < 0x165141a); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp new file mode 100644 index 000000000..e4b5a1359 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp @@ -0,0 +1,81 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF2E0 + void AICState ::aiCommandTribe12AggressiveApproach(int param_1) + + { + + int iVar1; + + BOOLEnum BVar2; + + int tribeID; + + if ((((DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) + && (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xc], tribeID != 0)) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xc])) + && (iVar1 = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID, iVar1 != 0)) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + DAT_PathFindingState::ptr)((int)DAT_UnitsState::instance.units[iVar1].x, + (uint)((int)((int)DAT_UnitsState::instance.units[iVar1].y)), -1, -1, 10000, FALSE); + + iVar1 = DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID; + + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + BVar2 = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)(iVar1, 200); + + if (((BVar2 != FALSE) + || (BVar2 = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, (int)((int)(150))), + BVar2 != FALSE)) + || ((BVar2 + = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, 100), + BVar2 != FALSE + || (BVar2 = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, (int)((int)(50))), + BVar2 != FALSE)))) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(tribeID, (uint)((int)(DAT_PathFindingState::instance.ALG_ResultX)), + (uint)((int)(DAT_PathFindingState::instance.ALG_ResultY)), 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp index fe11b9a93..3f1f25be3 100644 --- a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp @@ -13,14 +13,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF660 void AICState::aiCommandWallAssaultTribes(int param_1) { - int tribeID; - int iVar1; - short* psVar2; if (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) { - iVar1 = 0; - psVar2 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + 0xbe; + int iVar1 = 0; + short* psVar2 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + 0xbe; do { - tribeID = (int)*psVar2; + int tribeID = (int)*psVar2; if (((tribeID != 0) && (DAT_TribesState::instance.tribes[tribeID].uid == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar1 + 0xbe])) diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp new file mode 100644 index 000000000..ec0e19d76 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -0,0 +1,514 @@ +#include "OpenSHC/AI/AICState.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/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/Tribes/AITribeType.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Buildings/BuildingTypeShort.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.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_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::Tribes::AITribeType; + using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Buildings::BuildingTypeShort; + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2000 + void AICState ::aiCreateSiegeUnits(int playerID) + + { + + int _existingBuildingID; + + int _spawnedUnit; + + int _requiredEngineerCount; + + int _remainingRequiredEngineers; + + int _tribeID; + + int _targetUnitID; + + int _area; + + int _engineersTribe; + + int _aicOffset; + + int _y; + + int _slotIndex; + + int _nextSlotIndex; + + int _tile; + + int _mappingOffset; + + int _incrementsBy5; + + int _siegeInfoIndex; + + int _tribeSize; + + int _requiredGold; + + int _engineersGuildID; + + int _newUID; + + int _newBuildingID; + + int* _pGold; + + int _engineIndex; + + int _uid; + + int _unitID; + + int _location; + + AITypeInt _aiType; + + BuildingTypeShort _existingBuildingType; + + int* _pDelay; + + UnitType _unitType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType != OpenSHC::AI::AIT_NULL) { + + _engineersGuildID = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + + if (((0 < _engineersGuildID) + && (DAT_BuildingsState::instance.buildings[_engineersGuildID].buildingType + == OpenSHC::Map::Buildings::BT_ENGINEERSGUILD)) + && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) { + + _siegeInfoIndex = 0; + + _incrementsBy5 = 0; + + _mappingOffset = 0; + + do { + + _unitType + = *(UnitType*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].unitType + + _mappingOffset); + + _tribeSize = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*( + int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + + _mappingOffset)]; + + _slotIndex = 0; + + if (_tribeSize < 4) { + + if (0 < _tribeSize) + goto LAB_004d20c0; + + } + + else { + + _tribeSize = 3; + + LAB_004d20c0: + do { + + _nextSlotIndex = _slotIndex + 1; + + _location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[*( + int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + + _mappingOffset)][_slotIndex]; + + if (0 < _location) { + + _existingBuildingID = (int)(short)DAT_TileMapState::instance.BuildingLayer[_location]; + + _engineIndex = _incrementsBy5 + _slotIndex; + + _unitID = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID; + + _uid = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid; + + _tile = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID; + + if ((_unitID == 0) || (DAT_UnitsState::instance.units[_unitID].uid == _uid)) { + + if ((_tile == 0) || (DAT_BuildingsState::instance.buildings[_tile].uid == _uid)) { + + if (_unitID == 0) { + + if (_tile == 0) { + + if (_existingBuildingID == 0) { + + if (0x1f < _mappingOffset) + goto LAB_004d21d4; + + } + + else if ((_mappingOffset < 0x20) + && ((_existingBuildingType + = DAT_BuildingsState::instance.buildings[_existingBuildingID] + .buildingType, + _existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER4 + || (_existingBuildingType + == OpenSHC::Map::Buildings::BT_TOWER5)))) { + + LAB_004d21d4: + _requiredGold + = DAT_BuildingsState::instance + .buildingCosts[*( + int*)((int)&DAT_SkirmishDefinedData::instance + .DAT_SiegeEngineMetaInfoArray[0] + .buildingType + + _mappingOffset)] + .requiredGold; + + _aicOffset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + + /* + defSiegeEngineGoldThreshold */ + + /* + defSiegeEngineBuildDelay */ + + if ((_requiredGold + <= DAT_GameState::instance.playerDataArray[playerID] + .currentResources[0xf] + + *(int*)((int)this + _aicOffset + 0x118)) + && (_pDelay = &DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay, + *_pDelay = *_pDelay + 1, + *(int*)((int)this + _aicOffset + 0x11c) + <= DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay)) { + + _y = (int)DAT_ViewportRenderState::instance + .DAT_TileTranslationMatrix_YComponent[_location]; + + _tile = _location + - DAT_ViewportRenderState::instance.translationMatrix[_y] + .addXgetTile; + + if (_siegeInfoIndex < 2) { + + _spawnedUnit = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::spawnUnit, + DAT_UnitsState::ptr)(playerID, playerID, _tile * 8 + 4, + _y * 8 + 4, + (int)((int)(DAT_BuildingsState::instance + .buildings[_existingBuildingID] + .terrainHeightUnk)), + _unitType); + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .unitID = _spawnedUnit; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .uid = DAT_UnitsState::instance.units[_spawnedUnit].uid; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .buildingID = 0; + + MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func:: + processPlacementResourceLossForBuildingType, + DAT_BuildingsState::ptr)(playerID, + (BuildingType)((int)(DAT_SkirmishDefinedData::instance + .DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex] + .buildingType)), + 0); + + } + + else { + + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::placeBuilding, + DAT_TileMapState::ptr)(playerID, _tile, _y, + (CommandBuildingType)((int)((uint)(ushort)(short) + DAT_SkirmishDefinedData::instance + .DAT_SiegeEngineMetaInfoArray + [_siegeInfoIndex] + .commandBuildingType)), + 3, 0xf); + + if (DAT_TileMapState::instance.buildingPlacementFail + == FALSE) { + + _pGold + = DAT_GameState::instance.playerDataArray[playerID] + .currentResources + + 0xf; + + *_pGold = *_pGold - _requiredGold; + + _newBuildingID + = DAT_TileMapState::instance.DAT_PlacedBuildingID; + + _newUID = DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance + .DAT_PlacedBuildingID] + .uid; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex] + [_slotIndex] + .unitID = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex] + [_slotIndex] + .uid = _newUID; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex] + [_slotIndex] + .buildingID = _newBuildingID; + } + } + + /* + delay = 0 */ + + *(undefined4*)(playerID * 0x39f4 + 0x115f48c + _slotIndex * 20 + + _siegeInfoIndex * 100) = 0; + + return; + } + } + + } + + else { + + LAB_004d22d3: + _requiredEngineerCount + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: + getRequiredEngineerCountForSiegeBuilding, + DAT_BuildingsState::ptr)(_tile); + + if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount + != _requiredEngineerCount) { + + if (_requiredEngineerCount + <= DAT_GameState::instance.playerDataArray[playerID] + .engineerCountRelated) { + + _engineersTribe = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func:: + assignRequiredIdleEngineersToNewTribe, + this)(playerID, _requiredEngineerCount); + + DAT_TribesState::instance.tribes[_engineersTribe].tribeType + = OpenSHC::AI::Tribes::AITT_ENGINEERS; + + DAT_TribesState::instance.tribes[_engineersTribe] + .tribeBehaviorType = OpenSHC::Map::Units:: + STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func:: + giveTribeAnInstruction, + DAT_TribesState::ptr)(_engineersTribe, + OpenSHC::Map::Units:: + UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, + _tile, DAT_BuildingsState::instance.buildings[_tile].uid, + 0); + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired + = TRUE; + } + } + + } + + else { + + if (_tile != 0) + goto LAB_004d22d3; + + _remainingRequiredEngineers = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, + DAT_UnitsState::ptr)(_unitID); + + if (0 < _remainingRequiredEngineers) { + + if (DAT_GameState::instance.playerDataArray[playerID] + .engineerCountRelated + < _remainingRequiredEngineers) { + + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired + = TRUE; + + } + + else { + + _tribeID + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func:: + assignRequiredIdleEngineersToNewTribe, + this)(playerID, _remainingRequiredEngineers); + + _targetUnitID = (int)DAT_TribesState::instance.tribes[_tribeID] + .selectionTargetUnitID; + + if ((_targetUnitID != 0) + && (_area = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func:: + calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance + .units[_unitID] + .tile])), + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance + .units[_targetUnitID] + .tile])), + 0), + _area != 0)) { + + DAT_TribesState::instance.tribes[_tribeID].tribeType + = OpenSHC::AI::Tribes::AITT_ENGINEERS; + + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x41c; + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, + DAT_UnitsState::ptr)(_tribeID, + OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, _unitID, + DAT_UnitsState::instance.units[_unitID].uid, 0); + + return; + } + } + } + } + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unknown = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID = 0; + } + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unknown = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID = 0; + } + } + + _slotIndex = _nextSlotIndex; + + } while (_nextSlotIndex < _tribeSize); + } + + _siegeInfoIndex = _siegeInfoIndex + 1; + + _incrementsBy5 = _incrementsBy5 + 5; + + _mappingOffset = _mappingOffset + 16; + + if (64 < _mappingOffset) { + + return; + } + + } while (true); + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp new file mode 100644 index 000000000..3f67ced06 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -0,0 +1,306 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2A70 + void AICState ::aiGiveRaidInstructions(int playerID) + + { + + int* piVar1; + + short sVar2; + + int iVar3; + + int _isAlive; + + int _buildingID_2; + + int _buildingID; + + int iVar4; + + int _buildingTile; + + BOOLEnum BVar5; + + int _tribeID3; + + BOOLEnum _indexTo6; + + short* _ptrTribeID3; + + int _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType != 0) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter; + + *piVar1 = *piVar1 + 1; + + /* + AIC: RaidRetargetDelay */ + + _indexTo6 = FALSE; + + if (*(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x1f0) + <= DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter) { + + DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk == 0) { + + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; + + } + + else { + + iVar4 = DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown; + + if (0 < iVar4) { + + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + = iVar4 + -1; + } + } + + _ptrTribeID3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xb4; + + do { + + _tribeID3 = (int)*_ptrTribeID3; + + DAT_TribesState::instance.tribes[_tribeID3].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + if ((_tribeID3 != 0) + && (DAT_TribesState::instance.tribes[_tribeID3].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_indexTo6 + 0xb4])) { + + if ((DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2) + && (_isAlive = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), + _isAlive != 0)) { + + if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) { + + _buildingID_2 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk, + (undefined4)((int)(_indexTo6))); + + if (_buildingID_2 == 0) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + + LAB_004d2d6b: + if (_buildingID != 0) + goto LAB_004d2d6f; + + } + + else { + + LAB_004d2c00: + _buildingTile + = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] + .buildingEntryY] + .addXgetTile; + + LAB_004d2d8d: + if (_buildingTile != 0) { + + sVar2 = DAT_ViewportRenderState::instance + .DAT_TileTranslationMatrix_YComponent[_buildingTile]; + + iVar4 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; + + BVar5 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( + _tribeID3, _buildingTile); + + if (BVar5 == FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID3, playerID); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, + DAT_TribesState::ptr)(_tribeID3, (uint)((int)(_buildingTile - iVar4)), + (uint)((int)((int)sVar2)), 0); + } + } + } + } + + } + + else if ((DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + == 0) + && (iVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, + this)(_aiType + -1, playerID), + DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk < iVar4)) { + + if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) + && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, TRUE), + BVar5 == FALSE)) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + playerID, (undefined4)((int)(_indexTo6))); + + if (_buildingID != 0) { + + LAB_004d2d6f: + _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] + .buildingEntryY] + .addXgetTile; + + goto LAB_004d2d8d; + } + + _buildingID_2 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + + if (_buildingID_2 != 0) + goto LAB_004d2c00; + } + + } + + else if ((DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb6) + || (DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb5)) { + + if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) + && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, FALSE), + BVar5 == FALSE)) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk, + (undefined4)((int)(_indexTo6))); + + if (_buildingID == 0) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, + this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + + goto LAB_004d2d6b; + } + + goto LAB_004d2d6f; + } + + } + + else { + + BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, FALSE); + + if (BVar5 == FALSE) { + + iVar4 = (int)DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID; + + if ((((iVar4 == 0) + || (DAT_BuildingsState::instance.buildings[iVar4].uid + != DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID)) + || (DAT_BuildingsState::instance.buildings[iVar4].fireDuration != 0)) + || (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, TRUE), + BVar5 == FALSE)) { + + iVar4 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, + this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + + if (iVar4 == 0) { + + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; + + DAT_GameState::instance.playerDataArray[playerID] + .someTotalDefenseTroopsRelatedCountdown = 0; + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, + DAT_UnitsState::ptr)(_tribeID3, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, iVar4, + DAT_BuildingsState::instance.buildings[iVar4].uid, 0); + + iVar3 = DAT_BuildingsState::instance.buildings[iVar4].uid; + + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = (short)iVar4; + + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID = iVar3; + + DAT_GameState::instance.playerDataArray[playerID] + .someTotalDefenseTroopsRelatedCountdown = 100; + } + + } + + else { + + if (DAT_GameState::instance.mapAndTime.yearChanged != 0) { + + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; + } + + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + = 100; + } + } + } + } + + _ptrTribeID3 = _ptrTribeID3 + 1; + + _indexTo6 = _indexTo6 + TRUE; + + } while ((int)_indexTo6 < 6); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp b/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp new file mode 100644 index 000000000..0de10b080 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp @@ -0,0 +1,55 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Game::Player::PlayerData; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + 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 0x004D0580 + BOOLEnum AICState ::aiOfTypeInCurrentGame(int param_1) + + { + + int* _ptrCurrentAIArray; + + PlayerData* _playerData; + + _playerData = &DAT_GameState::instance.playerDataArray[1]; + + _ptrCurrentAIArray = DAT_GameSynchronyState::instance.currentAIArray + 1; + + while (((*_ptrCurrentAIArray == 0 || (_playerData->lordKilledByPlayerID != 0)) + || (param_1 != _playerData->aiType + ~OpenSHC::AI::AIT_NULL))) { + + _ptrCurrentAIArray = _ptrCurrentAIArray + 1; + + _playerData = _playerData + 0xe7d; + + if (0x191de9f < (int)_ptrCurrentAIArray) { + + return FALSE; + } + } + + return TRUE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp index 3c745352a..4b40f07e0 100644 --- a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp @@ -13,22 +13,17 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D40B0 void AICState::aiReassignTunnelersToTribe(int param_1) { - uint unitID = 1; - if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { - Map::Units::Unit* psVar1 = &DAT_UnitsState::instance.units[1]; - do { - if ((((psVar1->logicalState == Map::Units::ULS_NORMAL) && (psVar1->owner == param_1)) - && (psVar1->dying == 0)) - && ((psVar1->unitType == Map::Units::UT_TUNNELER && (psVar1->aiUnitBehaviourType == 0xf)))) { - if (psVar1->tribeID != 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( - unitID, (int)psVar1->tribeID); - } - MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 0xf); + for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { + Map::Units::Unit* _pUnit = &DAT_UnitsState::instance.units[unitID]; + if ((((_pUnit->logicalState == Map::Units::ULS_NORMAL) && (_pUnit->owner == param_1)) + && (_pUnit->dying == 0)) + && ((_pUnit->unitType == Map::Units::UT_TUNNELER && (_pUnit->aiUnitBehaviourType == 0xf)))) { + if (_pUnit->tribeID != 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, (int)_pUnit->tribeID); } - unitID = unitID + 1; - psVar1 = psVar1 + 1; - } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 0xf); + } } } } diff --git a/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp new file mode 100644 index 000000000..3b011e85d --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp @@ -0,0 +1,113 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Map::Units::UnitType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD690 + void AICState ::aiRecruitSortieMeleeUnits(int playerID) + + { + + AITypeInt AVar1; + + int iVar2; + + int _unitID; + + int _section1016id; + + UnitType _unitType; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 != OpenSHC::AI::AIT_NULL) { + + iVar2 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + + _section1016id = *(int*)((int)this + iVar2 + 0x154); + + if (((((-1 < _section1016id) + && (DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 < _section1016id)) + && (0 < DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount)) + && ((DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0 + && (_unitType = *(UnitType*)((int)this + iVar2 + 0x158), + _unitType != OpenSHC::Map::Units::UT_E_ENGINEER)))) + && ((_unitType != OpenSHC::Map::Units::UT_E_LADDER + && (_unitType != OpenSHC::Map::Units::UT_TUNNELER)))) { + + if ((int)_unitType < 0x46) { + + _section1016id = DAT_GameState::instance.playerDataArray[playerID].barracks.id; + + } + + else { + + _section1016id = DAT_GameState::instance.playerDataArray[playerID].mercenaryPost.id; + } + + if (_section1016id != 0) { + + if ((int)_unitType < 0x46) { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_section1016id)), playerID, 0); + + } + + else { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_section1016id)), playerID, 0); + } + + if (_unitID == 0) { + + _section1016id = *(int*)((int)this + iVar2 + 0x9c); + + if ((0 < _section1016id) && (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason == 2)) { + + DAT_GameState::instance.playerDataArray[playerID] + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] + = _section1016id; + + return; + } + + } + + else { + + DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType = 7; + + _section1016id = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::createTribeForUnitType, this)( + playerID, (int)((int)(167))); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + _unitID, _section1016id); + } + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp new file mode 100644 index 000000000..b9e473e21 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp @@ -0,0 +1,117 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Map::Units::UnitType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD560 + void AICState ::aiRecruitSortieRangedUnits(int playerID) + + { + + UnitType unitType; + + int iVar1; + + uint _unitID; + + int iVar2; + + int _buildingID; + + AITypeInt _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType != OpenSHC::AI::AIT_NULL) { + + iVar1 = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + + iVar2 = *(int*)((int)this + iVar1 + 0x14c); + + /* + bug: missing != 0? */ + + if (((((-1 < iVar2) + && (DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 + < DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 / 2 + iVar2)) + && (0 < DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount)) + && ((DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0 + && (unitType = *(UnitType*)((int)this + iVar1 + 0x150), + unitType != OpenSHC::Map::Units::UT_E_ENGINEER)))) + && ((unitType != OpenSHC::Map::Units::UT_E_LADDER && (unitType != OpenSHC::Map::Units::UT_TUNNELER)))) { + + if ((int)unitType < 0x46) { + + _buildingID = DAT_GameState::instance.playerDataArray[playerID].barracks.id; + + } + + else { + + _buildingID = DAT_GameState::instance.playerDataArray[playerID].mercenaryPost.id; + } + + if (_buildingID != 0) { + + if ((int)unitType < 0x46) { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, + DAT_UnitsState::ptr)(unitType, (undefined4)((int)(_buildingID)), playerID, 0); + + } + + else { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, + DAT_UnitsState::ptr)(unitType, (undefined4)((int)(_buildingID)), playerID, 0); + } + + if (_unitID == 0) { + + iVar2 = *(int*)((int)this + iVar1 + 0x9c); + + if ((0 < iVar2) && (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason == 2)) { + + DAT_GameState::instance.playerDataArray[playerID] + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = iVar2; + + return; + } + + } + + else { + + DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType = 6; + + iVar2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::createTribeForUnitType, this)( + playerID, (int)((int)(166))); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + _unitID, iVar2); + } + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp new file mode 100644 index 000000000..50877b900 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp @@ -0,0 +1,487 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AIRecruitUnitChoice.hpp" +#include "OpenSHC/AI/AIRecruitUnitChoiceInt.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/AIUnitBehaviourType.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Game/TrailType.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/UnitType.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_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AICState; + using OpenSHC::AI::AIRecruitUnitChoice; + using OpenSHC::AI::AIRecruitUnitChoiceInt; + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIUnitBehaviourType; + using OpenSHC::Game::GameMode2; + using OpenSHC::Game::TrailType; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3AE0 + void AICState ::aiRecruitUnits(int playerID) + + { + + int* piVar1; + + AIRecruitUnitChoiceInt AVar2; + + bool bVar3; + + int iVar4; + + int iVar5; + + int _tribeID_defDiggingUnitMax; + + int _unitID; + + UnitType _unitType; + + int iVar6; + + AICState* _pAICState; + + int local_8; + + int _aicRecruitInterval; + + int _nervousActionTracker; + + int _buildingID; + + int _unitChoiceIndex; + + AIRecruitUnitChoiceInt _unitTypeChoice; + + int _defTotal; + + AITypeInt _aiType; + + int _playerID2; + + bool _recruitDefDiggingUnit; + + _playerID2 = playerID; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + _unitType = ((UnitType)0); + + _pAICState = this; + + if (_aiType != OpenSHC::AI::AIT_NULL) { + + bVar3 = false; + + _recruitDefDiggingUnit = false; + + iVar6 = _aiType + ~OpenSHC::AI::AIT_NULL; + + if (((DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) + && (DAT_GameCore::instance.isSkirmishTrail == TRUE)) + && (DAT_GameCore::instance.currentTrailType == OpenSHC::Game::TT_EXTREME)) { + + bVar3 = true; + } + + iVar4 = iVar6 * 0xa9; + + _aicRecruitInterval = *(int*)((int)this + + (DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + iVar4) * 4 + 0x164); + + local_8 = -(uint)(_aicRecruitInterval != 0) + 2; + + if (bVar3) { + + local_8 = -(uint)(_aicRecruitInterval != 0) + 3; + } + + _nervousActionTracker = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + if (_nervousActionTracker < 1) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker; + + *piVar1 = *piVar1 + 1; + + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker < _aicRecruitInterval) { + + return; + } + + } + + else { + + local_8 = 4; + } + + iVar5 = DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount; + + DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker = 0; + + if ((0 < iVar5) && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) { + + AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState; + + if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { + + _defTotal = *(int*)((int)this + iVar6 * 0x2a4 + 0x170); + + if (bVar3) { + + _defTotal = (_defTotal * 4) / 3; + } + + if (0 < _nervousActionTracker) { + + _defTotal = _defTotal * 4; + } + + if (_defTotal <= DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk) { + + return; + } + + } + + else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { + + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( + iVar6, playerID); + + if (iVar5 <= DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk) { + + return; + } + + } + + else if ((AVar2 == OpenSHC::AI::AIRUC_ATTACKING) + && (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState != 0)) { + + return; + } + + iVar6 = iVar6 * 0x2a4; + + /* + DefDiggingUnitMax */ + + /* + DefDiggingUnitMax */ + + if (((*(int*)((int)this + iVar6 + 0x15c) != 0) + && (iVar5 + = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, + DAT_TileMapState::ptr)(playerID), + iVar5 != 0)) + && ((_tribeID_defDiggingUnitMax + = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10], + _tribeID_defDiggingUnitMax == 0 + || ((DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10] + != DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].uid + || ((int)DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].size + < *(int*)((int)this + iVar6 + 0x15c))))))) { + + _recruitDefDiggingUnit = true; + } + + playerID = 0; + + if (0 < local_8) { + + do { + + if (_recruitDefDiggingUnit) { + + if (((byte)SEC_RNG::instance.currentNumber2 & 1) != 0) { + + _recruitDefDiggingUnit = false; + + goto LAB_004d3cc1; + } + + if (DAT_GameState::instance.playerDataArray[_playerID2].barracks.id == 0) { + + if (DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id == 0) { + + return; + } + + /* + DefDiggingUnit */ + + _unitType = *(UnitType*)((int)this + iVar6 + 0x160); + + } + + else { + + /* + DefDiggingUnit */ + + _unitType = *(UnitType*)((int)this + iVar6 + 0x160); + } + + } + + else { + + LAB_004d3cc1: + _unitTypeChoice + = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; + + if (_unitTypeChoice == OpenSHC::AI::AIRUC_DEFENSIVE) { + + if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex) { + + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; + } + + /* + DefUnit 1 up to 8 */ + + if (*(int*)((int)this + + (DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex + + iVar4) + * 4 + + 0x184) + == 0) { + + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; + } + + _unitChoiceIndex + = DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex; + + /* + DefUnit 1 up to 8 */ + + _unitType = *(UnitType*)((int)this + (iVar4 + _unitChoiceIndex) * 4 + 0x184); + + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex + = _unitChoiceIndex + 1; + + } + + else if (_unitTypeChoice == OpenSHC::AI::AIRUC_RAIDING) { + + if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex) { + + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; + } + + if (*(int*)((int)this + + (DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex + + iVar4) + * 4 + + 0x1ac) + == 0) { + + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; + } + + iVar5 = DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex; + + _unitType = *(UnitType*)((int)this + (iVar4 + iVar5) * 4 + 0x1ac); + + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = iVar5 + 1; + + } + + else if (_unitTypeChoice == OpenSHC::AI::AIRUC_ATTACKING) { + + _pAICState = (AICState*)MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::randomlySelectAttackUnitTypeToRecruit, this)( + _playerID2); + + _unitType + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getUnitTypeForUnitBehaviourType, + this)(_playerID2, (AIUnitBehaviourType)((int)(_pAICState))); + } + } + + if (_unitType == ((UnitType)0)) { + + return; + } + + if (_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) { + + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; + + } + + else if (_unitType == OpenSHC::Map::Units::UT_E_LADDER) { + + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; + + } + + else if (_unitType == OpenSHC::Map::Units::UT_TUNNELER) { + + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].tunnelersGuild.id; + + } + + else if (_unitType == OpenSHC::Map::Units::UT_E_MONK) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(_playerID2, OpenSHC::Map::Buildings::BT_CATHEDRAL); + + } + + else if ((int)_unitType < 0x46) { + + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].barracks.id; + + } + + else { + + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id; + } + + if (_buildingID == 0) { + + return; + } + + if ((((_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) + || (_unitType == OpenSHC::Map::Units::UT_E_LADDER)) + || (_unitType == OpenSHC::Map::Units::UT_TUNNELER)) + || ((_unitType == OpenSHC::Map::Units::UT_E_MONK || (0x45 < (int)_unitType)))) { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); + + } + + else { + + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); + } + + if (_unitID == 0) { + + /* + tradeAmountEquipment */ + + iVar6 = *(int*)((int)this + iVar6 + 0x9c); + + if (iVar6 < 1) { + + return; + } + + if (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason != 2) { + + return; + } + + if (DAT_GameState::instance.playerDataArray[_playerID2].aiNervousActionsTracker < 1) { + + DAT_GameState::instance.playerDataArray[_playerID2] + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] + = iVar6; + + return; + } + + DAT_GameState::instance.playerDataArray[_playerID2] + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = 5; + + return; + } + + if (_recruitDefDiggingUnit) { + + /* + digging units? */ + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); + + } + + else { + + AVar2 = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; + + /* + 0 = defensive, 1 = raid, 2 = army */ + + if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { + + if (DAT_GameState::instance.playerDataArray[_playerID2].totalDefensiveTroopsUnk + < *(int*)((int)this + iVar6 + 0x180)) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignUnitToATribe, this)(_unitID); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToSmallestPatrolTribe, this)( + _unitID); + } + + } + + else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignUnitToDefensiveTribe, this)( + _unitID); + + } + + else if (AVar2 == OpenSHC::AI::AIRUC_ATTACKING) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToItsTribe, this)( + _unitID, (int)((int)(_pAICState))); + } + } + + playerID = playerID + 1; + + if (local_8 <= playerID) { + + return; + } + + } while (true); + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp b/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp new file mode 100644 index 000000000..74dfe4fde --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp @@ -0,0 +1,69 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1950 + void AICState ::aiRegisterTribeAndAssignTarget(int tribeID, int tribeUID) + + { + + int _index; + + short* _tribe; + + int* _uid; + + if (DAT_TribesState::instance.tribes[tribeID].size < 1) { + + DAT_TribesState::instance.tribes[tribeID].tribeState = 3; + + return; + } + + if (DAT_GameState::instance.playerDataArray[DAT_TribesState::instance.tribes[tribeID].owner].aiType + != OpenSHC::AI::AIT_NULL) { + + _index = 0; + + _uid = this->tribeUIDArray; + + _tribe = this->tribeIDArray; + + do { + + if ((*_tribe == 0) || (DAT_TribesState::instance.tribes[*_tribe].uid != *_uid)) { + + this->tribeIDArray[_index] = (short)tribeID; + + this->tribeUIDArray[_index] = tribeUID; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTargetForTribeBasedOnTargetChoiceLogic, this)( + DAT_TribesState::instance.tribes[tribeID].owner, tribeID); + + return; + } + + _index = _index + 1; + + _tribe = _tribe + 1; + + _uid = _uid + 1; + + } while (_index < 1000); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp new file mode 100644 index 000000000..a1c8bb331 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp @@ -0,0 +1,147 @@ +#include "OpenSHC/AI/AICState.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_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Buildings::BuildingType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CB3A0 + undefined4 AICState ::aiRequiresExtraOxtethers(int playerID) + + { + + int* piVar1; + + int _buildingID; + + int _oxTetherCount; + + int _linkedTetherID; + + short* _linkedTetherIDs; + + int _linkedTetherCount; + + int _oxTetherLoopIndex; + + int _quarryID; + + int _stoneWaiting; + + int _playerID; + + _playerID = playerID; + + _buildingID + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_QUARRY); + + _quarryID = 0; + + /* + reuse of playerID!! */ + + playerID = 0; + + _oxTetherCount = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(_playerID, OpenSHC::Map::Buildings::BT_OXTETHER, 1); + + if (9 < _oxTetherCount) { + + return (undefined4)(0); + } + + piVar1 = &DAT_GameState::instance.playerDataArray[_playerID].highestLoadedQuarryUnk; + + *piVar1 = 0; + + if (_buildingID != 0) { + + do { + + _stoneWaiting + = DAT_BuildingsState::instance + .buildings[(short)DAT_BuildingsState::instance.buildings[_buildingID].quarryStockpileID] + .resourceStone; + + _linkedTetherCount = 0; + + _linkedTetherIDs = DAT_BuildingsState::instance.buildings[_buildingID].quarryLinkedOxTethers; + + _oxTetherLoopIndex = 3; + + do { + + _linkedTetherID = (int)*_linkedTetherIDs; + + if (_linkedTetherID != 0) { + + if ((DAT_BuildingsState::instance.buildings[_linkedTetherID].buildingType + == OpenSHC::Map::Buildings::BT_OXTETHER) + && (DAT_BuildingsState::instance.buildings[_linkedTetherID].oxtetherLinkedQuarryID + == _buildingID)) { + + _linkedTetherCount = _linkedTetherCount + 1; + + } + + else { + + *_linkedTetherIDs = 0; + } + } + + _linkedTetherIDs = _linkedTetherIDs + 1; + + _oxTetherLoopIndex = _oxTetherLoopIndex + -1; + + } while (_oxTetherLoopIndex != 0); + + if (_linkedTetherCount < 1) { + + *piVar1 = _buildingID; + + return (undefined4)(1); + } + + /* + store the highest ratio of stone in quarry stockpile divided by linked ox + tethers */ + + if (playerID < _stoneWaiting / _linkedTetherCount) { + + playerID = _stoneWaiting / _linkedTetherCount; + + _quarryID = _buildingID; + } + + _buildingID + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findNextBuildingForPlayerAndType, + DAT_BuildingsState::ptr)(_playerID, OpenSHC::Map::Buildings::BT_QUARRY, _buildingID); + + } while (_buildingID != 0); + + /* + if the highest ratio is larger than 20, return true */ + + if (20 < playerID) { + + *piVar1 = _quarryID; + + return (undefined4)(1); + } + } + + return (undefined4)(0); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp new file mode 100644 index 000000000..d2308602d --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -0,0 +1,123 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + doc:| + Retreat units to campfire or keep + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE4D0 + void AICState ::aiRetreatUnits(short* playerID) + + { + + BOOLEnum BVar1; + + int _counter; + + int _tribeID; + + int* local_8; + + int _aiBehaviourType; + + int _groupCount; + + short* _playerID; + + _playerID = playerID; + + if (DAT_GameState::instance.playerDataArray[(int)playerID].aiType != OpenSHC::AI::AIT_NULL) { + + local_8 = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + _groupCount = *local_8; + + _aiBehaviourType = (*(int (*)[2])(local_8 + -1))[0]; + + _counter = 0; + + if (0 < _groupCount) { + + playerID = DAT_GameState::instance.playerDataArray[(int)_playerID].aiTribeIDs + _aiBehaviourType; + + do { + + _tribeID = (int)*playerID; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[(int)_playerID] + .aiTribeUIDs[_counter + _aiBehaviourType])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + if (_aiBehaviourType == 0xbe) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, (int)((int)(_playerID))); + + } + + else if (_aiBehaviourType == 0xd) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, (int)((int)(_playerID))); + + } + + else { + + BVar1 + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + + if (BVar1 == FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( + _tribeID, (int)((int)(_playerID))); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, (int)((int)(_playerID))); + } + } + } + + playerID = playerID + 1; + + _counter = _counter + 1; + + } while (_counter < _groupCount); + } + + local_8 = local_8 + 2; + + } while ((int)local_8 < 0xb42a2c); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp new file mode 100644 index 000000000..173aa0643 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp @@ -0,0 +1,112 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.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_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Game::GameMode2; + using OpenSHC::Game::Player::PlayerData; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDCF0 + BOOLEnum AICState ::aiShouldAttackOrWaitForTeamCoordination(int playerID) + + { + + AITypeInt _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) { + return FALSE; + } + + if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 1) { + return TRUE; + } + + int _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + if (DAT_GameState::instance.playerDataArray[_attackedPlayerID].totalTroopValue < 100) { + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 0; + } + + int _attForceBase = *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 500); + int _currentWaveStrength = DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; + int _totalAttack = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops; + + if (_totalAttack < _attForceBase + _currentWaveStrength) { + return FALSE; + } + + if (DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel == 0) { + return TRUE; + } + + int _readyTeamMembers = 0; + int _unreadyTeamMembers = 0; + int _iPlayer = 1; + PlayerData* _pPlayerData = &DAT_GameState::instance.playerDataArray[1]; + + do { + if (_iPlayer != playerID) { + int _isAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_iPlayer); + if (_isAlive != 0) { + BOOLEnum _isAI = MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, + DAT_GameSynchronyState::ptr)(_iPlayer); + if (_isAI != FALSE) { + if (DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + if (_pPlayerData->aiPlayerState != 0) { + return TRUE; + } + if (_pPlayerData->totalAttackTroops - _pPlayerData->totalAttackingEngineerTroops + < *(int*)((int)DAT_EntityState::instance.seagullArray + _pPlayerData->aiType * 0x2a4 + + 0x2664) + + _pPlayerData->currentWaveRandomAttackingStrength) { + _unreadyTeamMembers = _unreadyTeamMembers + 1; + } + else { + _readyTeamMembers = _readyTeamMembers + 1; + } + } + } + } + } + _iPlayer = _iPlayer + 1; + _pPlayerData = _pPlayerData + 1; + } while (_iPlayer < 9); + + if (_readyTeamMembers >= DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel) { + return TRUE; + } + if (_unreadyTeamMembers == 0) { + return TRUE; + } + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience = + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience + 1; + if (DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience <= 0x30 + || (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CAMPAIGN_MISSION)) { + return FALSE; + } + + return TRUE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp new file mode 100644 index 000000000..8bf86d291 --- /dev/null +++ b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp @@ -0,0 +1,157 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CAEA0 + void AICState ::aiUpdateTaxesAndRations(int playerID) + { + int _offset; + int _newTaxesVal; + int _newTaxes; + int _popularity; + int _currentTaxes; + int _taxesMin; + int _taxesMax; + int _peasants; + int _decision; + int _totalFood_2; + int _totalFood_1; + int _taxes; + AITypeInt _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) { + return; + } + + _offset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + + _popularity = DAT_GameState::instance.playerDataArray[playerID].popularity; + + // criticalPopularity - comparison order matches original: first jg sets decision=2 (critical) + if (*(int*)((int)this + _offset + 0x18) >= _popularity) { + DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 2; + } else if (*(int*)((int)this + _offset + 0x1c) < _popularity) { + // highestPopularity + if (*(int*)((int)this + _offset + 0x20) >= _popularity) { + DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 0; + } + } else { + DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 1; + } + + _decision = DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue; + + if (_decision == 2) { + _totalFood_2 = DAT_GameState::instance.playerDataArray[playerID].totalFood; + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 2; + + if (_totalFood_2 <= 0) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; + } else if (_totalFood_2 < 5) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; + } else { + int _r = 0; + if (_totalFood_2 > 8) _r = 1; + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = _r + 3; + } + + goto LAB_004cb010; + } + + if (_decision == 1) { + _currentTaxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; + _taxesMin = *(int*)((int)this + _offset + 0x24); + + if (_taxesMin < _currentTaxes) { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _currentTaxes - 1; + } else { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxesMin; + } + + _totalFood_1 = DAT_GameState::instance.playerDataArray[playerID].totalFood; + + if (_totalFood_1 <= 0) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; + } else { + if (_totalFood_1 <= 0xa) + goto LAB_004caff1; + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 3; + } + } else { + if (_decision != 0) + goto LAB_004cb010; + + _taxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; + _taxesMax = *(int*)((int)this + _offset + 0x28); + + if (_taxes < _taxesMax) { + _peasants = DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants; + int _r2 = 0; + if (_peasants < 0xf) { + if (_peasants >= 0xa) _r2 = 1; + _newTaxesVal = _r2 + 4; + } else { + _newTaxesVal = 6; + } + + if (DAT_GameState::instance.playerDataArray[playerID].storedPopularityPercent > _popularity) { + if (_taxes <= _newTaxesVal) + goto LAB_004cafcd; + _newTaxes = _taxes - 1; + } else { + _newTaxes = _taxes + 1; + } + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _newTaxes; + } else { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxesMax; + } + + LAB_004cafcd: + _totalFood_1 = DAT_GameState::instance.playerDataArray[playerID].totalFood; + + if (_totalFood_1 < 0xb) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; + goto LAB_004cb010; + } + + LAB_004caff1: + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; + } + + _newTaxes = *(int*)((int)this + _offset + 0xa8); + + if ((_newTaxes != 0) && (_newTaxes <= _totalFood_1)) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; + } + + LAB_004cb010: + if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting < 0) { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 0; + } + + if (11 < DAT_GameState::instance.playerDataArray[playerID].taxesSetting) { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 11; + } + + if (DAT_GameState::instance.playerDataArray[playerID].rationsSetting < 0) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; + } + + if (4 < DAT_GameState::instance.playerDataArray[playerID].rationsSetting) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; + } + + return; + } +} +} diff --git a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp index 5cbcef48a..f3cfc8926 100644 --- a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp +++ b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp @@ -41,7 +41,8 @@ namespace AI { MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); return; } - _tribeID = MACRO_CALL_MEMBER(AICState_Func::smallestTribeOfUnitType, this)(_playerID, _unitTypeIndex); + _tribeID = MACRO_CALL_MEMBER(AICState_Func::smallestTribeOfUnitType, this)( + _playerID, (OpenSHC::Map::Units::UnitType)((int)_unitTypeIndex)); MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); } } diff --git a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp new file mode 100644 index 000000000..27cb9b4c3 --- /dev/null +++ b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp @@ -0,0 +1,129 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" +#include "OpenSHC/Game/Resources/ResourceTypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Game::Resources::ResourceType; + using OpenSHC::Game::Resources::ResourceTypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + Walks the AIC resource acquisition preference order (up to 25 entries in + DAT_ResourceAcquisitionPreferenceOrder) and attempts to buy the first resource for which the + player has a non-zero resourcesToAcquireArray entry and meets one of the spending conditions: + popularity is below the AIC minimum threshold (only checked for the first 4 entries), the AI is + nervous, or the canStartSpending flag is set. If the AI is nervous, entries 0-11 (non-weapon + resources) are skipped entirely so it only buys weapons. A special override fires first inside + the loop: if the building-destroy tracker is non-zero AND the player has fewer than 20 wood, the + resource type is forced to RT_WOOD regardless of the preference order. Before calling buyGoods() + the required gold is computed via getBuyPrice(); if the AI cannot afford the purchase it calls + requestGoods() from a teammate at double the desired amount instead. On a successful purchase + resourcesToAcquireArray for that resource is cleared and the function returns immediately, + buying at most one resource type per call. */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D39B0 + void AICState ::buyRequiredGoods(int param_1) + + { + + AITypeInt AVar1; + + int amount; + + int playerID; + + int iVar2; + + BOOLEnum BVar3; + + ResourceTypeInt resourceType; + + playerID = param_1; + + /* + buying */ + + AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + + return; + } + + /* + reused! playerID now means a counter */ + + param_1 = 0; + + do { + + resourceType = DAT_SkirmishDefinedData::instance.DAT_ResourceAcqusitionPreferenceOrder[param_1]; + + /* + If nervous, only buy from entry 12 onwards, which are weapons */ + + if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) || (12 < param_1)) { + + if ((DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker != 0) + && (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] < 20)) { + + /* + if short on wood, buy wood! */ + + resourceType = OpenSHC::Game::Resources::RT_WOOD; + } + + amount = DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType]; + + if ((amount != 0) + && ((((param_1 < 4 + && (DAT_GameState::instance.playerDataArray[playerID].popularity + < *(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x18))) + || (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker)) + || (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)))) { + + iVar2 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::getBuyPrice, DAT_GameState::ptr)( + playerID, (int)((int)(resourceType)), amount); + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < iVar2) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::requestGoods, this)( + playerID, (ResourceType)((int)(resourceType)), amount * 2); + + } + + else { + + BVar3 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::buyGoods, this)( + playerID, (ResourceType)((int)(resourceType)), amount); + + if (BVar3 != FALSE) { + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType] = 0; + + return; + } + } + } + } + + param_1 = param_1 + 1; + + } while (param_1 < 25); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp new file mode 100644 index 000000000..595a02e11 --- /dev/null +++ b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp @@ -0,0 +1,105 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingTypeInt.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Buildings::BuildingTypeInt; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDB20 + int AICState ::chooseRandomBuildingIDFromPlayersArrayOfBuildings(int playerID) + + { + + int _chosenBuilding; + + int _selectionIndex; + + int _chosenBuildingTypeIndex; + + short* _ptr_buildingIDArray; + + int _buildingID; + + BuildingTypeInt _buildingType; + + bool bVar1; + + _selectionIndex = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + + _chosenBuilding = 0; + + _chosenBuildingTypeIndex = 46; + + if (0 < _selectionIndex) { + + _ptr_buildingIDArray = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings; + + playerID = _selectionIndex; + + do { + + _buildingID = (int)*_ptr_buildingIDArray; + + if ((_buildingID != 0) && (_selectionIndex = 0, 0 < _chosenBuildingTypeIndex)) { + + _buildingType + = (BuildingTypeInt)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType; + + do { + + if (((byte)SEC_RNG::instance.currentNumber2 & 7) < 2) { + + bVar1 = _buildingType + == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet3[_selectionIndex]; + + } + + else if (((byte)SEC_RNG::instance.currentNumber2 & 7) < 4) { + + bVar1 = _buildingType + == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet2[_selectionIndex]; + + } + + else { + + bVar1 = _buildingType + == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_selectionIndex]; + } + + if (bVar1) { + + /* + very unique way to break from a loop ;) */ + + _chosenBuilding = _buildingID; + + _chosenBuildingTypeIndex = _selectionIndex; + } + + _selectionIndex = _selectionIndex + 1; + + } while (_selectionIndex < _chosenBuildingTypeIndex); + } + + _ptr_buildingIDArray = _ptr_buildingIDArray + 1; + + playerID = playerID + -1; + + } while (playerID != 0); + } + + return _chosenBuilding; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp new file mode 100644 index 000000000..91ef8a70c --- /dev/null +++ b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp @@ -0,0 +1,67 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF870 + void AICState ::clearOutdatedAITribes(int playerID) + + { + + if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { + + int _index = 0; + + do { + + if (_index != 8) { + + int _groupCount + = DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[_index][1]; + + int _tribeType + = DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[_index][0]; + + int _offset = 0; + + if (0 < _groupCount) { + + short* _ptrTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeType; + + do { + int _tribeIDVal = (int)*_ptrTribeID; + if ((_tribeIDVal != 0) + && (DAT_TribesState::instance.tribes[_tribeIDVal].uid + != DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_offset + _tribeType])) { + + *_ptrTribeID = 0; + + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_offset + _tribeType] = 0; + } + + _offset = _offset + 1; + + _ptrTribeID = _ptrTribeID + 1; + + } while (_offset < _groupCount); + } + } + + _index = _index + 1; + + } while (_index < 0xb); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp new file mode 100644 index 000000000..ca0fa349b --- /dev/null +++ b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp @@ -0,0 +1,52 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Synchrony::GameSynchronyState; + + /* + 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 0x004CAC70 + void AICState ::clearPlayerDataInformationChunk() + + { + + GameSynchronyState* piVar1; + + int* _Dst; + + _Dst = &DAT_GameState::instance.playerDataArray[0].aiFarmIndex; + + piVar1 = (GameSynchronyState*)DAT_GameSynchronyState::instance.currentAIArray; + + do { + + if ((piVar1->currentPlayerFullIDArray[0] != -1) || (piVar1->currentAIArray[0] == 0)) { + + MACRO_CALL(OpenSHC::OS_Func::_memset)(_Dst, 0, (size_t)((int)(3748))); + } + + piVar1 = (GameSynchronyState*)(piVar1->currentAIArray + 1); + + _Dst = _Dst + 3709; + + } while ((int)piVar1 < 0x191dea0); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp new file mode 100644 index 000000000..548106804 --- /dev/null +++ b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp @@ -0,0 +1,89 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE790 + void AICState ::clearRallyFlagOnAllAIAttackTribes(int param_1) + + { + + int _tribeID; + + int _counter; + + short* _ptrTribeID; + + int* _ptrTribeCount; + + int _tribeCount; + + int _tribeType; + + if (DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) { + + _ptrTribeCount + = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + /* + first iteration: 3 */ + + _tribeCount = *_ptrTribeCount; + + /* + first iteration: 186 */ + + _tribeType = (*(int (*)[2])(_ptrTribeCount + -1))[0]; + + /* + first iteration: 0 */ + + _counter = 0; + + if (0 < _tribeCount) { + + _ptrTribeID = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + _tribeType; + + do { + + _tribeID = (int)*_ptrTribeID; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1] + .aiTribeUIDs[_counter + _tribeType])) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, + DAT_TribesState::ptr)(_tribeID); + } + + _counter = _counter + 1; + + _ptrTribeID = _ptrTribeID + 1; + + } while (_counter < _tribeCount); + } + + _ptrTribeCount = _ptrTribeCount + 2; + + } while ((int)_ptrTribeCount < 0xb42a2c); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp b/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp new file mode 100644 index 000000000..d701a1a34 --- /dev/null +++ b/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp @@ -0,0 +1,68 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF7C0 + void AICState ::commandFourTribesToMove(int playerID) + + { + + if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { + + int _counter2 = 0; + + int _counter = 0; + + short* _ptrTribeIDArray = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xba; + + do { + + int _tribeID = (int)*_ptrTribeIDArray; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_counter + 0xba])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; + + /* + fixme: array too small? */ + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_counter2] + .xOffset)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_counter2] + .yOffset)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + _counter2 = _counter2 + 1; + } + + _counter = _counter + 1; + + _ptrTribeIDArray = _ptrTribeIDArray + 1; + + } while (_counter < 3); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp new file mode 100644 index 000000000..e73d9dff7 --- /dev/null +++ b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp @@ -0,0 +1,60 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Game::Player::PlayerData; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2EC0 + void AICState ::computeAttackPossibilities(int playerID) + + { + + PlayerData* piVar1; + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID]; + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIInfoLayer))); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackPrimeInfo, this)(playerID, piVar1->attackedPlayerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::recomputeTargetedBuildingTilesArray, + DAT_TroopValueState::ptr)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::recomputeAttackInfo, DAT_TroopValueState::ptr)( + playerID, piVar1->attackedPlayerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::computeSiegeSpotScores, DAT_TroopValueState::ptr)( + piVar1->attackedPlayerID, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setScale3, DAT_TroopValueState::ptr)(1, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setTown2, DAT_TroopValueState::ptr)(1, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setGate2, DAT_TroopValueState::ptr)(1, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setWide3, DAT_TroopValueState::ptr)(1, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setMoat3, DAT_TroopValueState::ptr)(1, playerID); + + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::calculateAttackVectorsToCampFireOfPlayer, + DAT_GameState::ptr)(piVar1->attackedPlayerID); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp new file mode 100644 index 000000000..3143812d5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp @@ -0,0 +1,173 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/AI/TileDistancePair.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::TileDistancePair; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE200 + void AICState ::computeEnemyKeepApproachTile(int playerID) + + { + + int _shortestDistanceTile; + + int _shortestDistanceX; + + TileDistancePair* _tilePointer; + + int iVar1; + + int* _distancePointer; + + int _shortestDistance; + + int local_c; + + int _keepX; + + int _keepY; + + int _tile; + + short _y; + + _keepX = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; + + _keepY = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; + + this->aiBorderTilesIndex = 0; + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 8000, '\0', (void*)((int)(this->aiBorderTiles))); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); + + local_c = 0; + + if (0 < this->aiBorderTilesIndex) { + + _distancePointer = &this->aiBorderTiles[0].distance; + + do { + + _tile = ((TileDistancePair*)(_distancePointer + -1))->tile; + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(_keepX, _keepY, + _tile + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance + .DAT_TileTranslationMatrix_YComponent[_tile]] + .addXgetTile, + (int)((int)(DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]))); + + /* + avoiding unit death areas */ + + *_distancePointer = (uint)DAT_TileMapState::instance.unitDeathHeatMap[_tile] + + DAT_DirectionAlgorithmState::instance.distanceHigh; + + local_c = local_c + 1; + + _distancePointer = _distancePointer + 2; + + } while (local_c < this->aiBorderTilesIndex); + } + + _shortestDistanceTile = 0; + + _shortestDistance = 100000; + + if (0 < this->aiBorderTilesIndex) { + + _tilePointer = this->aiBorderTiles; + + iVar1 = this->aiBorderTilesIndex; + + do { + + if (_tilePointer->distance < _shortestDistance) { + + _shortestDistanceTile = _tilePointer->tile; + + _shortestDistance = _tilePointer->distance; + } + + _tilePointer = _tilePointer + 1; + + iVar1 = iVar1 + -1; + + } while (iVar1 != 0); + } + + /* + sets the first attack distance to the enemy keep */ + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile = 0; + + if (0 < _shortestDistanceTile) { + + _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_shortestDistanceTile]; + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY = (int)_y; + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile = _shortestDistanceTile; + + _shortestDistanceX + = _shortestDistanceTile - DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX = _shortestDistanceX; + + DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][0] = _shortestDistanceX; + + DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][1] + = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY; + + if ((short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX] + != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)( + (int)(short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]); + } + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + DAT_PathFindingState::ptr)(DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][0], + (uint)((int)(DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][1])), -1, -1, 2000, + FALSE); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::storeDestinationOptionsUnk, + DAT_PathFindingState::ptr)(playerID + -1); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/computeNervousness.cpp b/src/OpenSHC/AI/AICState/computeNervousness.cpp new file mode 100644 index 000000000..2d0d9f26e --- /dev/null +++ b/src/OpenSHC/AI/AICState/computeNervousness.cpp @@ -0,0 +1,86 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3780 + void AICState ::computeNervousness(int playerID) + + { + + int iVar1; + + int _someCutoff; + + int _totalTroopValueOfEnemy; + + iVar1 = DAT_TroopValueState::instance.attackInfo.playerTotalTroopValueOfTroopsNearKeep[playerID]; + + _totalTroopValueOfEnemy = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; + + int _one = 1; + + if (_totalTroopValueOfEnemy < 50) { + + _someCutoff = _one - 0x15; + + } + + else if (_totalTroopValueOfEnemy < 100) { + + _someCutoff = 0; + + } + + else if (_totalTroopValueOfEnemy < 200) { + + _someCutoff = 20; + + } + + else if (_totalTroopValueOfEnemy < 400) { + + _someCutoff = 100; + + } + + else if (_totalTroopValueOfEnemy < 600) { + + _someCutoff = 200; + + } + + else { + + _someCutoff = ((_totalTroopValueOfEnemy >= 800) - _one & 0xffffff38) + 500; + } + + if (iVar1 > _someCutoff + _totalTroopValueOfEnemy) { + + DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue = 0; + + return; + } + + if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue == 0) { + + if (iVar1 < DAT_GameState::instance.playerDataArray[playerID] + .totalEnemyTroopValueByPlayerID[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playNervous1BikFromPlayer, this)(playerID); + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playRequestHelpBikFromPlayer, this)(playerID); + } + + DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue = _one; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp b/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp new file mode 100644 index 000000000..e58e36158 --- /dev/null +++ b/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp @@ -0,0 +1,63 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/Unit.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitTypeShort.hpp" + +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Unit; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::UnitTypeShort; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFBC0 + int AICState::countSiegeEngineUnits(int playerID) + { + int _count = 0; + Unit* _units = &DAT_UnitsState::instance.units[0]; + + for (int i = 1; i < 2500; i += 1) { + // Unit[1] + if (_units[i].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE && _units[i].owner == playerID + && _units[i].unknownSiegeTentRelated02 == 3 && _units[i].aiUnitBehaviourType != 0x15) { + UnitTypeShort t = _units[i].unitType; + if (t == OpenSHC::Map::Units::UT_S_CATAPULT || t == OpenSHC::Map::Units::UT_S_TREBUCHET + || t == OpenSHC::Map::Units::UT_S_TOWER || t == OpenSHC::Map::Units::UT_S_BATTERINGRAM + || t == OpenSHC::Map::Units::UT_S_FBALLISTA) { + _count = _count + 1; + } + } + + // Compiler unrolled the loop because 2499 is divisible by 3? + // // Unit[2] + // if (_units[i + 1].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE && _units[i + 1].owner == playerID + // && _units[i + 1].unknownSiegeTentRelated02 == 3 && _units[i + 1].aiUnitBehaviourType != 0x15) { + // UnitTypeShort t = _units[i + 1].unitType; + // if (t == OpenSHC::Map::Units::UT_S_CATAPULT || t == OpenSHC::Map::Units::UT_S_TREBUCHET + // || t == OpenSHC::Map::Units::UT_S_TOWER || t == OpenSHC::Map::Units::UT_S_BATTERINGRAM + // || t == OpenSHC::Map::Units::UT_S_FBALLISTA) { + // _count = _count + 1; + // } + // } + + // // Unit[3] + // if (_units[i + 2].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE && _units[i + 2].owner == playerID + // && _units[i + 2].unknownSiegeTentRelated02 == 3 && _units[i + 2].aiUnitBehaviourType != 0x15) { + // UnitTypeShort t = _units[i + 2].unitType; + // if (t == OpenSHC::Map::Units::UT_S_CATAPULT || t == OpenSHC::Map::Units::UT_S_TREBUCHET + // || t == OpenSHC::Map::Units::UT_S_TOWER || t == OpenSHC::Map::Units::UT_S_BATTERINGRAM + // || t == OpenSHC::Map::Units::UT_S_FBALLISTA) { + // _count = _count + 1; + // } + // } + }; + + return _count; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp new file mode 100644 index 000000000..59f8a77c5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp @@ -0,0 +1,287 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1A00 + void AICState ::decideOnTribeAttackLocation(uint tribeID_OR_moatWasHit) + + { + + short* psVar1; + + short sVar2; + + bool bVar3; + + BOOLEnum _canHaveActivity; + + int _unitID; + + BOOLEnum BVar4; + + int _targetBuilding; + + int _buildingID; + + int _buildingID_2; + + int iVar5; + + int _destinationX; + + int _targetPlayer; + + int _destinationY; + + int _y; + + int _x; + + int _buildingUID; + + int _rng; + + int _destinationTile; + + uint _tribeID; + + _tribeID = tribeID_OR_moatWasHit; + + _canHaveActivity + = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(tribeID_OR_moatWasHit, FALSE, TRUE); + + if (_canHaveActivity != FALSE) { + + DAT_TribesState::instance.tribes[_tribeID].counter = 0; + + return; + } + + _targetPlayer = (int)DAT_TribesState::instance.tribes[_tribeID].targetPlayer_outpost; + + if (DAT_TribesState::instance.tribes[_tribeID].randomNumber == 0) { + + DAT_TribesState::instance.tribes[_tribeID].randomNumber = (int)SEC_RNG::instance.currentNumber2; + + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + } + + _rng = DAT_TribesState::instance.tribes[_tribeID].randomNumber; + + psVar1 = &DAT_TribesState::instance.tribes[_tribeID].counter; + + *psVar1 = *psVar1 + 1; + + if ((int)DAT_TribesState::instance.tribes[_tribeID].counter == _rng % 6 + 7) { + + DAT_TribesState::instance.tribes[_tribeID].counter = 0; + + /* + WARNING: tribeID has a new purpose */ + + tribeID_OR_moatWasHit = tribeID_OR_moatWasHit & 0xffffff00; + + _x = 0; + + _y = 0; + + _unitID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::getUnitIDForIndexInTribe, DAT_TribesState::ptr)(_tribeID, 0); + + if ((_unitID != 0) + && (bVar3 = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, + DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[_tribeID].owner, _targetPlayer, + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), (byte*)&tribeID_OR_moatWasHit, + &_x, &_y), + bVar3)) { + + if ((char)tribeID_OR_moatWasHit != '\0') { + + /* + moat was not hit */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + _tribeID, ((UnitInstructionType)0x23), + DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile + _x, 0, 0); + + return; + } + + /* + moat was hit */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + _tribeID, OpenSHC::Map::Units::UIT_FILL_MOAT, _x, _y, 1000); + + return; + } + } + + sVar2 = DAT_TribesState::instance.tribes[_tribeID].tribeSubtype1; + + if ((sVar2 != 0xb6) && (sVar2 != 0xb9)) { + + BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, FALSE); + + if (BVar4 != FALSE) { + + return; + } + + _targetBuilding = (int)DAT_TribesState::instance.tribes[_tribeID].targetBuildingID; + + if ((((_targetBuilding != 0) + && (DAT_BuildingsState::instance.buildings[_targetBuilding].uid + == DAT_TribesState::instance.tribes[_tribeID].targetBuildingUID)) + && (DAT_BuildingsState::instance.buildings[_targetBuilding].fireDuration == 0)) + && (BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, TRUE), + BVar4 != FALSE)) { + + if (DAT_GameState::instance.mapAndTime.yearChanged == 0) { + + return; + } + + DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = 0; + + return; + } + + _buildingID = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + DAT_GameState::ptr)(_targetPlayer); + + if (_buildingID != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + _tribeID, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, _buildingID, + DAT_BuildingsState::instance.buildings[_buildingID].uid, 0); + + _buildingUID = DAT_BuildingsState::instance.buildings[_buildingID].uid; + + DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = (short)_buildingID; + + DAT_TribesState::instance.tribes[_tribeID].targetBuildingUID = _buildingUID; + + return; + } + + _destinationX = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; + + DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = 0; + + _destinationY = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry; + + BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(_tribeID, + DAT_ViewportRenderState::instance.translationMatrix[_destinationY].addXgetTile + _destinationX); + + if (BVar4 == FALSE) { + + return; + } + + goto LAB_004d1c59; + } + + _buildingID_2 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + DAT_GameState::ptr)(_targetPlayer); + + if (_buildingID_2 == 0) { + + iVar5 = DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] + .addXgetTile; + + LAB_004d1d11: + _destinationTile = iVar5 + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; + + } + + else { + + iVar5 = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; + + if (iVar5 == 0) { + + _destinationTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryY] + .addXgetTile; + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathfindingForAttacksUnk, + DAT_PathFindingState::ptr)(_tribeID, _buildingID_2, 1, + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance.units[iVar5].tile])), + _targetPlayer); + + _destinationTile = DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile1; + + if (DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper == 0) { + + iVar5 = DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer] + .campground.yEntry] + .addXgetTile; + + goto LAB_004d1d11; + } + } + } + + if (_destinationTile != 0) { + + _destinationY + = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_destinationTile]; + + _destinationX + = _destinationTile - DAT_ViewportRenderState::instance.translationMatrix[_destinationY].addXgetTile; + + BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( + _tribeID, _destinationTile); + + if (BVar4 != FALSE) { + + LAB_004d1c59: + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + _tribeID, (uint)((int)(_destinationX)), (uint)((int)(_destinationY)), 1); + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(_tribeID, _targetPlayer); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp index 85d25c03d..e34daac0d 100644 --- a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp +++ b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp @@ -14,24 +14,30 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB940 undefined4 AICState::destroyBuildingIfNoWorker(int buildingID) { - short _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; - int _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; + short _value; + int _owner; + _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; + _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; if ((((0 < _value) && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1)) && (DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0)) && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY)) { - if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] == 0) { - if (0x13 < _value) { - MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( - (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, - (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( - buildingID); - return 1; + if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] != 0) { +LAB_CHECK_MONTH: + if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { + DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = _value + -1; } - } else if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { - DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = _value + -1; + } else { + if (!((short)0x14 <= _value)) { + goto LAB_CHECK_MONTH; + } + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( + buildingID); + return 1; } } return 0; diff --git a/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp b/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp new file mode 100644 index 000000000..ecdd9457b --- /dev/null +++ b/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp @@ -0,0 +1,55 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D38C0 + BOOLEnum AICState ::determineAIPlayerAttackRequestResponse( + int playerID, undefined4 param_2, int requestedByPlayerID) + + { + + AITypeInt AVar1; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 != OpenSHC::AI::AIT_NULL) { + + if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue == 0) { + + if (DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops + < *(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x1fc)) { + + MACRO_CALL(OpenSHC::Global_Func::PlayWillNotAttack2BikFromPlayerToPlayer)( + playerID, requestedByPlayerID); + + return FALSE; + } + + MACRO_CALL(OpenSHC::Global_Func::PlayWillAttackBikFromPlayerToPlayer)(playerID, requestedByPlayerID); + + return TRUE; + } + + MACRO_CALL(OpenSHC::Global_Func::PlayWillNotAttack1BikFromPlayerToPlayer)(playerID, requestedByPlayerID); + } + + return FALSE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp b/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp new file mode 100644 index 000000000..41f1ba2ec --- /dev/null +++ b/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp @@ -0,0 +1,53 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3850 + BOOLEnum AICState ::determineAIPlayerHelp(int playerID, int requestedByPlayerID) + + { + + AITypeInt AVar1; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 != OpenSHC::AI::AIT_NULL) { + + if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue == 0) { + + if (DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + < *(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x1fc)) { + + MACRO_CALL(OpenSHC::Global_Func::PlayWillNotHelp2BikFromPlayerToPlayer)( + playerID, requestedByPlayerID); + + return FALSE; + } + + MACRO_CALL(OpenSHC::Global_Func::PlayWillHelpBikFromPlayerToPlayer)(playerID, requestedByPlayerID); + + return TRUE; + } + + MACRO_CALL(OpenSHC::Global_Func::PlayWillNotHelp1BikFromPlayerToPlayer)(playerID, requestedByPlayerID); + } + + return FALSE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp b/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp new file mode 100644 index 000000000..531b03abe --- /dev/null +++ b/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp @@ -0,0 +1,72 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/States/UnitState.hpp" +#include "OpenSHC/Map/Units/Unit.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitTypeShort.hpp" + +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Unit; + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::UnitTypeShort; + using OpenSHC::Map::Units::States::UnitState; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CFB20 + void AICState ::disbandAIPlayerSiegeUnits(int playerID) + + { + + Unit* _unit; + + int _unitIDCounter; + + UnitTypeShort _unitType; + + _unitIDCounter = 1; + + _unit = &DAT_UnitsState::instance.units[1]; + + do { + + if ((((_unit->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) && (_unit->owner == playerID)) + && (((_unitType = _unit->unitType, + _unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || (((_unitType == OpenSHC::Map::Units::UT_S_TREBUCHET + || (_unitType == OpenSHC::Map::Units::UT_S_TOWER)) + || (_unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM)))) + || ((_unitType == OpenSHC::Map::Units::UT_S_SHIELD + || (_unitType == OpenSHC::Map::Units::UT_S_FBALLISTA)))))) + && ((_unit->unknownSiegeTentRelated02 == 3 && (_unit->aiUnitBehaviourType != 0x15)))) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( + (int)_unit->tribeID, OpenSHC::Map::Units::UIT_EXIT_SIEGE_EQUIPMENT, _unitIDCounter, _unit->uid, 0); + + /* + shouldn't logicalState be set to something too? */ + + (_unit->state).generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } + + _unit = _unit + 0x248; + + _unitIDCounter = _unitIDCounter + 1; + + } while ((int)_unit < 0x165141a); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp new file mode 100644 index 000000000..68b449749 --- /dev/null +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -0,0 +1,117 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000This function finds the first active AI + attack tribe for a player (validating it's still alive via UID matching), then traces a path from + that tribe's position toward the player's own defenses, storing the resulting tile coordinates in + the player's game state. It's likely used by the AI to rally or redirect attacking forces — + perhaps pulling them back toward defensive structures when needed, or seeding a waypoint for a + retreat/regroup maneuver. */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE930 + void AICState ::findAttackTribePositionAndPathToDefenses(int playerID) + + { + + int iVar1; + + int _tile; + + int iVar2; + + short* psVar3; + + int* local_c; + + uint local_8; + + uint local_4; + + short _y; + + local_8 = 0; + + local_4 = 0; + + local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + iVar2 = 0; + + if (0 < *local_c) { + + psVar3 + = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + (*(int (*)[2])(local_c + -1))[0]; + + do { + + iVar1 = (int)*psVar3; + + if ((iVar1 != 0) + && (DAT_TribesState::instance.tribes[iVar1].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[iVar2 + (*(int (*)[2])(local_c + -1))[0]])) { + + iVar2 = (int)DAT_TribesState::instance.tribes[iVar1].selectionTargetUnitID; + + local_8 = (uint)DAT_UnitsState::instance.units[iVar2].x; + + local_4 = (uint)DAT_UnitsState::instance.units[iVar2].y; + + if (iVar2 != 0) + goto LAB_004ce9f1; + + break; + } + + iVar2 = iVar2 + 1; + + psVar3 = psVar3 + 1; + + } while (iVar2 < *local_c); + } + + local_c = local_c + 2; + + if (0xb42a2b < (int)local_c) { + + LAB_004ce9f1: + DAT_GameState::instance.playerDataArray[playerID].someTile = 0; + + if ((local_8 != 0) + && (_tile = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: + tracePathToFriendlyDefensesAndReturnTileUnk, + DAT_PathFindingState::ptr)(playerID, local_8, local_4), + 0 < _tile)) { + + _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + + DAT_GameState::instance.playerDataArray[playerID].someTile = _tile; + + iVar2 = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + + DAT_GameState::instance.playerDataArray[playerID].someY = (int)_y; + + DAT_GameState::instance.playerDataArray[playerID].someX = _tile - iVar2; + } + + return; + } + + } while (true); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp new file mode 100644 index 000000000..581d2e863 --- /dev/null +++ b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp @@ -0,0 +1,106 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Game/GameMode.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/Map/Units/UnitTypeShort.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Game::GameMode; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::Map::Units::UnitTypeShort; + + /* + 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 0x004CC420 + void AICState ::generateSiegeCreationInformation(int playerID, int buildingID, int unitID) + + { + + UnitTypeShort UVar1; + + int iVar2; + + int _siegeIndex; + + int _engineIndexUnk; + + int _nextIndex; + + int _goal; + + if ((DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) + && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != OpenSHC::Game::GM_SOLITARY)) { + + UVar1 = DAT_UnitsState::instance.units[unitID].unitType; + + if (UVar1 == OpenSHC::Map::Units::UT_S_TREBUCHET) { + + _siegeIndex = 2; + + } + + else { + + if (UVar1 != OpenSHC::Map::Units::UT_S_FBALLISTA) { + + return; + } + + _siegeIndex = 3; + } + + iVar2 = DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeIndex].slot; + + _goal = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[iVar2]; + + if (0 < _goal) { + + _engineIndexUnk = 0; + + while ((_nextIndex = _engineIndexUnk + 1, + *(int*)(playerID * 0x39f4 + iVar2 * 40 + 0x115eb14 + _engineIndexUnk * 4) < 1 + || (buildingID + != *(int*)(playerID * 0x39f4 + 0x115f494 + (_engineIndexUnk + _siegeIndex * 5) * 0x14)))) { + + _engineIndexUnk = _nextIndex; + + if (_goal <= _nextIndex) { + + return; + } + } + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeIndex][_engineIndexUnk] + .unitID = unitID; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeIndex][_engineIndexUnk] + .uid = DAT_UnitsState::instance.units[unitID].uid; + + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeIndex][_engineIndexUnk] + .buildingID = 0; + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp new file mode 100644 index 000000000..3b82b7d3d --- /dev/null +++ b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp @@ -0,0 +1,100 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CCAF0 + int AICState ::getSmallestPatrolTribe(int playerID, int tribeCount) + + { + + int _selectedTribeID; + + int _tribeID; + + int _tribeNumber; + + short* _pTribeID; + + int _selectedTribeNumber; + + short _lowestTribeUnitCount; + + short _tribeSize; + + _selectedTribeID = 0; + + _tribeNumber = 0; + + _selectedTribeNumber = 0; + + _lowestTribeUnitCount = 1000; + + if (0 < tribeCount) { + + _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; + + do { + + _tribeID = (int)*_pTribeID; + + if ((_tribeID == 0) + || (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeNumber + 0xaa])) { + + _selectedTribeID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + + _selectedTribeNumber = _tribeNumber; + + goto LAB_004ccb9d; + } + + _tribeSize = DAT_TribesState::instance.tribes[_tribeID].size; + + if (_tribeSize < _lowestTribeUnitCount) { + + _selectedTribeID = _tribeID; + + _selectedTribeNumber = _tribeNumber; + + _lowestTribeUnitCount = _tribeSize; + } + + _tribeNumber = _tribeNumber + 1; + + _pTribeID = _pTribeID + 1; + + } while (_tribeNumber < tribeCount); + + if (_selectedTribeID != 0) { + + LAB_004ccb9d: + /* + pTribeID = selectedTribeID */ + + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_selectedTribeNumber + 0xaa] + = (short)_selectedTribeID; + + /* + pTribeUID = selectedTribeUID */ + + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_selectedTribeNumber + 0xaa] + = DAT_TribesState::instance.tribes[_selectedTribeID].uid; + + return _selectedTribeID; + } + } + + return 0; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp new file mode 100644 index 000000000..5cb3f087a --- /dev/null +++ b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp @@ -0,0 +1,116 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/Map/Buildings/BuildingTypeInt.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Game::Player::PlayerData; + using OpenSHC::Map::Buildings::BuildingTypeInt; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDBC0 + int AICState ::getTargetableBuildingForPlayerID(int playerID, int param_2) + + { + + int* piVar1; + + PlayerData* pPVar2; + + int iVar3; + + int _candidateBuilding; + + BuildingTypeInt* _pTargets; + + int _index; + + int _aiType; + + int _outerPatrolGroupsCount; + + int _tracker; + + iVar3 = playerID; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if ((_aiType != 0) + && (_outerPatrolGroupsCount = *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x174), + 0 < _outerPatrolGroupsCount)) { + + _tracker = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + + if (0 < _tracker) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].someCounter2; + + *piVar1 = *piVar1 + 1; + + if (_tracker <= DAT_GameState::instance.playerDataArray[playerID].someCounter2) { + + DAT_GameState::instance.playerDataArray[playerID].someCounter2 = 0; + } + + pPVar2 = DAT_GameState::instance.playerDataArray + playerID; + + playerID = 0; + + _index = ((_tracker / _outerPatrolGroupsCount) * param_2 + pPVar2->someCounter2) % _tracker; + + if (0 < _tracker) { + + do { + + _candidateBuilding + = (int)DAT_GameState::instance.playerDataArray[iVar3].top100TargetableBuildings[_index]; + + _index = _index + 1; + + if (_tracker <= _index) { + + _index = 0; + } + + if (_candidateBuilding != 0) { + + _pTargets = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1; + + do { + + if ((int)(short)DAT_BuildingsState::instance.buildings[_candidateBuilding].buildingType + == *_pTargets) { + + return _candidateBuilding; + } + + _pTargets = _pTargets + 1; + + /* + Iterates only over resource buildings, so if resource building, return + */ + + } while ((int)_pTargets < 0xb427c8); + } + + playerID = playerID + 1; + + } while (playerID < _tracker); + } + } + + return 0; + } + + return 0; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp b/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp new file mode 100644 index 000000000..fcf4860b8 --- /dev/null +++ b/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp @@ -0,0 +1,118 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/AIUnitBehaviourType.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIUnitBehaviourType; + using OpenSHC::Map::Units::UnitType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC250 + UnitType AICState ::getUnitTypeForUnitBehaviourType(int playerID, AIUnitBehaviourType unitBehaviourType) + + { + + AITypeInt AVar1; + + int iVar2; + + UnitType UVar3; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + + return ((UnitType)0); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_ENGINEERING) { + + return OpenSHC::Map::Units::UT_E_ENGINEER; + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_DIGGING) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttDiggingUnit); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_ASSASSINATION) { + + return OpenSHC::Map::Units::UT_A_ASSASSIN; + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_ATTUNIT2) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnit2); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_LADDERING) { + + return OpenSHC::Map::Units::UT_E_LADDER; + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_TUNNELING) { + + return OpenSHC::Map::Units::UT_TUNNELER; + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_PATROLLING) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitPatrol); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_BACKUPING) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitBackup); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_ENGAGING) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitEngage); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_SIEGEDEFENSE) { + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitSiegeDef); + } + + if (unitBehaviourType == OpenSHC::AI::AIUBT_ATTUNITMAIN) { + + if (*(int*)((int)this->aics + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex * 4 + + AVar1 * 0x2a4 + -0x1c) + == 0) { + + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = 0; + } + + if (3 < DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex) { + + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = 0; + } + + iVar2 = DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex; + + /* + AttUnitMain[] */ + + UVar3 = *(UnitType*)((int)this->aics + AVar1 * 0x2a4 + iVar2 * 4 + -0x1c); + + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = iVar2 + 1; + + return UVar3; + } + + return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitMain1); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp new file mode 100644 index 000000000..b9bce3061 --- /dev/null +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp @@ -0,0 +1,106 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CEB50 + void AICState ::giveMoveCommandToAttackTribes(int playerID) + + { + + int _aiTribeID; + + int _counter; + + int _groupCounter; + + int* _ptrGroupCount; + + int _groupCount; + + int _playerID; + + int _tribeType; + + _playerID = playerID; + + if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { + + _counter = 0; + + _ptrGroupCount + = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + _tribeType = (*(int (*)[2])(_ptrGroupCount + -1))[0]; + + _groupCount = *_ptrGroupCount; + + if ((((_tribeType != 18) && (_tribeType != 190)) && (_tribeType != 15)) + && (_groupCounter = 0, 0 < _groupCount)) { + + /* + fixme: param reusage */ + + playerID = (_playerID * 0x1cfa + _tribeType) * 2 + 0x115ef04; + + do { + + _aiTribeID = (int)*(short*)playerID; + + if ((_aiTribeID != 0) + && (DAT_TribesState::instance.tribes[_aiTribeID].uid + == DAT_GameState::instance.playerDataArray[_playerID] + .aiTribeUIDs[_groupCounter + _tribeType])) { + + /* + bug: why give a random unit stance? */ + + DAT_TribesState::instance.tribes[_aiTribeID].unitStance + = (short)(char)((byte)SEC_RNG::instance.currentNumber2 & 1); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(_aiTribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[_playerID * 5][_counter] + .xOffset)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[_playerID * 5][_counter] + .yOffset)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + _counter = _counter + 1; + } + + playerID = playerID + 2; + + _groupCounter = _groupCounter + 1; + + } while (_groupCounter < _groupCount); + } + + _ptrGroupCount = _ptrGroupCount + 2; + + } while ((int)_ptrGroupCount < 0xb42a2c); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp new file mode 100644 index 000000000..6c36b0a2e --- /dev/null +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp @@ -0,0 +1,105 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD8F0 + void AICState ::giveMoveCommandToSortieUnits(int playerID) + + { + + int iVar1; + + int _tribeID; + + int _aiType; + + int _unitID; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == 0) { + return; + } + + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa7]; + + if (_tribeID == 0) { + return; + } + + if (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa7]) { + return; + } + + if ((int)DAT_TribesState::instance.tribes[_tribeID].size + < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 + -1) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::syncBehaviourType7UnitTribes, this)(playerID); + } + + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { + goto LAB_sendToKeep; + } + + /* + SortieUnitMeleeMin */ + + if ((int)DAT_TribesState::instance.tribes[_tribeID].size + < *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x154)) + goto LAB_004cda3c; + + _unitID = DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitID; + + if (((_unitID != 0) + && (DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitUID + == DAT_UnitsState::instance.units[_unitID].uid)) + && (iVar1 = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, + (dword)(( + int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID] + .tile])), + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance.units[_unitID].tile])), + 0), + iVar1 != 0)) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, + DAT_TribesState::ptr)(_tribeID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(_tribeID, (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + return; + } + + LAB_sendToKeep: + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); + + LAB_004cda3c: + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp new file mode 100644 index 000000000..0228ab5f7 --- /dev/null +++ b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp @@ -0,0 +1,70 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF920 + undefined4 AICState ::giveSomeRaidCommand(int tribeIndex, int tribeType) + + { + + int _chosenBuildingID; + + int _targetBuildingID; + + int _attacked; + + _targetBuildingID = (int)DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID; + + if ((((tribeType != 0xba) && (tribeType != 0x12)) && (tribeType != 0xe)) && (tribeType != 0xd)) { + + if (((_targetBuildingID != 0) + && (DAT_BuildingsState::instance.buildings[_targetBuildingID].uid + == DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID)) + && (DAT_BuildingsState::instance.buildings[_targetBuildingID].fireDuration == 0)) { + + return (undefined4)(1); + } + + _attacked = DAT_GameState::instance.playerDataArray[DAT_TribesState::instance.tribes[tribeIndex].owner] + .attackedPlayerID; + + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = 0; + + _chosenBuildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)(_attacked); + + if (_chosenBuildingID != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::queueDisbandAndAttackCommand4Params, + DAT_UnitsState::ptr)(tribeIndex, 9, (undefined4)((int)(_chosenBuildingID)), + (undefined4)((int)(DAT_BuildingsState::instance.buildings[_chosenBuildingID].uid))); + + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID + = DAT_BuildingsState::instance.buildings[_chosenBuildingID].uid; + + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = (short)_chosenBuildingID; + + DAT_TribesState::instance.tribes[tribeIndex].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + + return (undefined4)(1); + } + } + + return (undefined4)(0); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp index 32fca0836..d550e65f5 100644 --- a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp +++ b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp @@ -8,43 +8,46 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CFFD0 BOOLEnum AICState::hasNoTroopsOrAllAreDiggers(int playerID) { - int _totalBackup; - int _totalBackup2; - int _total1; int _totalTroops; int _halfOfDiggingTroops; - int _totalBackupLate; - int _totalBackupLate2; - _total1 = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + int _totalMisc = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops; _halfOfDiggingTroops = 0; if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState == 6) { - if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 17) { - _totalBackup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + _totalMisc += DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops; + int _attackTicker = DAT_GameState::instance.playerDataArray[playerID].attackTicker; + int _backup; + if (_attackTicker > 0x10) { + int _bp = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + _backup = (_bp + (_bp >> 0x1f & 7)) >> 3; } else { - _totalBackupLate = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - _totalBackup = (int)(_totalBackupLate + (_totalBackupLate >> 0x1f & 7U)) >> 3; + _backup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; } - _totalTroops = _total1 + DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops - + _totalBackup + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + _totalMisc += _backup; + _totalTroops = _totalMisc + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops - + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops; } else { - _halfOfDiggingTroops = DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops / 2; - if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 13) { - _totalBackup2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + int _digging = DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops; + _halfOfDiggingTroops = _digging / 2; + int _attackTicker = DAT_GameState::instance.playerDataArray[playerID].attackTicker; + int _backup; + if (_attackTicker > 0xc) { + int _bp2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + _backup = (_bp2 + (_bp2 >> 0x1f & 7)) >> 3; } else { - _totalBackupLate2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - _totalBackup2 = (int)(_totalBackupLate2 + (_totalBackupLate2 >> 0x1f & 7U)) >> 3; + _backup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; } - _totalTroops = _total1 + _totalBackup2 - + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + _totalMisc += _backup; + _totalTroops = _totalMisc + + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops - + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops; + + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops; } - if ((1 < _totalTroops) && ((4 < _totalTroops || (_halfOfDiggingTroops <= _totalTroops * 2)))) { + if ((1 < _totalTroops) && ((4 < _totalTroops) || (_halfOfDiggingTroops <= _totalTroops + _totalTroops))) { return FALSE; } return TRUE; diff --git a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp new file mode 100644 index 000000000..414d34b99 --- /dev/null +++ b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp @@ -0,0 +1,116 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD7B0 + void AICState ::instructTribe166ToMove(int playerID) + + { + + BOOLEnum _keepEnclosed; + + int _tribeID; + + int _counter; + + AITypeInt _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) { + + return; + } + + _counter = DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01; + + if (0 < _counter) { + + DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 = _counter + -1; + } + + if (50 < DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01) { + + DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 = 50; + } + + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; + + _keepEnclosed = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + + if (_tribeID == 0) { + + return; + } + + if (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa6]) { + + return; + } + + if ((int)DAT_TribesState::instance.tribes[_tribeID].size + < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 + -5) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitsToTribe166, this)(playerID); + } + + if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) + || (_keepEnclosed != FALSE)) { + + /* + SortieUnitRangedMin */ + + if ((int)DAT_TribesState::instance.tribes[_tribeID].size + < *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x14c)) + goto LAB_004cd86b; + + if ((0 < DAT_GameState::instance.playerDataArray[playerID].someXPosition) + && (0 < DAT_GameState::instance.playerDataArray[playerID].someYPosition)) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, + DAT_TribesState::ptr)(_tribeID); + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, + (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someXPosition)), + (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someYPosition)), 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + return; + } + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); + + LAB_004cd86b: + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp index 8168e916d..17c068b42 100644 --- a/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp +++ b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp @@ -8,15 +8,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D3960 void AICState::makeOutpostTribesAttack() { - uint _tribeID; - int _countDown; - short* _tribeIDs; - int* _tribeUIDs; - _tribeUIDs = this->tribeUIDArray; - _tribeIDs = this->tribeIDArray; - _countDown = 1000; + int* _tribeUIDs = this->tribeUIDArray; + short* _tribeIDs = this->tribeIDArray; + int _countDown = 1000; do { - _tribeID = (uint)*_tribeIDs; + unsigned int _tribeID = (uint)*_tribeIDs; if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid == *_tribeUIDs)) { MACRO_CALL_MEMBER(AICState_Func::decideOnTribeAttackLocation, this)(_tribeID); } diff --git a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp new file mode 100644 index 000000000..4c1c47ab2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp @@ -0,0 +1,100 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CEA50 + void AICState ::makeUnitsGoDefensiveAndBackToSomeLocation(int param_1) + + { + + int iVar1; + + int iVar2; + + int _commandResult; + + short* psVar3; + + int tribeID; + + int iVar4; + + int* local_c; + + uint _x; + + if ((DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) + && (DAT_GameState::instance.playerDataArray[param_1].someTile != 0)) { + + local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + iVar1 = *local_c; + + iVar2 = (*(int (*)[2])(local_c + -1))[0]; + + iVar4 = 0; + + if (0 < iVar1) { + + psVar3 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + iVar2; + + do { + + tribeID = (int)*psVar3; + + if ((tribeID != 0) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar4 + iVar2])) { + + _x = DAT_GameState::instance.playerDataArray[param_1].someX; + + DAT_TribesState::instance.tribes[tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + + _commandResult = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, _x, (uint)((int)(DAT_GameState::instance.playerDataArray[param_1].someY)), 0, + 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + if (_commandResult == 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::removeAllTribeUnits, + DAT_TribesState::ptr)(tribeID); + } + } + + iVar4 = iVar4 + 1; + + psVar3 = psVar3 + 1; + + } while (iVar4 < iVar1); + } + + local_c = local_c + 2; + + } while ((int)local_c < 0xb42a2c); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp new file mode 100644 index 000000000..46999d708 --- /dev/null +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -0,0 +1,104 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE830 + void AICState ::moveAttackTribesToLocations(short* playerID) + + { + + int iVar1; + + int iVar2; + + short* psVar3; + + int tribeID; + + int iVar4; + + int iVar5; + + int* local_c; + + psVar3 = playerID; + + if (DAT_GameState::instance.playerDataArray[(int)playerID].aiType != OpenSHC::AI::AIT_NULL) { + + iVar4 = 0; + + local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + iVar1 = *local_c; + + iVar2 = (*(int (*)[2])(local_c + -1))[0]; + + iVar5 = 0; + + if (0 < iVar1) { + + playerID = DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeIDs + iVar2; + + do { + + tribeID = (int)*playerID; + + if ((tribeID != 0) + && (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeUIDs[iVar5 + iVar2])) { + + DAT_TribesState::instance.tribes[tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + + /* + fixme: array too small? + */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(tribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[(int)psVar3 * 5][iVar4] + .xOffset)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[(int)psVar3 * 5][iVar4] + .yOffset)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + iVar4 = iVar4 + 1; + } + + playerID = playerID + 1; + + iVar5 = iVar5 + 1; + + } while (iVar5 < iVar1); + } + + local_c = local_c + 2; + + } while ((int)local_c < 0xb42a2c); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp b/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp new file mode 100644 index 000000000..18634bdf2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp @@ -0,0 +1,151 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2F80 + void AICState ::moveAttackingUnitsToNextRallyPoint(int playerID) + + { + + short sVar1; + + short* _ptrAttackingUnitsTribeID; + + BOOLEnum _allArrived; + + int _rallyPointIndex; + + uint _x; + + uint _y; + + int _tribeID; + + bool bVar2; + + bool bVar3; + + bool bVar4; + + int _counter; + + short _totalRallyPointSteps; + + short _targetUnitID; + + if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { + + _ptrAttackingUnitsTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xbe; + + _counter = 0; + + do { + + _tribeID = (int)*_ptrAttackingUnitsTribeID; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_counter + 0xbe])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + _allArrived + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::allUnitsReachedTheirDestination, + DAT_TribesState::ptr)(_tribeID); + + if (_allArrived != FALSE) { + + DAT_TribesState::instance.tribes[_tribeID].unknownAttackRelatedUpdateCounter = 0; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addRallyPointForTribe, this)(_tribeID); + + _totalRallyPointSteps = DAT_TribesState::instance.tribes[_tribeID].rallyPointCount; + + _rallyPointIndex = DAT_TribesState::instance.tribes[_tribeID].currentRallyPointIndex + 1; + + if (_totalRallyPointSteps <= _rallyPointIndex) { + + _rallyPointIndex = 0; + } + + _x = (uint)DAT_TribesState::instance.tribes[_tribeID].rallyPointArray[_rallyPointIndex][0]; + + _y = (uint)DAT_TribesState::instance.tribes[_tribeID].rallyPointArray[_rallyPointIndex][1]; + + _targetUnitID = DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; + + DAT_TribesState::instance.tribes[_tribeID].currentRallyPointIndex = (short)_rallyPointIndex; + + if (0 < _totalRallyPointSteps) { + + if (_totalRallyPointSteps < 2) { + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)( + (int)DAT_UnitsState::instance.units[_targetUnitID].x, + (int)((int)(DAT_UnitsState::instance.units[_targetUnitID].y)), (int)((int)(_x)), + (int)((int)(_y))); + + bVar4 = (DAT_DirectionAlgorithmState::instance.distanceHigh < 5); + + bVar3 = DAT_DirectionAlgorithmState::instance.distanceHigh + -5 < 0; + + bVar2 = DAT_DirectionAlgorithmState::instance.distanceHigh == 5; + + } + + else { + + sVar1 = DAT_UnitsState::instance.units[_targetUnitID].closestEnemyMicroDistance; + + bVar4 = (sVar1 < 96); + + bVar3 = (short)(sVar1 + 96) < 0; + + bVar2 = sVar1 == 96; + } + + if (!bVar2 && bVar4 == bVar3) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)( + _tribeID, _x, _y, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + } + } + } + } + + _counter = _counter + 1; + + _ptrAttackingUnitsTribeID = _ptrAttackingUnitsTribeID + 1; + + } while (_counter < 2); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp new file mode 100644 index 000000000..8d942cd2a --- /dev/null +++ b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp @@ -0,0 +1,96 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CED90 + BOOLEnum AICState ::percentageNonMovingTribesGTEAICSpecified(int playerID) + + { + + int _tribe; + + int _index; + + short* _ptrTribeNumber; + + int _tribesCount; + + int _movingFewerThan20Percent; + + int* _ptrSize; + + AITypeInt _aiType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) { + + return FALSE; + } + + _tribesCount = 0; + + _movingFewerThan20Percent = 0; + + _ptrSize = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + _index = 0; + + if (0 < *_ptrSize) { + + _ptrTribeNumber + = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + (*(int (*)[2])(_ptrSize + -1))[0]; + + do { + + _tribe = (int)*_ptrTribeNumber; + + if (((_tribe != 0) + && (DAT_TribesState::instance.tribes[_tribe].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_index + (*(int (*)[2])(_ptrSize + -1))[0]])) + && (_tribesCount = _tribesCount + 1, + DAT_TribesState::instance.tribes[_tribe].percentageMovingUnk < 20)) { + + _movingFewerThan20Percent = _movingFewerThan20Percent + 1; + } + + _index = _index + 1; + + _ptrTribeNumber = _ptrTribeNumber + 1; + + } while (_index < *_ptrSize); + } + + _ptrSize = _ptrSize + 2; + + } while ((int)_ptrSize < 0xb42a2c); + + if (0 < _tribesCount) { + + return (uint)(*(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x204) + <= (_movingFewerThan20Percent * 100) / _tribesCount); + } + + return FALSE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp new file mode 100644 index 000000000..c9b015a83 --- /dev/null +++ b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp @@ -0,0 +1,333 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CBA50 + void AICState ::planToBuyWhenLowOnResourceAndSnoozeBuildings(int playerID) + + { + + int _buildingBurning; + + int _offset; + + int _currentWood; + + int _noWood; + + int _currentPopulation; + + int* _pResourceCounter; + + int _hasArmoyUnk; + + int* _pNoBeerCounter; + + int* _pNoHopsTracker; + + int* _pNoFlourTracker; + + int* _pNoIronTracker; + + bool _enoughFood; + + bool _enoughGold; + + bool _enoughPeopleUnk; + + int _nerves; + + int _noBeerCounterUnk; + + int _noFlourCounterUnk; + + int _noHopsCounterUnk; + + int _noIronCounterUnk; + + bool _noNerves; + + int* _pNoWoodTracker; + + int _resourceCounter; + + _offset = playerID * 0x39f4; + + if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { + + _enoughPeopleUnk = true; + + _enoughFood = true; + + _enoughGold = true; + + _buildingBurning = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::playerHasBurningBuilding, + DAT_BuildingsState::ptr)(playerID); + + _currentWood = DAT_GameState::instance.playerDataArray[playerID].currentResources[2]; + + if (_currentWood < 1) { + + _pNoWoodTracker = &DAT_GameState::instance.playerDataArray[playerID].noWoodTracker; + + *_pNoWoodTracker = *_pNoWoodTracker + 1; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].noWoodTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[6] < 1) { + + _pNoIronTracker = &DAT_GameState::instance.playerDataArray[playerID].noIronTracker; + + *_pNoIronTracker = *_pNoIronTracker + 1; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].noIronTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0x10] < 1) { + + _pNoFlourTracker = &DAT_GameState::instance.playerDataArray[playerID].noFlourTracker; + + *_pNoFlourTracker = *_pNoFlourTracker + 1; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].noFlourTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[3] < 1) { + + _pNoHopsTracker = &DAT_GameState::instance.playerDataArray[playerID].noHopsTracker; + + *_pNoHopsTracker = *_pNoHopsTracker + 1; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].noHopsTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xe] < 1) { + + _pNoBeerCounter = &DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk; + + *_pNoBeerCounter = *_pNoBeerCounter + 1; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk = 0; + } + + _pResourceCounter = &DAT_GameState::instance.playerDataArray[playerID].someResourceCounter; + + *_pResourceCounter = *_pResourceCounter + 1; + + if (DAT_GameState::instance.playerDataArray[playerID].countFletchersPoleturners < 1) { + + DAT_GameState::instance.playerDataArray[playerID].noWoodTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].countArmorersAndBlacksmiths < 1) { + + DAT_GameState::instance.playerDataArray[playerID].noIronTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].countBakers < 1) { + + DAT_GameState::instance.playerDataArray[playerID].noFlourTracker = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].countBrewers < 1) { + + DAT_GameState::instance.playerDataArray[playerID].noHopsTracker = 0; + } + + _currentPopulation = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; + + if ((_currentPopulation < 10) + && ((DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers != 0 + || (2 < DAT_GameState::instance.playerDataArray[playerID].countWoodcutters)))) { + + _enoughPeopleUnk = false; + } + + if ((((20 < _currentWood) && (_currentPopulation < 10)) + && (DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers != 0)) + && (DAT_GameState::instance.playerDataArray[playerID].totalFood < 8)) { + + _enoughFood = false; + } + + if (((_buildingBurning == 0) + && (DAT_GameState::instance.playerDataArray[playerID].countFarms + <= DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers)) + && (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < 500)) { + + _enoughGold = false; + } + + _hasArmoyUnk = DAT_GameState::instance.playerDataArray[playerID].armory.id; + + _noWood = DAT_GameState::instance.playerDataArray[playerID].noWoodTracker; + + _noIronCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noIronTracker; + + _resourceCounter = DAT_GameState::instance.playerDataArray[playerID].someResourceCounter; + + _noFlourCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noFlourTracker; + + _noHopsCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noHopsTracker; + + _noBeerCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk; + + _nerves = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + _noNerves = _nerves < 1; + + if (!_noNerves) { + + _enoughPeopleUnk = false; + + _enoughFood = false; + } + + if (_enoughGold) { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[27] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x46] = false; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1b] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x46] = true; + } + + if (_enoughPeopleUnk) { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[20] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[4] = false; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x14] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[4] = true; + } + + *(bool*)(_offset + 0x115df8f) = !_enoughFood; + + *(bool*)(_offset + 0x115df91) = !_noNerves; + + *(bool*)(_offset + 0x115df92) = !_noNerves; + + *(bool*)(_offset + 0x115df98) = _nerves < 1 && (36 < _noWood || _hasArmoyUnk == 0); + + *(bool*)(_offset + 0x115df9a) = _nerves < 1 && (36 < _noWood || _hasArmoyUnk == 0); + + *(bool*)(_offset + 0x115df99) = _noNerves && (0x24 < _noIronCounterUnk || _hasArmoyUnk == 0); + + *(bool*)(_offset + 0x115df9b) = _noNerves && (0x24 < _noIronCounterUnk || _hasArmoyUnk == 0); + + *(bool*)(_offset + 0x115df9c) = _noNerves && (0x24 < _resourceCounter || _hasArmoyUnk == 0); + + *(bool*)(_offset + 0x115df9d) = !_noNerves || 0x24 < _noFlourCounterUnk; + + *(bool*)(_offset + 0x115df9e) = !_noNerves || 0x48 < _noHopsCounterUnk; + + *(bool*)(_offset + 0x115dfa2) = !_noNerves || 0x48 < _noBeerCounterUnk; + + if (_noNerves) { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1e] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1f] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x20] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x21] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[7] = false; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[34] = false; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1e] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1f] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x20] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x21] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[7] = true; + + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x22] = true; + } + + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0) { + + if ((36 < DAT_GameState::instance.playerDataArray[playerID].noWoodTracker) + && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] == 0)) { + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] = 5; + } + + if ((36 < DAT_GameState::instance.playerDataArray[playerID].noIronTracker) + && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[6] == 0)) { + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[6] = 2; + } + + if ((36 < DAT_GameState::instance.playerDataArray[playerID].noFlourTracker) + && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[0x10] == 0)) { + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[0x10] = 2; + } + + if ((72 < DAT_GameState::instance.playerDataArray[playerID].noHopsTracker) + && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[3] == 0)) { + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[3] = 2; + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp index a0679b77a..b520df926 100644 --- a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp @@ -17,10 +17,11 @@ namespace AI { int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( killerPlayerID); if (iVar1 != 0) { - if (killedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + int _curPlayer = DAT_GameSynchronyState::instance.currentPlayerSlotID; + if (killedPlayerID == _curPlayer) { iVar1 = 0xc; } else { - if (killerPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + if (killerPlayerID == _curPlayer) { MACRO_CALL_MEMBER( Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); @@ -28,8 +29,7 @@ namespace AI { do { if ((DAT_GameState::instance.playerDataArray[i].aiType != AITA_NULL) && (DAT_GameState::instance.mapAndTime.playerTeams[i] - == DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + == DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer])) { int iVar2 = MACRO_CALL_MEMBER( Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i); if (iVar2 != 0) { @@ -42,25 +42,21 @@ namespace AI { } while (i < 9); return; } - iVar1 = DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]; - if (iVar1 == DAT_GameState::instance.mapAndTime.playerTeams[killedPlayerID]) { + int _curTeam = DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer]; + if (_curTeam == DAT_GameState::instance.mapAndTime.playerTeams[killedPlayerID]) { MACRO_CALL_MEMBER( Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 0x10); return; } - if (DAT_GameState::instance.mapAndTime.playerTeams[killerPlayerID] == iVar1) { - MACRO_CALL_MEMBER( - Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + if (DAT_GameState::instance.mapAndTime.playerTeams[killerPlayerID] == _curTeam) { MACRO_CALL_MEMBER( Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 0x12); return; } - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); iVar1 = 0xd; } MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( diff --git a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp index e95658878..cc48af4ee 100644 --- a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp @@ -17,19 +17,20 @@ namespace AI { int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar1 != 0) { - iVar1 = 0; - if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] - == DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { - iVar1 = 0x17; + int _aiTypeMinusOne = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + int _myTeam = DAT_GameState::instance.mapAndTime.playerTeams[playerID]; + int _curPlayer = DAT_GameSynchronyState::instance.currentPlayerSlotID; + int _bik = 0; + if (_myTeam == DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer]) { + _bik = 0x17; } - if (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID - == DAT_GameSynchronyState::instance.currentPlayerSlotID) { - if (iVar1 == 0) { - iVar1 = ((byte)SEC_RNG::instance.currentNumber2 & 3) + 1; - } + int _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + if (_bik == 0) { + _bik = ((byte)SEC_RNG::instance.currentNumber2 & 3) + 1; + } + if (_attackedPlayerID == _curPlayer) { MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, iVar1); + playerID, _aiTypeMinusOne, _bik); } } } diff --git a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp new file mode 100644 index 000000000..7eaedffbb --- /dev/null +++ b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp @@ -0,0 +1,111 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CEEA0 + BOOLEnum AICState ::processAttForceRallyPercentage(int playerID) + + { + + AITypeInt AVar1; + + int iVar2; + + int iVar3; + + int _tribeID; + + short* psVar4; + + int iVar5; + + int _tribeTotal; + + int _notReallyMoving; + + int* local_c; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + + return FALSE; + } + + _tribeTotal = 0; + + _notReallyMoving = 0; + + local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + iVar2 = (*(int (*)[2])(local_c + -1))[0]; + + iVar3 = *local_c; + + if ((((iVar2 != 0x12) && (iVar2 != 0xbe)) && (iVar2 != 0xf)) && (iVar5 = 0, 0 < iVar3)) { + + psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar2; + + do { + + _tribeID = (int)*psVar4; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar5 + iVar2])) { + + _tribeTotal = _tribeTotal + 1; + + if (DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0x14) { + + _notReallyMoving = _notReallyMoving + 1; + } + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; + } + + iVar5 = iVar5 + 1; + + psVar4 = psVar4 + 1; + + } while (iVar5 < iVar3); + } + + local_c = local_c + 2; + + } while ((int)local_c < 0xb42a2c); + + if (0 < _tribeTotal) { + + /* + AttForceRallyPercentage */ + + return (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x200) + <= (_notReallyMoving * 100) / _tribeTotal); + } + + return FALSE; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp new file mode 100644 index 000000000..c9ffdb38b --- /dev/null +++ b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp @@ -0,0 +1,233 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/AIUnitBehaviourType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIUnitBehaviourType; + + /* + doc: + Determines which AI unit behaviour groups need recruiting because AIC Max units hasn't been + reached for that category, then randomly selects one of those groups to recruit + + @returns AiUnitBehaviourType The selected unit behaviour type + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC070 + AIUnitBehaviourType AICState ::randomlySelectAttackUnitTypeToRecruit(int playerID) + + { + + int* piVar1; + + dword _engineersCount; + + int _index2; + + int _rng; + + int _index; + + int _aiTypeMin1; + + dword _maxDiggingUnits; + + dword _maxAssassins; + + dword _maxUnit2; + + dword _maxLaddermen; + + dword _maxTunnelers; + + dword _maxUnitPatrol; + + AITypeInt _aiType; + + int _attackedPlayerID; + + dword _maxEngineers; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) { + + return OpenSHC::AI::AIUBT_ATTUNITMAIN; + } + + _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + + _index = 0; + + /* + clear out flags */ + + piVar1 = DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[0] + 1; + + do { + + *piVar1 = 0; + + piVar1 = piVar1 + 2; + + } while ((int)piVar1 < 0xb425ec); + + _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxEngineers; + + _engineersCount = DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; + + if ((int)_maxEngineers < (int)_engineersCount) { + + _engineersCount = _maxEngineers; + } + + if ((_maxEngineers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops + < (int)_engineersCount)) { + + _index = 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[0][1] = 1; + } + + _maxDiggingUnits = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttDiggingUnitMax; + + if (((_maxDiggingUnits != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops < (int)_maxDiggingUnits)) + && (5 < DAT_GameState::instance.playerDataArray[_attackedPlayerID].field992_0x396c)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[1][1] = 1; + } + + _maxAssassins = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxAssassins; + + if ((_maxAssassins != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops < (int)_maxAssassins)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[2][1] = 1; + } + + _maxUnit2 = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnit2Max; + + if ((_maxUnit2 != 0) && (DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops < (int)_maxUnit2)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[3][1] = 1; + } + + _maxLaddermen = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxLaddermen; + + if ((_maxLaddermen != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalLaddermenTroops < (int)_maxLaddermen)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[4][1] = 1; + } + + _maxTunnelers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxTunnelers; + + if ((_maxTunnelers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalTunnelerTroops < (int)_maxTunnelers)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[5][1] = 1; + } + + _maxUnitPatrol = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitPatrolMax; + + if ((_maxUnitPatrol != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops < (int)_maxUnitPatrol)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[6][1] = 1; + } + + _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitBackupMax; + + if ((_maxEngineers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops < (int)_maxEngineers)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[7][1] = 1; + } + + _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitEngageMax; + + if ((_maxEngineers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops < (int)_maxEngineers)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[8][1] = 1; + } + + _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitSiegeDefMax; + + if ((_maxEngineers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops < (int)_maxEngineers)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[9][1] = 1; + } + + _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxDefault; + + if ((_maxEngineers != 0) + && (DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops < (int)_maxEngineers)) { + + _index = _index + 1; + + DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[10][1] = 1; + } + + if (_index != 0) { + + _rng = (int)SEC_RNG::instance.currentNumber2 % _index; + + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + + _index2 = 0; + + do { + + if (DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[_index2][1] != 0) { + + if (_rng == 0) { + + return (AIUnitBehaviourType)(DAT_SkirmishDefinedData::instance + .DAT_AIBehaviourTypeUnitRequired[_index2][0]); + } + + _rng = _rng + -1; + } + + _index2 = _index2 + 1; + + } while (_index2 < 0xb); + } + + return OpenSHC::AI::AIUBT_ATTUNITMAIN; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp new file mode 100644 index 000000000..a25c39500 --- /dev/null +++ b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp @@ -0,0 +1,93 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE040 + void AICState ::recomputeAIPathCostToAttackedKeep(int playerID, int useBorderDistance) + + { + + BOOLEnum BVar1; + + uint _borderDistance; + + bool _cannotNavigateToKeep; + + int _attackedPlayerID; + + int _bd; + + ushort _keepArea; + + _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + + _keepArea = DAT_TileMapState::instance + .PathConnectionLayer[DAT_GameState::instance.playerDataArray[playerID].campground.tileEntry]; + + _bd = DAT_GameState::instance.playerDataArray[_attackedPlayerID].unknownPathBorderDistanceRelated; + + if (_bd < 120) { + + _borderDistance = ((_bd < 90) - 1 & 20) + 50; + + } + + else { + + _borderDistance = 98; + } + + if (useBorderDistance == 0) { + + _borderDistance = 0; + } + + *(int*)((int)DAT_TroopValueState::instance.attackInfo.hackValuesArray + playerID * 0x177bc + -0x10) + = _attackedPlayerID; + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); + + BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + _cannotNavigateToKeep = BVar1 == FALSE; + + if (_cannotNavigateToKeep) { + + _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + + } + + else { + + _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + } + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, + DAT_PathFindingState::ptr)(_attackedPlayerID, (int)((int)((uint)!_cannotNavigateToKeep))); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkLayerAndAIPathCostLayer, + DAT_PathFindingState::ptr)(110, _borderDistance, (dword)((int)((int)(short)_keepArea)), playerID); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp new file mode 100644 index 000000000..6213b44c7 --- /dev/null +++ b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp @@ -0,0 +1,42 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE1A0 + void AICState ::recomputeAIZonerLayer() + + { + + DAT_TroopValueState::instance.attackInfo.playerInfo[0].currentPlayerID_OR_attackedPlayerID_OR_one = 1; + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, DAT_PathFindingState::ptr)(1, 2); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkLayerAndAIPathCostLayer, + DAT_PathFindingState::ptr)(252, 0, 1, 1); + + DAT_GameState::instance.playerDataArray[1].unknownPathBorderDistanceRelated + = DAT_PathFindingState::instance.distance; + + DAT_TroopValueState::instance.attackInfo.playerInfo[0].currentPlayerID_OR_attackedPlayerID_OR_one = 1; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp new file mode 100644 index 000000000..8ab398ad0 --- /dev/null +++ b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp @@ -0,0 +1,71 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/AttackInfoSubElement.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::AttackInfoSubElement; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE110 + void AICState ::recomputeAttackAIZone() + + { + + int* _pBorderDistance; + + int _playerID; + + AttackInfoSubElement* _pi; + + int _fullID; + + _playerID = 1; + + _pi = DAT_TroopValueState::instance.attackInfo.playerInfo; + + _pBorderDistance = &DAT_GameState::instance.playerDataArray[1].unknownPathBorderDistanceRelated; + + do { + + _fullID = DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_playerID]; + + _pi->currentPlayerID_OR_attackedPlayerID_OR_one = _playerID; + + if ((_fullID != -1) || (DAT_GameSynchronyState::instance.currentAIArray[_playerID] != 0)) { + + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, + DAT_PathFindingState::ptr)(_playerID, 2); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkLayerAndAIPathCostLayer, + DAT_PathFindingState::ptr)(252, 0, 1, _playerID); + + *_pBorderDistance = DAT_PathFindingState::instance.distance; + + _pi->currentPlayerID_OR_attackedPlayerID_OR_one = 1; + } + + _playerID = _playerID + 1; + + _pBorderDistance = _pBorderDistance + 0xe7d; + + _pi = _pi + 1; + + } while (_playerID < 9); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp index a733ce5f7..78ed1689a 100644 --- a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp +++ b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp @@ -10,7 +10,7 @@ namespace AI { void AICState::recreateEngineersTribe(int playerID) { if (0 < DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops) { - int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; + int _tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { diff --git a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp new file mode 100644 index 000000000..21cd5785b --- /dev/null +++ b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp @@ -0,0 +1,254 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIVState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/Tribes/AITribeType.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/Unit.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" +#include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::Tribes::AITribeType; + using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::Unit; + using OpenSHC::Map::Units::UnitInstructionType; + using OpenSHC::Map::Units::UnitLogicState; + using OpenSHC::Map::Units::UnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CD2A0 + void AICState ::recruitHarrassingSiegeEngines(int playerID) + + { + + uint _unitID; + + int iVar1; + + Unit* pUVar4; + + int _unit; + + int _tribeID; + + int _harrassingSiegeEnginesMax; + + int _recruitTimeoutValue; + + int _engineersGuild; + + int _aiType; + + int _tribeUID; + + int _buildingID; + + int _aicEnginesArrayIndex; + + CommandBuildingType _siegeEngineToBuild; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + _engineersGuild = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + + if ((_aiType != 0) && (499 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf])) { + + _harrassingSiegeEnginesMax = *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x1ec); + + if (0 < _harrassingSiegeEnginesMax) { + + _recruitTimeoutValue = DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout; + + if (_recruitTimeoutValue != 0) { + + DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout + = _recruitTimeoutValue + -1; + + return; + } + + if ((DAT_GameState::instance.playerDataArray[playerID].harassingSiegeEnginesCountUnk + < _harrassingSiegeEnginesMax) + && (DAT_GameState::instance.playerDataArray[playerID].unknownHarrassingSiegeRelated < 0x14)) { + + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa5]; + + if ((_tribeID == 0) + || ((DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa5] + || (DAT_TribesState::instance.tribes[_tribeID].size < 2)))) { + + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) { + + return; + } + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < 30) { + + return; + } + + if (_engineersGuild < 1) { + + return; + } + + if (DAT_BuildingsState::instance.buildings[_engineersGuild].buildingType + != OpenSHC::Map::Buildings::BT_ENGINEERSGUILD) { + + return; + } + + _unitID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + OpenSHC::Map::Units::UT_E_ENGINEER, (undefined4)((int)(_engineersGuild)), playerID, 0); + + if (_unitID == 0) { + + return; + } + + if ((_tribeID == 0) + || (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa5])) { + + _tribeID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, + DAT_TribesState::ptr)(playerID); + } + + _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; + + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa5] = (short)_tribeID; + + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa5] = _tribeUID; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + _unitID, _tribeID); + + DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType = 0x16; + + } + + else { + + if (7 < DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex) { + + DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = 0; + } + + iVar1 = (_aiType + -1) * 0xa9; + + if (*(int*)((int)this + + (DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex + + iVar1) + * 4 + + 0x1cc) + == 0) { + + DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = 0; + } + + _aicEnginesArrayIndex + = DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex; + + _siegeEngineToBuild + = *(CommandBuildingType*)((int)this + (iVar1 + _aicEnginesArrayIndex) * 4 + 0x1cc); + + DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex + = _aicEnginesArrayIndex + 1; + + iVar1 = MACRO_CALL_MEMBER( + OpenSHC::AI::AIVState_Func::findSpotNearEngineersGuild, DAT_AIVState::ptr)(playerID); + + if (iVar1 == 0) { + + return; + } + + iVar1 = DAT_AIVState::instance.DAT_BuildingAppropriateGridYPosition * 5; + + _aicEnginesArrayIndex = DAT_AIVState::instance.DAT_BuildingApproriateGridXPosition * 5; + + DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + + /* + palce siege engine tent? */ + + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)( + playerID, _aicEnginesArrayIndex, iVar1, _siegeEngineToBuild, 3, 0xf); + + _buildingID = DAT_TileMapState::instance.DAT_PlacedBuildingID; + + if (DAT_TileMapState::instance.buildingPlacementFail != FALSE) { + + return; + } + + DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.DAT_PlacedBuildingID] + .attackWave = 0; + + DAT_BuildingsState::instance.buildings[_buildingID].unknownSiegeTentRelated01 = 2; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, + DAT_TribesState::ptr)(_tribeID, + OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _buildingID, + DAT_BuildingsState::instance.buildings[_buildingID].uid, 0); + } + + _unit = 1; + + if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + + pUVar4 = &DAT_UnitsState::instance.units[1]; + + do { + + if ((((pUVar4->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) && (pUVar4->dying == 0)) + && ((pUVar4->unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || (pUVar4->unitType == OpenSHC::Map::Units::UT_S_FBALLISTA)))) + && (pUVar4->aiUnitBehaviourType == 0x15)) { + + pUVar4->siegeTargetPlayerID + = (short)DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + } + + _unit = _unit + 1; + + pUVar4 = pUVar4 + 0x248; + + } while (_unit < (int)DAT_UnitsState::instance.maxUnitCount); + } + + DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout = 8; + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp b/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp new file mode 100644 index 000000000..34db026dd --- /dev/null +++ b/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp @@ -0,0 +1,66 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE430 + void AICState ::removeOrganismsAndSetMoveDestinationPairs(int playerID) + + { + + AITypeInt _aiType; + + if ((short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX] + != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)( + (int)(short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]); + } + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + /* + bug: special hardcoded exception for AI type 8 */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, + (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY)), -1, -1, 10000, FALSE); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::setMoveDestinationPairs, + DAT_PathFindingState::ptr)(playerID + -1, + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, + (int)((int)(*(int*)(DAT_TroopValueState::instance.attackInfo.scaleValuesArray + playerID * 0x177bc + -0x1c) + + (-(uint)(_aiType != OpenSHC::AI::AIT_SULTAN) & 0xc) + 8))); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp new file mode 100644 index 000000000..6367b31c8 --- /dev/null +++ b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp @@ -0,0 +1,248 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/Text/TextManager.func.hpp" +#include "OpenSHC/AI/AIC/AICSpecification.hpp" +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AIStrengthType.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/Text/TextAlignment.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" +#include "OpenSHC/Globals/DAT_BlendingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_RenderingDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TextManagerObject.hpp" +#include "OpenSHC/Globals/MSVC_SecurityCookie.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AICState; + using OpenSHC::AI::AIStrengthType; + using OpenSHC::AI::AIType; + using OpenSHC::AI::AIC::AICSpecification; + using OpenSHC::Game::Player::PlayerData; + using OpenSHC::Text::TextAlignment; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + 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 0x004D1320 + void AICState ::renderDebugDataAiInfo(int x, int y, int width, int height) + + { + + uint foregroundColor; + + int iVar1; + + PlayerData* _playerData; + + int yParam; + + char* pcVar2; + + uint foregroundColor_00; + + char (*pPlayerNames)[250]; + + int _aiTypeMin1; + + AICSpecification* local_3f4; + + AICState* local_3f0; + + char local_3ec[1000]; + + uint local_4; + + int _playerID; + + local_4 = MSVC_SecurityCookie::instance ^ (uint)&_playerID; + + local_3f0 = this; + + _playerID = 1; + + _playerData = &DAT_GameState::instance.playerDataArray[1]; + + pPlayerNames = DAT_GameSynchronyState::instance.DAT_PlayerNames + 1; + + do { + + yParam = y + 0x18; + + if (((_playerData->playerDeathRelated == 0) && (_playerData->lordKilledByPlayerID == 0)) + && ((_playerData->aiType != OpenSHC::AI::AIT_NULL + || (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_playerID] != -1)))) { + + /* + aiType - 1 */ + + _aiTypeMin1 = _playerData->aiType + ~OpenSHC::AI::AIT_NULL; + + foregroundColor + = DAT_RenderingDefinedData::instance + .DAT_ColorArray[DAT_BlendingDefinedData::instance.SEC_PlayerSlotUnitColor[_playerID]]; + + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + _playerID, x + 6, yParam, OpenSHC::Text::TTA_LEFT, 0xc2f0eb, 0x12, FALSE, 0); + + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + "-", x + 0x10, yParam, OpenSHC::Text::TTA_LEFT, 0xc2f0eb, 0x12, FALSE, 0); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + *pPlayerNames, x + 0x1a, y + 0x19, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + if (_playerData->aiStrengthFeeling == OpenSHC::AI::AIST_WEAK) { + + pcVar2 = "Weak"; + + } + + else if (_playerData->aiStrengthFeeling == OpenSHC::AI::AIST_DEFAULT) { + + pcVar2 = "Normal"; + + } + + else { + + pcVar2 = "Strong"; + } + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + pcVar2, x + 0xca, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + "P:", x + 0x106, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumber2, DAT_TextManagerObject::ptr)( + _playerData->aivCurrentPause, x + 0x108, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, + TRUE, 0); + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)( + local_3ec, "Atk:%d W:%d", _playerData->attackedPlayerID, _playerData->aiAttackCoordinationLevel); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x12e, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + if (_playerData->aiType == OpenSHC::AI::AIT_NULL) { + + iVar1 = DAT_AIVState::instance.SEC_AIVS[_playerData->aivID].castleID; + + pcVar2 = "AIV:n/a"; + + } + + else { + + iVar1 = DAT_AIVState::instance.SEC_AIVS[_playerData->aivID].castleID; + + pcVar2 = "AIV: %d"; + } + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, (char const*)((int)(pcVar2)), iVar1 + 1); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x17e, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + local_3f4 = local_3f0->aics + _aiTypeMin1; + + /* + total engineers? */ + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, "E:%d/%d", _playerData->totalTroopsType6, + _playerData->unknownCounter_01 + local_3f0->aics[_aiTypeMin1].SortieUnitRangedMin); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x1c4, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + /* + total attack troops - engineer troops */ + + iVar1 = _playerData->totalAttackTroops - _playerData->totalAttackingEngineerTroops; + + /* + ai player state == attacking */ + + if (_playerData->aiPlayerState == 0) { + + /* + AttForceBase + currentWaveRandomAttackingStrength */ + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, "Sg:%d/%d", iVar1, + _playerData->currentWaveRandomAttackingStrength + local_3f4->AttForceBase); + + foregroundColor_00 = foregroundColor; + + } + + else { + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, "%d/%d", iVar1, _playerData->attackTicker); + + foregroundColor_00 = 0xffffff; + } + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x200, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor_00, 0, 0x12, FALSE, 0); + + iVar1 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, local_3f0)( + _aiTypeMin1, _playerID); + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)( + local_3ec, "Hr:%d/%d", _playerData->totalRaidingTroopsUnk, iVar1); + + /* + display raid/harassing units */ + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x250, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + + /* + TotalDefensiveTroops / DefWalls */ + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)( + local_3ec, "Df:%d/%d", _playerData->totalDefensiveTroopsUnk, local_3f4->DefWalls); + + MACRO_CALL_MEMBER( + OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + local_3ec, x + 0x291, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + } + + pPlayerNames = pPlayerNames + 1; + + _playerID = _playerID + 1; + + _playerData = _playerData + 0xe7d; + + y = yParam; + + } while (_playerID < 9); + + ; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/requestGoods.cpp b/src/OpenSHC/AI/AICState/requestGoods.cpp new file mode 100644 index 000000000..20c9e32df --- /dev/null +++ b/src/OpenSHC/AI/AICState/requestGoods.cpp @@ -0,0 +1,70 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Game::Resources::ResourceType; + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1F00 + void AICState ::requestGoods(int playerID, ResourceType resourceType, int amount) + + { + + if ((((((DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) + && (DAT_GameState::instance.playerDataArray[playerID].aiRequestDelay == 0)) + && (resourceType != OpenSHC::Game::Resources::RT_WHEAT)) + && ((resourceType != OpenSHC::Game::Resources::RT_HOPS + && (resourceType != OpenSHC::Game::Resources::RT_ALE)))) + && ((((resourceType != OpenSHC::Game::Resources::RT_BREAD + && ((resourceType != OpenSHC::Game::Resources::RT_CHEESE + && (resourceType != OpenSHC::Game::Resources::RT_MEAT)))) + && (resourceType != OpenSHC::Game::Resources::RT_APPLE)) + || (DAT_GameState::instance.playerDataArray[playerID].totalFood < 5)))) + && (((((resourceType != OpenSHC::Game::Resources::RT_BREAD + && (resourceType != OpenSHC::Game::Resources::RT_CHEESE)) + && (resourceType != OpenSHC::Game::Resources::RT_MEAT)) + && (resourceType != OpenSHC::Game::Resources::RT_APPLE)) + || (DAT_GameState::instance.playerDataArray[playerID].totalFood < 5)))) { + + int iVar1; + int _playerID = 1; + + short* psVar2 = DAT_GameState::instance.playerDataArray[1].requestedGoodsArray1Unk + playerID; + + do { + + if (((DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_playerID] != -1) + && (DAT_GameState::instance.mapAndTime.playerTeams[_playerID] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID])) + && ((iVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_playerID), + iVar1 != 0 && (*psVar2 == 0)))) { + + *psVar2 = (short)resourceType; + + psVar2[10] = (short)amount; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playGoodsRequestBikFromPlayerToPlayer, this)( + playerID, _playerID); + } + + _playerID = _playerID + 1; + + psVar2 = psVar2 + 0x1cfa; + + } while (_playerID < 9); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp new file mode 100644 index 000000000..b9af53ac5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp @@ -0,0 +1,254 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AIC/AITargetChoiceInt.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Game/Player/PlayerData.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" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIC::AITargetChoice; + using OpenSHC::AI::AIC::AITargetChoiceInt; + using OpenSHC::Game::Player::PlayerData; + + /* + 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 0x004D4680 + void AICState ::selectAttackTarget(int playerID) + + { + + int fromXPosition; + + int fromYPosition; + + int iVar1; + + int _alive1; + + int _isLordAlive; + + int _lord; + + int _selectedPlayer; + + PlayerData* _pPlayerData2; + + int _iPlayer2; + + int _iPlayer; + + PlayerData* _ptrPlayerData; + + int _lowestDistance; + + int _highestGold; + + int _lowestPoints; + + int _currentGoldValue; + + int _points; + + int _reqState; + + int _reqState2; + + AITypeInt _aiType; + + AITargetChoiceInt _targetChoiceType; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + _selectedPlayer = 0; + + if (_aiType != OpenSHC::AI::AIT_NULL) { + + fromXPosition = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; + + fromYPosition = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; + + _lowestDistance = 10000; + + _highestGold = 0; + + _lowestPoints = 1000000; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeNervousness, this)(playerID); + + _reqState = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; + + if (((_reqState == 2) || (_reqState == 1)) + && (iVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), + iVar1 == 0)) { + + DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; + } + + _reqState2 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; + + if (_reqState2 == 2) { + + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = 0; + + return; + } + + if (_reqState2 == 1) { + + _alive1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk); + + if (_alive1 != 0) { + + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID + = DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk; + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; + } + + _pPlayerData2 = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); + + _iPlayer = 1; + + do { + + if ((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] + != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) + && (_isLordAlive = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_iPlayer), + _isLordAlive != 0)) { + + /* + fixme:improve: use pythagoras */ + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)((_pPlayerData2->campground).xEntry, + (_pPlayerData2->campground).yEntry, fromXPosition, fromYPosition); + + _targetChoiceType = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].TargetChoice; + + _currentGoldValue = _highestGold; + + _points = _lowestPoints; + + if (_targetChoiceType == OpenSHC::AI::AIC::AITC_PLAYER) { + + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_iPlayer] != -1) { + + LAB_004d47c5: + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance) { + + _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + + LAB_004d4845: + _lowestPoints = _points; + + _highestGold = _currentGoldValue; + + _selectedPlayer = _iPlayer; + } + } + + } + + else { + + if (_targetChoiceType == OpenSHC::AI::AIC::AITC_CLOSEST) + goto LAB_004d47c5; + + if (_targetChoiceType == OpenSHC::AI::AIC::AITC_GOLD) { + + _currentGoldValue = _pPlayerData2->currentResources[0xf]; + + if (_highestGold <= _pPlayerData2->currentResources[0xf]) + goto LAB_004d4845; + + } + + else if ((_targetChoiceType == OpenSHC::AI::AIC::AITC_BALANCED) + && (_points = _pPlayerData2->currentPopulation * 5 + _pPlayerData2->totalTroopValue + + _pPlayerData2->currentResources[0xf] / 100 + + DAT_DirectionAlgorithmState::instance.distanceHigh * 2, + _points <= _lowestPoints)) + goto LAB_004d4845; + } + } + + _iPlayer = _iPlayer + 1; + + _pPlayerData2 = _pPlayerData2 + 0x39f4; + + } while (_iPlayer < 9); + + if (_selectedPlayer == 0) { + + _iPlayer2 = 1; + + _ptrPlayerData = &DAT_GameState::instance.playerDataArray[1]; + + do { + + if (((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer2] + != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) + && (_lord = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_iPlayer2), + _lord != 0)) + && (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, + (_ptrPlayerData->campground).yEntry, fromXPosition, fromYPosition), + DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance)) { + + _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + + _selectedPlayer = _iPlayer2; + } + + _iPlayer2 = _iPlayer2 + 1; + + /* + next player */ + + _ptrPlayerData = _ptrPlayerData + 0xe7d; + + } while (_iPlayer2 < 9); + + if (_selectedPlayer == 0) { + + return; + } + } + + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk = _selectedPlayer; + + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = _selectedPlayer; + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp new file mode 100644 index 000000000..1b1c2239a --- /dev/null +++ b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp @@ -0,0 +1,75 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDAB0 + int AICState ::selectBuildingFromAListOfBuildingTypes(int playerID) + + { + + int _selectedBuildingID; + + int _loopCounter; + + int _loopLimit; + + short* psVar1; + + int _arraySize; + + int _buildingID; + + _arraySize = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + + _selectedBuildingID = 0; + + _loopLimit = 0x2e; + + if (0 < _arraySize) { + + psVar1 = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings; + + do { + + _buildingID = (int)*psVar1; + + if ((_buildingID != 0) && (_loopCounter = 0, 0 < _loopLimit)) { + + do { + + if ((int)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType + == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_loopCounter]) { + + /* + fancy break statement? */ + + _selectedBuildingID = _buildingID; + + _loopLimit = _loopCounter; + } + + _loopCounter = _loopCounter + 1; + + } while (_loopCounter < _loopLimit); + } + + psVar1 = psVar1 + 1; + + _arraySize = _arraySize + -1; + + } while (_arraySize != 0); + } + + return _selectedBuildingID; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp b/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp new file mode 100644 index 000000000..072e4b84d --- /dev/null +++ b/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp @@ -0,0 +1,37 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CDCA0 + int AICState ::selectRandomBuildingIDFromListOfBuildingTypes(int playerID, undefined4 param_2) + + { + + int iVar1; + + int iVar2; + + iVar1 = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + + if (iVar1 < 1) { + + return 0; + } + + iVar2 = (int)SEC_RNG::instance.currentNumber2; + + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + + return (int)DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings[iVar2 % iVar1]; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp new file mode 100644 index 000000000..412497ce2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -0,0 +1,147 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/Trading/AIResourceTradeCategory.hpp" +#include "OpenSHC/AI/Trading/AIResourceTradeCategoryInt.hpp" +#include "OpenSHC/AI/Trading/ResourceAICResourceMappingEntry.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::Trading::AIResourceTradeCategory; + using OpenSHC::AI::Trading::AIResourceTradeCategoryInt; + using OpenSHC::AI::Trading::ResourceAICResourceMappingEntry; + using OpenSHC::Game::Resources::ResourceType; + + // FUNCTION: STRONGHOLDCRUSADER 0x004D1D60 + void AICState ::sellExcessGoods(int param_1) + + { + + AITypeInt AVar1; + + ResourceType resourceType; + + AIResourceTradeCategoryInt AVar2; + + int iVar3; + + uint uVar4; + + int iVar5; + + int iVar6; + + ResourceType* pRVar7; + + AIResourceTradeCategoryInt* local_18; + + AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + return; + } + + iVar3 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + + local_18 = &DAT_SkirmishDefinedData::instance.DAT_AIResourceTradeAICMapping[0].aic; + + do { + + resourceType + = (OpenSHC::Game::Resources::ResourceType)((ResourceAICResourceMappingEntry*)(local_18 + -1))->game; + + AVar2 = *local_18; + + iVar6 = *(int*)((int)this + iVar3 + 0xc0); + + if (AVar2 == OpenSHC::AI::Trading::AIRTC_WOOD) { + iVar5 = *(int*)((int)this + iVar3 + 0xac); + } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { + iVar5 = *(int*)((int)this + iVar3 + 0x80); + } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_STONE) { + iVar5 = *(int*)((int)this + iVar3 + 0xb0); + } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_WEAPONS) { + iVar5 = *(int*)((int)this + iVar3 + 0xb8); + } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_ALE) { + iVar5 = *(int*)((int)this + iVar3 + 0xbc); + } else { + iVar5 = *(int*)((int)this + iVar3 + 0xb4); + } + + uVar4 = iVar5 + iVar6; + + if ((DAT_GameState::instance.playerDataArray[param_1].aiNervousActionsTracker <= 0) + || (DAT_GameState::instance.playerDataArray[param_1].currentResources[0xf] >= 0x1f4)) { + + if (DAT_GameState::instance.playerDataArray[param_1].popularity < *(int*)((int)this + iVar3 + 0x18)) { + + if (AVar2 != OpenSHC::AI::Trading::AIRTC_FOOD) { + + if (AVar2 == OpenSHC::AI::Trading::AIRTC_WEAPONS) { + uVar4 = 0; + iVar6 = 0; + goto LAB_004d1e81; + } + + uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; + } + + iVar6 = 0; + + } else { + uVar4 = uVar4 + + DAT_GameState::instance.playerDataArray[param_1].resourcesToAcquireArray[resourceType]; + } + + } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { + + uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; + iVar6 = 0; + + } else { + + uVar4 = (AVar2 != OpenSHC::AI::Trading::AIRTC_WEAPONS) - 1 & 10000; + iVar6 = 0; + } + + LAB_004d1e81: + iVar5 = 0; + + pRVar7 = (ResourceType*)((int)this + iVar3 + 0xd4); + + do { + if (resourceType == *pRVar7) { + uVar4 = 0; + iVar6 = 0; + break; + } + iVar5 = iVar5 + 1; + pRVar7 = pRVar7 + 1; + } while (iVar5 < 0xf); + + if ((int)uVar4 < DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType]) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellGoods, this)(param_1, resourceType, + (DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType] - uVar4) + iVar6); + + return; + } + + local_18 = local_18 + 2; + + if (0xb4252b < (int)local_18) { + return; + } + + } while (true); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp new file mode 100644 index 000000000..83b899711 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp @@ -0,0 +1,109 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/AI/AIVUnitType.hpp" +#include "OpenSHC/AI/AIVUnitTypeInt.hpp" +#include "OpenSHC/AI/Tribes/AIVUnitTypeMaxLocationPair.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIVUnitType; + using OpenSHC::AI::AIVUnitTypeInt; + using OpenSHC::AI::Tribes::AIVUnitTypeMaxLocationPair; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4220 + void AICState ::sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed(int playerID) + + { + + BOOLEnum _enclosed; + + AIVUnitTypeInt* _ptr; + + int _tribe; + + int _index; + + int _limit; + + int* _nervous; + + _enclosed = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)( + playerID); + + _ptr = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_GroundUnits[0].aivUnitType; + + do { + + _limit = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*_ptr]; + + _index = 0; + + if (0 < _limit) { + + _nervous = &DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + do { + + _tribe = (int)DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index]; + + if ((_tribe != 0) + && (DAT_TribesState::instance.tribes[_tribe].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index])) { + + if ((*_nervous < 1) || (_enclosed != FALSE)) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( + _tribe, (AIVUnitType)((int)(*_ptr)), _index); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribe, playerID); + } + } + + /* + bug:fixme: _tribe could be 0 */ + + if ((*_nervous < 1) || (_enclosed != FALSE)) { + + DAT_TribesState::instance.tribes[_tribe].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + } + + else { + + DAT_TribesState::instance.tribes[_tribe].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + } + + _index = _index + 1; + + } while (_index < _limit); + } + + _ptr = _ptr + 2; + + } while ((int)_ptr < 0xb4277c); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp new file mode 100644 index 000000000..afc77615c --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp @@ -0,0 +1,104 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIVUnitType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIVUnitType; + using OpenSHC::Map::Units::UnitInstructionType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D44E0 + void AICState ::sendOilMenForOilPickupOrToAIVLocations(int playerID) + + { + + short* _ptrTribeIDArray; + + int _oilManLocationsCount; + + int _tribeID; + + int _index; + + int _oilSmelter; + + _oilSmelter = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id; + + _oilManLocationsCount = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1]; + + if (0 < _oilManLocationsCount) { + + if (_oilManLocationsCount == 10) { + + _oilManLocationsCount = 9; + } + + _index = 1; + + if (0 < _oilManLocationsCount) { + + /* + oil men offset in tribe id array */ + + _ptrTribeIDArray = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 71; + + do { + + _tribeID = (int)*_ptrTribeIDArray; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0x46])) { + + if (DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID] + .resourceToDeposit + == 0) { + + if (_oilSmelter != 0) { + + /* + send for oil duty */ + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, + DAT_UnitsState::ptr)(_tribeID, + OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, + _oilSmelter, DAT_BuildingsState::instance.buildings[_oilSmelter].uid, 0); + } + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, + DAT_TribesState::ptr)(_tribeID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( + _tribeID, OpenSHC::AI::AIVUT_ENGINEER, _index + -1); + } + } + + _index = _index + 1; + + _ptrTribeIDArray = _ptrTribeIDArray + 1; + + } while (_index <= _oilManLocationsCount); + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp new file mode 100644 index 000000000..429bb500b --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp @@ -0,0 +1,76 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIVUnitType.hpp" +#include "OpenSHC/AI/AIVUnitTypeInt.hpp" +#include "OpenSHC/AI/Tribes/AIVUnitTypeMaxLocationPair.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIVUnitType; + using OpenSHC::AI::AIVUnitTypeInt; + using OpenSHC::AI::Tribes::AIVUnitTypeMaxLocationPair; + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4130 + void AICState ::sendRangedUnitTribesToAIVSlotsOrKeepIfNervous(int playerID) + + { + + AIVUnitTypeInt* _ptr + = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_RangedUnits[0].aivUnitType; + + do { + + int _limit = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*_ptr]; + + int _index = 0; + + if (0 < _limit) { + + do { + + int _tribe = (int)DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index]; + + if ((_tribe != 0) + && (DAT_TribesState::instance.tribes[_tribe].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index])) { + + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { + + if ((DAT_TileMapState::instance.LogicLayer[DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[_tribe].selectionTargetUnitID] + .tile] + & 0x10000100U) + == 0) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribe, playerID); + } + + } else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( + _tribe, (AIVUnitType)((int)(*_ptr)), _index); + } + } + + _index = _index + 1; + + } while (_index < _limit); + } + + _ptr = _ptr + 2; + + } while ((int)_ptr < 0xb42744); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp new file mode 100644 index 000000000..3cd363930 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp @@ -0,0 +1,90 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIVUnitType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIVUnitType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + [doc] + @param slotIndex int slotIndex to browse to + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D2E00 + void AICState ::sendTribeToAIVLocationSlot(int tribeID, AIVUnitType aivUnitType, int slotIndex) + + { + + int _slotIndex; + + BOOLEnum _canNavigate; + + int* _ptrSlot; + + int _tile; + + int _x; + + int _owner; + + short _y; + + /* + all experimental, heavy local reuse... */ + + _owner = DAT_TribesState::instance.tribes[tribeID].owner; + + _tile = 0; + + _slotIndex = 0; + + /* + aivUnitLocationSlots */ + + _ptrSlot = (int*)(_owner * 0x39f4 + 0x115eb14 + aivUnitType * 0x28); + + while ((*_ptrSlot == 0 || (slotIndex = slotIndex + -1, -1 < slotIndex))) { + + _slotIndex = _slotIndex + 1; + + _ptrSlot = _ptrSlot + 1; + + if (9 < _slotIndex) { + + LAB_004d2e6d: + _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + + _x = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + + _canNavigate = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, _tile); + + if (_canNavigate == FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, _owner); + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + tribeID, (uint)((int)(_tile - _x)), (uint)((int)((int)_y)), 0); + + return; + } + } + + _tile = DAT_GameState::instance.playerDataArray[_owner].aivUnitLocationSlots[aivUnitType][_slotIndex]; + + goto LAB_004d2e6d; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp new file mode 100644 index 000000000..6870e8369 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp @@ -0,0 +1,181 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D30E0 + undefined4 AICState ::sendUnitsToAttackBreachedCastle(int attackingPlayerIndex) + + { + + int tribeType; + + int _defendingLordIndex; + + int _successUnk; + + int iVar1; + + int _vector; + + int _tribeID; + + short* local_20; + + int local_18; + + int (*_ptrGroupCount)[2]; + + int _attackedPlayerID; + + int _groupCount; + + short _targetUnit; + + bool sentUnitsToAttackLord; + + _vector = 0; + + if (DAT_GameState::instance.playerDataArray[attackingPlayerIndex].aiType == OpenSHC::AI::AIT_NULL) { + + return (undefined4)(1); + } + + sentUnitsToAttackLord = false; + + _defendingLordIndex = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID); + + _ptrGroupCount + = (int (*)[2])(DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[0] + 1); + + do { + + tribeType = _ptrGroupCount[-1][1]; + + _groupCount = (*_ptrGroupCount)[0]; + + if ((((tribeType != 18) && (tribeType != 14)) && (tribeType != 13)) && (local_18 = 0, 0 < _groupCount)) { + + local_20 = DAT_GameState::instance.playerDataArray[attackingPlayerIndex].aiTribeIDs + tribeType; + + do { + + _tribeID = (int)*local_20; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[attackingPlayerIndex] + .aiTribeUIDs[local_18 + tribeType])) { + + _targetUnit = DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + + if ((sentUnitsToAttackLord) || ((_defendingLordIndex == 0 || (tribeType == 186)))) { + + iVar1 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveSomeRaidCommand, this)( + _tribeID, tribeType); + + if (iVar1 == 0) { + + if (tribeType == 0xba) { + + _vector = _vector + 4; + } + + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_8; + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + iVar1 = DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID; + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)( + (int)DAT_UnitsState::instance.units[_targetUnit].x, + (int)((int)(DAT_UnitsState::instance.units[_targetUnit].y)), + DAT_GameState::instance.mapAndTime.attackVectors[iVar1][_vector].x, + DAT_GameState::instance.mapAndTime.attackVectors[iVar1][_vector].y); + + if (4 < DAT_DirectionAlgorithmState::instance.distanceHigh) { + + _attackedPlayerID = DAT_GameState::instance.playerDataArray[attackingPlayerIndex] + .attackedPlayerID; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(_tribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .attackVectors[_attackedPlayerID][_vector] + .x)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .attackVectors[_attackedPlayerID][_vector] + .y)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + } + + _vector = _vector + 1; + } + + } + + else { + + /* + Send units to attack lord */ + + _successUnk = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + _tribeID, (uint)((int)((int)DAT_UnitsState::instance.units[_defendingLordIndex].x)), + (uint)((int)((int)DAT_UnitsState::instance.units[_defendingLordIndex].y)), 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + + if (_successUnk == 0) { + + return (undefined4)(0); + } + + sentUnitsToAttackLord = true; + } + } + + local_20 = local_20 + 1; + + local_18 = local_18 + 1; + + } while (local_18 < _groupCount); + } + + _ptrGroupCount = _ptrGroupCount + 1; + + } while ((int)_ptrGroupCount < 0xb42acc); + + return (undefined4)(1); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp index 8b0339efc..dd0c25b0d 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp @@ -9,7 +9,7 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CD0C0 - void AICState::sendUnitsToKeep(undefined4 tribeID, int playerID) + void AICState::sendUnitsToKeep(int tribeID, int playerID) { int iVar1 = DAT_GameState::instance.playerDataArray[playerID].keep.id; if (0 < iVar1) { diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp new file mode 100644 index 000000000..db61864a8 --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -0,0 +1,165 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE5F0 + void AICState ::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, short* playerID2) + + { + + BOOLEnum BVar1; + + dword _gatehouseTile; + + int _tribeID; + + int _counter; + + int* local_10; + + uint _ghY; + + uint _ghX; + + int _maxTribeCount; + + int _p1_keepCampfireX; + + int _aiTribeBehaviourTypeOffset; + + uint _p1_keepCampfireY; + + short* _playerID2; + + _playerID2 = playerID2; + + _p1_keepCampfireY = DAT_GameState::instance.playerDataArray[playerID1].campground.yEntry; + + _p1_keepCampfireX = DAT_GameState::instance.playerDataArray[playerID1].campground.xEntry; + + BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID1, (int)((int)(playerID2))); + + if (BVar1 == FALSE) { + + _gatehouseTile = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findOwnedGatehouse, + DAT_PathFindingState::ptr)((int)playerID2, (uint)((int)(_p1_keepCampfireX)), _p1_keepCampfireY); + + if (_gatehouseTile == 0) { + + DAT_GameState::instance.playerDataArray[playerID1].requestStateUnk = 0; + + return; + } + + _ghY = (uint)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_gatehouseTile]; + + _ghX = _gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[_ghY].addXgetTile; + } + + local_10 = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + + do { + + _maxTribeCount = *local_10; + + _aiTribeBehaviourTypeOffset = (*(int (*)[2])(local_10 + -1))[0]; + + _counter = 0; + + if (0 < _maxTribeCount) { + + /* + fixme: reused parameter */ + + playerID2 = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _aiTribeBehaviourTypeOffset; + + do { + + _tribeID = (int)*playerID2; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID1] + .aiTribeUIDs[_counter + _aiTribeBehaviourTypeOffset])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID1, (int)((int)(_playerID2))); + + if (BVar1 == FALSE) { + + /* + send to enemy gate house */ + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + _tribeID, _ghX, _ghY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + + } + + else if (_aiTribeBehaviourTypeOffset == 0xbe) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, (int)((int)(_playerID2))); + + } + + else { + + BVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + + if (BVar1 == FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( + _tribeID, (int)((int)(_playerID2))); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, (int)((int)(_playerID2))); + } + } + } + + playerID2 = playerID2 + 1; + + _counter = _counter + 1; + + } while (_counter < _maxTribeCount); + } + + local_10 = local_10 + 2; + + } while ((int)local_10 < 0xb42a2c); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp new file mode 100644 index 000000000..b5d4cdd8e --- /dev/null +++ b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp @@ -0,0 +1,155 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/AIVUnitType.hpp" +#include "OpenSHC/AI/AIVUnitTypeInt.hpp" +#include "OpenSHC/AI/Tribes/AIVUnitTypeMaxLocationPair.hpp" +#include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIVUnitType; + using OpenSHC::AI::AIVUnitTypeInt; + using OpenSHC::AI::Tribes::AIVUnitTypeMaxLocationPair; + using OpenSHC::Map::Units::Behavior::UnitStanceEnum; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4340 + void AICState ::sendWallPatrolUnitTribesToAIVLocations(int playerID) + + { + + BOOLEnum _enclosed; + + int _tribeID; + + AIVUnitTypeInt* _ptr; + + int _patrolGroupIndex; + + int _index; + + int _minCount; + + int _stepSize; + + int _defWallPatrolGroups; + + AITypeInt _aiType; + + int _count; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (_aiType != OpenSHC::AI::AIT_NULL) { + + _enclosed = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + + /* + defWallPatrolGroups */ + + _ptr = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_PatrolUnits[0].aivUnitType; + + do { + + _defWallPatrolGroups = *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x114); + + _count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*_ptr]; + + _index = 0; + + _minCount = _count; + + if (_defWallPatrolGroups < _count) { + + _minCount = _defWallPatrolGroups; + } + + if (0 < _minCount) { + + _stepSize = _count / _minCount; + + if (_stepSize < 1) { + + _stepSize = 1; + } + + if (0 < _minCount) { + + _patrolGroupIndex = 0; + + do { + + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + + _index]; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + + _index])) { + + if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) + || (_enclosed != FALSE)) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( + _tribeID, (AIVUnitType)((int)(*_ptr)), + (DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits + + _patrolGroupIndex) + % _count); + + } + + else { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID); + } + + if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) + || (_enclosed != FALSE)) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + } + + else { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + } + } + + _patrolGroupIndex = _patrolGroupIndex + _stepSize; + + _index = _index + 1; + + } while (_index < _minCount); + } + } + + _ptr = _ptr + 2; + + } while ((int)_ptr < 0xb42794); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_06.cpp b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp new file mode 100644 index 000000000..2a28425db --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp @@ -0,0 +1,289 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C8110 + void AICState ::setAICParameters_06(int param_1) + + { + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].taxesMax = 0xc; + + this->aics[param_1].farm1 = 0x20; + + this->aics[param_1].farm3 = 0x20; + + this->aics[param_1].unknown011 = 0xc; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x32; + + this->aics[param_1].doubleRationsFoodThreshold = 0x32; + + this->aics[param_1].maxWood = 0x32; + + this->aics[param_1].maxStone = 0x32; + + this->aics[param_1].populationPerIronmine = 0xc; + + this->aics[param_1].flagType = 10; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 0; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 3; + + this->aics[param_1].farm2 = 0x1f; + + this->aics[param_1].populationPerFarm = 5; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].tradeAmountFood = 10; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 5; + + this->aics[param_1].maxBeer = 0xf; + + this->aics[param_1].maxResourceVariance = 5; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 10; + + this->aics[param_1].populationPerPitchrig = 7; + + this->aics[param_1].maxQuarries = 2; + + this->aics[param_1].maxIronmines = 1; + + this->aics[param_1].maxWoodcutters = 8; + + this->aics[param_1].maxPitchrigs = 10; + + this->aics[param_1].maxFarms = 10; + + this->aics[param_1].buildInterval = 3; + + this->aics[param_1].resourceRebuildDelay = 0x3c; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x12; + + this->aics[param_1].poleturnerSetting = 0x14; + + this->aics[param_1].defWallPatrolRallyTime = 5; + + this->aics[param_1].defWallPatrolGroups = 2; + + this->aics[param_1].defSiegeEngineGoldThreshold = 0x78; + + this->aics[param_1].defSiegeEngineBuildDelay = 8; + + this->aics[param_1].sellResource03 = 6; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource08 = 0x11; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].unknown072 = 100; + + this->aics[param_1].SortieUnitRangedMin = 7; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 0x14; + + this->aics[param_1].recruitProbAttackDefault = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 0; + + this->aics[param_1].RecruitInterval = 0; + + this->aics[param_1].RecruitIntervalStrong = 0; + + this->aics[param_1].SortieUnitMeleeMin = 5; + + this->aics[param_1].OuterPatrolGroupsCount = 2; + + this->aics[param_1].HarassingSiegeEnginesMax = 2; + + this->aics[param_1].recruitProbDefWeak = 0x50; + + this->aics[param_1].recruitProbDefDefault = 0x28; + + this->aics[param_1].recruitProbDefStrong = 0x28; + + this->aics[param_1].recruitProbRaidDefault = 0x28; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackStrong = 0x1e; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].SortieUnitMelee = 0x4b; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].DefDiggingUnit = 0x47; + + this->aics[param_1].DefWalls = 0x3c; + + this->aics[param_1].DefTotal = 0x3c; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 10; + + this->aics[param_1].DefUnit1 = 0x4c; + + this->aics[param_1].RaidUnitsBase = 0x1e; + + this->aics[param_1].RaidUnitsRandom = 0x1e; + + this->aics[param_1].RaidUnit1 = 0x47; + + this->aics[param_1].SortieUnitRanged = 0x46; + + this->aics[param_1].DefUnit2 = 0x46; + + this->aics[param_1].DefUnit3 = 0x46; + + this->aics[param_1].DefUnit4 = 0x46; + + this->aics[param_1].HarassingSiegeEngine1 = 0x166; + + this->aics[param_1].HarassingSiegeEngine2 = 0xbe; + + this->aics[param_1].RaidRetargetDelay = 3; + + this->aics[param_1].AttForceBase = 0xf; + + this->aics[param_1].AttForceRandom = 10; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x46; + + this->aics[param_1].AttForceRallyPercentage = 100; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 2; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 10; + + this->aics[param_1].AttCoordinationPreference = 0x32; + + this->aics[param_1].CowThrowInterval = 7; + + this->aics[param_1].SiegeEngine1 = 0x4d; + + this->aics[param_1].SiegeEngine2 = 0x4d; + + this->aics[param_1].SiegeEngine3 = 0x4d; + + this->aics[param_1].AttMaxEngineers = 6; + + this->aics[param_1].AttDiggingUnit = 0x47; + + this->aics[param_1].AttDiggingUnitMax = 0x14; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0x4b; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0x4a; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x4a; + + this->aics[param_1].AttUnitBackupMax = 0x28; + + this->aics[param_1].AttUnitBackupGroupsCount = 2; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0x46; + + this->aics[param_1].AttUnitSiegeDefMax = 10; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; + + this->aics[param_1].AttUnitMain1 = 0x4b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 5; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp new file mode 100644 index 000000000..84fc2c94a --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp @@ -0,0 +1,283 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C8530 + void AICState ::setAICParameters_07(int param_1) + + { + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].maxEquipment = 5; + + this->aics[param_1].maxResourceVariance = 5; + + this->aics[param_1].flagType = 10; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 0; + + this->aics[param_1].unknown005 = 0; + + this->aics[param_1].criticalPopularity = 5000; + + this->aics[param_1].lowestPopularity = 6000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 1; + + this->aics[param_1].taxesMax = 8; + + this->aics[param_1].farm1 = 0; + + this->aics[param_1].populationPerFarm = 100; + + this->aics[param_1].unknown011 = 0x14; + + this->aics[param_1].maxFood = 500; + + this->aics[param_1].minimumApples = 0x14; + + this->aics[param_1].tradeAmountFood = 10; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].aiRequestDelay = 0x1e; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0; + + this->aics[param_1].doubleRationsFoodThreshold = 0; + + this->aics[param_1].maxWood = 0x1e; + + this->aics[param_1].maxStone = 0x14; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxBeer = 0x14; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 2; + + this->aics[param_1].populationPerQuarry = 5; + + this->aics[param_1].populationPerIronmine = 0; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 2; + + this->aics[param_1].maxIronmines = 1; + + this->aics[param_1].maxWoodcutters = 0xf; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 6; + + this->aics[param_1].buildInterval = 5; + + this->aics[param_1].resourceRebuildDelay = 0x50; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource02 = 3; + + this->aics[param_1].sellResource03 = 6; + + this->aics[param_1].sellResource04 = 7; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource06 = 0xe; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource08 = 0x11; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 10; + + this->aics[param_1].defWallPatrolGroups = 2; + + this->aics[param_1].defSiegeEngineGoldThreshold = 200; + + this->aics[param_1].defSiegeEngineBuildDelay = 0x14; + + this->aics[param_1].unknown072 = 800; + + this->aics[param_1].unknown073 = 0x50; + + this->aics[param_1].recruitProbDefStrong = 0x1e; + + this->aics[param_1].recruitProbRaidWeak = 10; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackDefault = 0x1e; + + this->aics[param_1].DefDiggingUnitMax = 2; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 10; + + this->aics[param_1].RaidUnitsRandom = 10; + + this->aics[param_1].recruitProbDefWeak = 0x46; + + this->aics[param_1].recruitProbDefDefault = 0x32; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 0x14; + + this->aics[param_1].recruitProbAttackStrong = 0x28; + + this->aics[param_1].RecruitIntervalWeak = 8; + + this->aics[param_1].RecruitInterval = 8; + + this->aics[param_1].RecruitIntervalStrong = 4; + + this->aics[param_1].SortieUnitRangedMin = 0; + + this->aics[param_1].SortieUnitRanged = 0x48; + + this->aics[param_1].SortieUnitMeleeMin = 3; + + this->aics[param_1].SortieUnitMelee = 0x4b; + + this->aics[param_1].DefDiggingUnit = 0x47; + + this->aics[param_1].DefWalls = 0x28; + + this->aics[param_1].DefTotal = 0x32; + + this->aics[param_1].OuterPatrolGroupsMove = 0; + + this->aics[param_1].DefUnit1 = 0x48; + + this->aics[param_1].DefUnit2 = 0x48; + + this->aics[param_1].DefUnit3 = 0x4b; + + this->aics[param_1].RaidUnitsBase = 0x14; + + this->aics[param_1].RaidUnit1 = 0x48; + + this->aics[param_1].HarassingSiegeEnginesMax = 0; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].RaidRetargetDelay = 3; + + this->aics[param_1].AttForceBase = 10; + + this->aics[param_1].AttForceRandom = 0x14; + + this->aics[param_1].AttForceSupportAllyThreshold = 5; + + this->aics[param_1].AttForceRallyPercentage = 0x1e; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 0x28; + + this->aics[param_1].AttCoordinationPreference = 0x14; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0; + + this->aics[param_1].AttMaxEngineers = 0; + + this->aics[param_1].AttDiggingUnit = 0; + + this->aics[param_1].AttDiggingUnitMax = 0; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x46; + + this->aics[param_1].AttUnitBackupMax = 0x78; + + this->aics[param_1].AttUnitBackupGroupsCount = 1; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x4b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 1; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_08.cpp b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp new file mode 100644 index 000000000..fbc4839a2 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp @@ -0,0 +1,289 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C8920 + void AICState ::setAICParameters_08(int param_1) + + { + + this->aics[param_1].farm2 = 0x20; + + this->aics[param_1].farm3 = 0x20; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].minimumApples = 5; + + this->aics[param_1].minimumCheese = 5; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].tradeAmountFood = 5; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown005 = 0; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 8000; + + this->aics[param_1].taxesMin = 3; + + this->aics[param_1].taxesMax = 10; + + this->aics[param_1].farm1 = 0x21; + + this->aics[param_1].populationPerFarm = 4; + + this->aics[param_1].unknown011 = 0xc; + + this->aics[param_1].maxFood = 200; + + this->aics[param_1].tradeAmountEquipment = 2; + + this->aics[param_1].aiRequestDelay = 0x16; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + + this->aics[param_1].doubleRationsFoodThreshold = 0x28; + + this->aics[param_1].maxWood = 0x32; + + this->aics[param_1].maxStone = 0x3c; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 10; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 10; + + this->aics[param_1].populationPerIronmine = 10; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 3; + + this->aics[param_1].maxIronmines = 4; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxFarms = 0xf; + + this->aics[param_1].buildInterval = 4; + + this->aics[param_1].resourceRebuildDelay = 0x14; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x14; + + this->aics[param_1].sellResource02 = 3; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource06 = 0xe; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].defWallPatrolRallyTime = 8; + + this->aics[param_1].defWallPatrolGroups = 4; + + this->aics[param_1].defSiegeEngineGoldThreshold = 200; + + this->aics[param_1].defSiegeEngineBuildDelay = 2; + + this->aics[param_1].unknown072 = 100; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x5a; + + this->aics[param_1].recruitProbDefDefault = 0x1e; + + this->aics[param_1].recruitProbDefStrong = 10; + + this->aics[param_1].recruitProbAttackWeak = 10; + + this->aics[param_1].RaidUnitsBase = 10; + + this->aics[param_1].recruitProbRaidWeak = 0; + + this->aics[param_1].recruitProbRaidDefault = 0; + + this->aics[param_1].recruitProbRaidStrong = 0; + + this->aics[param_1].SortieUnitRanged = 0x16; + + this->aics[param_1].DefDiggingUnitMax = 0; + + this->aics[param_1].DefWalls = 0x14; + + this->aics[param_1].OuterPatrolGroupsCount = 2; + + this->aics[param_1].DefUnit1 = 0x16; + + this->aics[param_1].DefUnit2 = 0x16; + + this->aics[param_1].RaidUnitsRandom = 4; + + this->aics[param_1].RaidUnit1 = 0x16; + + this->aics[param_1].HarassingSiegeEnginesMax = 2; + + this->aics[param_1].AttForceBase = 0x14; + + this->aics[param_1].recruitProbAttackDefault = 0x46; + + this->aics[param_1].recruitProbAttackStrong = 0x5a; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].RecruitInterval = 1; + + this->aics[param_1].RecruitIntervalStrong = 1; + + this->aics[param_1].SortieUnitRangedMin = 6; + + this->aics[param_1].SortieUnitMeleeMin = 6; + + this->aics[param_1].SortieUnitMelee = 0x19; + + this->aics[param_1].DefDiggingUnit = 0x19; + + this->aics[param_1].DefTotal = 0x28; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 5; + + this->aics[param_1].DefUnit3 = 0x19; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].RaidRetargetDelay = 5; + + this->aics[param_1].AttForceRandom = 5; + + this->aics[param_1].AttForceSupportAllyThreshold = 10; + + this->aics[param_1].AttForceRallyPercentage = 10; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0x14; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 2; + + this->aics[param_1].AttCoordinationPreference = 10; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x27; + + this->aics[param_1].SiegeEngine2 = 0x27; + + this->aics[param_1].SiegeEngine3 = 0x27; + + this->aics[param_1].SiegeEngine4 = 0x3b; + + this->aics[param_1].SiegeEngine5 = 0x28; + + this->aics[param_1].SiegeEngine6 = 0x28; + + this->aics[param_1].AttMaxEngineers = 0x10; + + this->aics[param_1].AttDiggingUnit = 0x19; + + this->aics[param_1].AttDiggingUnitMax = 6; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 3; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x16; + + this->aics[param_1].AttUnitBackupMax = 0x14; + + this->aics[param_1].AttUnitBackupGroupsCount = 2; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0x1b; + + this->aics[param_1].AttUnitSiegeDefMax = 4; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 2; + + this->aics[param_1].AttUnitMain1 = 0x1b; + + this->aics[param_1].AttUnitMain2 = 0x19; + + this->aics[param_1].AttUnitMain3 = 0x19; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 3; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_09.cpp b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp new file mode 100644 index 000000000..28bd5aac5 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp @@ -0,0 +1,283 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C8D20 + void AICState ::setAICParameters_09(int param_1) + + { + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].minimumApples = 5; + + this->aics[param_1].minimumCheese = 5; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x3c; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 0x157c; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 3; + + this->aics[param_1].taxesMax = 10; + + this->aics[param_1].farm1 = 0x21; + + this->aics[param_1].farm2 = 0x20; + + this->aics[param_1].farm3 = 0x1f; + + this->aics[param_1].populationPerFarm = 4; + + this->aics[param_1].unknown011 = 0xc; + + this->aics[param_1].maxFood = 200; + + this->aics[param_1].tradeAmountFood = 10; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].aiRequestDelay = 0x16; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + + this->aics[param_1].doubleRationsFoodThreshold = 0x28; + + this->aics[param_1].maxResourceOther = 0xf; + + this->aics[param_1].maxEquipment = 0x14; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 0xc; + + this->aics[param_1].populationPerIronmine = 10; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 4; + + this->aics[param_1].maxIronmines = 5; + + this->aics[param_1].maxWoodcutters = 0xc; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 0xc; + + this->aics[param_1].buildInterval = 4; + + this->aics[param_1].resourceRebuildDelay = 0x1e; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = -999; + + this->aics[param_1].poleturnerSetting = 0x14; + + this->aics[param_1].sellResource04 = 7; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].defWallPatrolRallyTime = 8; + + this->aics[param_1].defWallPatrolGroups = 2; + + this->aics[param_1].defSiegeEngineGoldThreshold = 200; + + this->aics[param_1].defSiegeEngineBuildDelay = 2; + + this->aics[param_1].unknown072 = 100; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 100; + + this->aics[param_1].recruitProbDefDefault = 0x32; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 0; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x14; + + this->aics[param_1].RecruitInterval = 4; + + this->aics[param_1].RecruitIntervalStrong = 4; + + this->aics[param_1].SortieUnitRanged = 0x16; + + this->aics[param_1].SortieUnitMeleeMin = 4; + + this->aics[param_1].DefDiggingUnitMax = 10; + + this->aics[param_1].DefDiggingUnit = 0x16; + + this->aics[param_1].OuterPatrolRallyDelay = 10; + + this->aics[param_1].DefUnit1 = 0x16; + + this->aics[param_1].DefUnit2 = 0x16; + + this->aics[param_1].RaidUnitsBase = 4; + + this->aics[param_1].AttForceRandom = 4; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackWeak = 0; + + this->aics[param_1].recruitProbAttackDefault = 0x1e; + + this->aics[param_1].recruitProbAttackStrong = 0x32; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].SortieUnitRangedMin = 0xc; + + this->aics[param_1].SortieUnitMelee = 0x1b; + + this->aics[param_1].DefWalls = 0x32; + + this->aics[param_1].DefTotal = 0x50; + + this->aics[param_1].OuterPatrolGroupsCount = 2; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].DefUnit3 = 0x17; + + this->aics[param_1].RaidUnitsRandom = 0; + + this->aics[param_1].RaidUnit1 = 0x1c; + + this->aics[param_1].HarassingSiegeEnginesMax = 2; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].RaidRetargetDelay = 6; + + this->aics[param_1].AttForceBase = 0x1e; + + this->aics[param_1].AttForceRallyPercentage = 0x32; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0x14; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x32; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x28; + + this->aics[param_1].SiegeEngine2 = 0x28; + + this->aics[param_1].SiegeEngine3 = 0x28; + + this->aics[param_1].SiegeEngine4 = 0x28; + + this->aics[param_1].SiegeEngine5 = 0x28; + + this->aics[param_1].SiegeEngine6 = 0x28; + + this->aics[param_1].AttMaxEngineers = 0x12; + + this->aics[param_1].AttDiggingUnit = 0x16; + + this->aics[param_1].AttDiggingUnitMax = 0x14; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0x17; + + this->aics[param_1].AttUnitPatrolMax = 0x14; + + this->aics[param_1].AttUnitPatrolGroupsCount = 1; + + this->aics[param_1].AttUnitBackup = 0x16; + + this->aics[param_1].AttUnitBackupMax = 0x1e; + + this->aics[param_1].AttUnitBackupGroupsCount = 2; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0x17; + + this->aics[param_1].AttUnitSiegeDefMax = 10; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; + + this->aics[param_1].AttUnitMain1 = 0x1b; + + this->aics[param_1].AttUnitMain2 = 0x1b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 4; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp new file mode 100644 index 000000000..0d6b6afba --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp @@ -0,0 +1,283 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C9120 + void AICState ::setAICParameters_10(int param_1) + + { + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].farm1 = 0x20; + + this->aics[param_1].farm2 = 0x20; + + this->aics[param_1].tradeAmountEquipment = 2; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x3c; + + this->aics[param_1].resourceRebuildDelay = 0x3c; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 8000; + + this->aics[param_1].taxesMax = 10; + + this->aics[param_1].populationPerFarm = 5; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].minimumCheese = 10; + + this->aics[param_1].minimumBread = 10; + + this->aics[param_1].tradeAmountFood = 0x14; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + + this->aics[param_1].doubleRationsFoodThreshold = 0x32; + + this->aics[param_1].maxResourceOther = 0xf; + + this->aics[param_1].maxEquipment = 6; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 0; + + this->aics[param_1].populationPerIronmine = 7; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 1; + + this->aics[param_1].maxIronmines = 3; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 8; + + this->aics[param_1].buildInterval = 4; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource02 = 3; + + this->aics[param_1].sellResource04 = 7; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource06 = 0xe; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x46; + + this->aics[param_1].recruitProbDefDefault = 0x28; + + this->aics[param_1].RecruitIntervalWeak = 4; + + this->aics[param_1].RecruitInterval = 4; + + this->aics[param_1].RecruitIntervalStrong = 4; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].DefWalls = 4; + + this->aics[param_1].OuterPatrolGroupsCount = 4; + + this->aics[param_1].RaidUnitsBase = 4; + + this->aics[param_1].RaidUnitsRandom = 4; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 0x14; + + this->aics[param_1].recruitProbRaidStrong = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 10; + + this->aics[param_1].recruitProbAttackDefault = 0x14; + + this->aics[param_1].SortieUnitRanged = 0x16; + + this->aics[param_1].SortieUnitMeleeMin = 0x14; + + this->aics[param_1].DefTotal = 0x14; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].DefUnit2 = 0x16; + + this->aics[param_1].DefUnit3 = 0x16; + + this->aics[param_1].DefUnit4 = 0x16; + + this->aics[param_1].DefUnit5 = 0x16; + + this->aics[param_1].DefUnit6 = 0x16; + + this->aics[param_1].HarassingSiegeEnginesMax = 1; + + this->aics[param_1].recruitProbRaidDefault = 0x28; + + this->aics[param_1].recruitProbAttackStrong = 0x3c; + + this->aics[param_1].SortieUnitRangedMin = 2; + + this->aics[param_1].SortieUnitMelee = 0x18; + + this->aics[param_1].DefDiggingUnit = 0x18; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].DefUnit1 = 0x1c; + + this->aics[param_1].RaidUnit1 = 0x1c; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].AttForceBase = 10; + + this->aics[param_1].AttForceRandom = 0x14; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x28; + + this->aics[param_1].AttForceRallyPercentage = 0x28; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x46; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0; + + this->aics[param_1].AttMaxEngineers = 0; + + this->aics[param_1].AttDiggingUnit = 0x18; + + this->aics[param_1].AttDiggingUnitMax = 0x3c; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0x18; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0; + + this->aics[param_1].AttUnitBackupMax = 0; + + this->aics[param_1].AttUnitBackupGroupsCount = 0; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x18; + + this->aics[param_1].AttUnitMain2 = 0x18; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 2; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_11.cpp b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp new file mode 100644 index 000000000..9f6a82e8a --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp @@ -0,0 +1,281 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C94F0 + void AICState ::setAICParameters_11(int param_1) + + { + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].minimumApples = 0xffffffff; + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 2; + + this->aics[param_1].minimumHop = 0xffffffff; + + this->aics[param_1].flagType = 10; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 0x1194; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 8000; + + this->aics[param_1].taxesMax = 0xc; + + this->aics[param_1].farm1 = 0x1e; + + this->aics[param_1].populationPerFarm = 5; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].tradeAmountFood = 0x14; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].aiRequestDelay = 0x16; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x1e; + + this->aics[param_1].doubleRationsFoodThreshold = 0x32; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x28; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 4; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 100; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 6; + + this->aics[param_1].populationPerIronmine = 0xc; + + this->aics[param_1].populationPerPitchrig = 6; + + this->aics[param_1].maxQuarries = 3; + + this->aics[param_1].maxIronmines = 1; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxPitchrigs = 4; + + this->aics[param_1].maxFarms = 8; + + this->aics[param_1].buildInterval = 3; + + this->aics[param_1].resourceRebuildDelay = 0x32; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource02 = 3; + + this->aics[param_1].sellResource03 = 6; + + this->aics[param_1].sellResource06 = 0xe; + + this->aics[param_1].sellResource08 = 0x11; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x46; + + this->aics[param_1].recruitProbDefDefault = 0x1e; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].recruitProbRaidStrong = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 0x1e; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].RaidUnitsBase = 0x1e; + + this->aics[param_1].HarassingSiegeEnginesMax = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].SortieUnitMeleeMin = 10; + + this->aics[param_1].RaidUnitsRandom = 10; + + this->aics[param_1].recruitProbRaidWeak = 0; + + this->aics[param_1].recruitProbAttackDefault = 0x32; + + this->aics[param_1].recruitProbAttackStrong = 0x3c; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].RecruitInterval = 1; + + this->aics[param_1].RecruitIntervalStrong = 1; + + this->aics[param_1].SortieUnitRangedMin = 6; + + this->aics[param_1].SortieUnitMelee = 0x4b; + + this->aics[param_1].DefDiggingUnit = 0x47; + + this->aics[param_1].DefWalls = 0x28; + + this->aics[param_1].DefTotal = 0x28; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].DefUnit1 = 0x46; + + this->aics[param_1].DefUnit2 = 0x4c; + + this->aics[param_1].HarassingSiegeEngine1 = 0x166; + + this->aics[param_1].AttForceBase = 0x28; + + this->aics[param_1].AttForceRandom = 5; + + this->aics[param_1].SortieUnitRanged = 0x4a; + + this->aics[param_1].RaidUnit1 = 0x4a; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; + + this->aics[param_1].AttForceRallyPercentage = 0x50; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 4; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x5a; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x28; + + this->aics[param_1].SiegeEngine2 = 0x4d; + + this->aics[param_1].SiegeEngine3 = 0x4d; + + this->aics[param_1].SiegeEngine4 = 0x4d; + + this->aics[param_1].AttMaxEngineers = 9; + + this->aics[param_1].AttDiggingUnit = 0x47; + + this->aics[param_1].AttDiggingUnitMax = 0xf; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x4a; + + this->aics[param_1].AttUnitBackupMax = 0x50; + + this->aics[param_1].AttUnitBackupGroupsCount = 1; + + this->aics[param_1].AttUnitEngageMax = 10; + + this->aics[param_1].AttUnitEngage = 0x4c; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x4b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 2; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp new file mode 100644 index 000000000..a09be5a21 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp @@ -0,0 +1,281 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C9900 + void AICState ::setAICParameters_12(int param_1) + + { + + this->aics[param_1].farm1 = 0x1e; + + this->aics[param_1].farm3 = 0x1e; + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].flagType = 10; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 0x1194; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].taxesMax = 0xc; + + this->aics[param_1].farm2 = 0x20; + + this->aics[param_1].farm4 = 0x1f; + + this->aics[param_1].populationPerFarm = 4; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 0x50; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].minimumWheat = 2; + + this->aics[param_1].minimumHop = 2; + + this->aics[param_1].tradeAmountFood = 0x14; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + + this->aics[param_1].doubleRationsFoodThreshold = 0x28; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x3c; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 4; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 6; + + this->aics[param_1].populationPerIronmine = 10; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 4; + + this->aics[param_1].maxIronmines = 3; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 0x10; + + this->aics[param_1].buildInterval = 2; + + this->aics[param_1].resourceRebuildDelay = 0x28; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x50; + + this->aics[param_1].recruitProbDefDefault = 0x28; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 10; + + this->aics[param_1].SortieUnitRangedMin = 4; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 10; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].SortieUnitMeleeMin = 0x14; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].RaidUnitsRandom = 10; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackDefault = 0x28; + + this->aics[param_1].recruitProbAttackStrong = 0x32; + + this->aics[param_1].RecruitInterval = 0; + + this->aics[param_1].RecruitIntervalStrong = 0; + + this->aics[param_1].SortieUnitRanged = 0x46; + + this->aics[param_1].SortieUnitMelee = 0x4b; + + this->aics[param_1].DefDiggingUnit = 0x16; + + this->aics[param_1].DefWalls = 0x32; + + this->aics[param_1].DefTotal = 0x32; + + this->aics[param_1].DefUnit1 = 0x16; + + this->aics[param_1].DefUnit2 = 0x46; + + this->aics[param_1].RaidUnitsBase = 0x1e; + + this->aics[param_1].RaidUnit1 = 0x4b; + + this->aics[param_1].HarassingSiegeEnginesMax = 3; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].HarassingSiegeEngine2 = 0xbe; + + this->aics[param_1].HarassingSiegeEngine3 = 0x166; + + this->aics[param_1].AttForceBase = 0x1e; + + this->aics[param_1].AttForceRandom = 10; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x14; + + this->aics[param_1].AttForceRallyPercentage = 0x50; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x50; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x27; + + this->aics[param_1].SiegeEngine2 = 0x27; + + this->aics[param_1].SiegeEngine3 = 0x3d; + + this->aics[param_1].AttMaxEngineers = 6; + + this->aics[param_1].AttDiggingUnit = 0x16; + + this->aics[param_1].AttDiggingUnitMax = 0xf; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x4a; + + this->aics[param_1].AttUnitBackupMax = 0x50; + + this->aics[param_1].AttUnitBackupGroupsCount = 1; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x4b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 2; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_13.cpp b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp new file mode 100644 index 000000000..be05cbf93 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp @@ -0,0 +1,275 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004C9CF0 + void AICState ::setAICParameters_13(int param_1) + + { + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].minimumWheat = 5; + + this->aics[param_1].minimumHop = 5; + + this->aics[param_1].recruitGoldThreshold = 100; + + this->aics[param_1].flagType = 10; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 0x1194; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].taxesMax = 0xc; + + this->aics[param_1].farm1 = 0x1e; + + this->aics[param_1].farm2 = 0x1e; + + this->aics[param_1].farm3 = 0x1e; + + this->aics[param_1].farm4 = 0x1f; + + this->aics[param_1].populationPerFarm = 3; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].tradeAmountFood = 10; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x1e; + + this->aics[param_1].doubleRationsFoodThreshold = 0x1e; + + this->aics[param_1].maxWood = 0x32; + + this->aics[param_1].maxStone = 0x28; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 4; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 0x14; + + this->aics[param_1].populationPerIronmine = 10; + + this->aics[param_1].populationPerPitchrig = 0xf; + + this->aics[param_1].maxQuarries = 1; + + this->aics[param_1].maxIronmines = 2; + + this->aics[param_1].maxWoodcutters = 0xc; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 0x10; + + this->aics[param_1].buildInterval = 1; + + this->aics[param_1].resourceRebuildDelay = 0x14; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource03 = 6; + + this->aics[param_1].sellResource08 = 0x11; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x50; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackDefault = 0x1e; + + this->aics[param_1].RecruitIntervalStrong = 1; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].RecruitInterval = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].recruitProbDefDefault = 0x32; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 0; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].recruitProbAttackWeak = 0x14; + + this->aics[param_1].recruitProbAttackStrong = 0x32; + + this->aics[param_1].RecruitIntervalWeak = 8; + + this->aics[param_1].SortieUnitRanged = 0x46; + + this->aics[param_1].SortieUnitMeleeMin = 0xf; + + this->aics[param_1].SortieUnitMelee = 0x46; + + this->aics[param_1].DefDiggingUnitMax = 0x3c; + + this->aics[param_1].DefDiggingUnit = 0x47; + + this->aics[param_1].DefWalls = 0x50; + + this->aics[param_1].DefTotal = 0x50; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].DefUnit1 = 0x46; + + this->aics[param_1].HarassingSiegeEnginesMax = 0; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].AttForceBase = 0x28; + + this->aics[param_1].AttForceRandom = 0; + + this->aics[param_1].SortieUnitRangedMin = 5; + + this->aics[param_1].RaidUnitsBase = 5; + + this->aics[param_1].RaidUnitsRandom = 5; + + this->aics[param_1].RaidUnit1 = 0x49; + + this->aics[param_1].AttForceSupportAllyThreshold = 10; + + this->aics[param_1].AttForceRallyPercentage = 0x32; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x32; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x27; + + this->aics[param_1].AttMaxEngineers = 0; + + this->aics[param_1].AttDiggingUnit = 0x47; + + this->aics[param_1].AttDiggingUnitMax = 0x14; + + this->aics[param_1].AttMaxAssassins = 0x28; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x4a; + + this->aics[param_1].AttUnitBackupMax = 0; + + this->aics[param_1].AttUnitBackupGroupsCount = 0; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x49; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 4; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp new file mode 100644 index 000000000..c5590667e --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp @@ -0,0 +1,289 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CA0C0 + void AICState ::setAICParameters_14(int param_1) + + { + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].minimumHop = 2; + + this->aics[param_1].tradeAmountEquipment = 2; + + this->aics[param_1].defWallPatrolGroups = 2; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].aiRequestDelay = 0x28; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x28; + + this->aics[param_1].doubleRationsFoodThreshold = 0x28; + + this->aics[param_1].defSiegeEngineGoldThreshold = 200; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 6000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 3; + + this->aics[param_1].taxesMax = 0xb; + + this->aics[param_1].farm1 = 0x20; + + this->aics[param_1].farm2 = 0x1f; + + this->aics[param_1].farm3 = 0x21; + + this->aics[param_1].populationPerFarm = 4; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 300; + + this->aics[param_1].minimumApples = 0x14; + + this->aics[param_1].minimumCheese = 0x14; + + this->aics[param_1].tradeAmountFood = 10; + + this->aics[param_1].maxWood = 0x32; + + this->aics[param_1].maxStone = 0x32; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 10; + + this->aics[param_1].maxBeer = 10; + + this->aics[param_1].maxResourceVariance = 5; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 10; + + this->aics[param_1].populationPerIronmine = 0xc; + + this->aics[param_1].populationPerPitchrig = 0xf; + + this->aics[param_1].maxQuarries = 3; + + this->aics[param_1].maxIronmines = 6; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxPitchrigs = 4; + + this->aics[param_1].maxFarms = 10; + + this->aics[param_1].buildInterval = 3; + + this->aics[param_1].resourceRebuildDelay = 8; + + this->aics[param_1].blacksmithSetting = 0x15; + + this->aics[param_1].fletcherSetting = 0x12; + + this->aics[param_1].poleturnerSetting = 0x14; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource08 = 0x11; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 8; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown073 = 0x1e; + + this->aics[param_1].recruitProbDefWeak = 100; + + this->aics[param_1].recruitProbDefDefault = 0x32; + + this->aics[param_1].recruitProbDefStrong = 0x1e; + + this->aics[param_1].recruitProbRaidDefault = 0x1e; + + this->aics[param_1].RecruitInterval = 4; + + this->aics[param_1].RecruitIntervalStrong = 4; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].RaidUnitsRandom = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].recruitProbAttackDefault = 0x14; + + this->aics[param_1].recruitProbAttackStrong = 0x14; + + this->aics[param_1].recruitProbRaidStrong = 0x32; + + this->aics[param_1].SortieUnitRangedMin = 10; + + this->aics[param_1].SortieUnitMeleeMin = 10; + + this->aics[param_1].DefTotal = 0x32; + + this->aics[param_1].RaidUnitsBase = 10; + + this->aics[param_1].recruitProbRaidWeak = 0; + + this->aics[param_1].recruitProbAttackWeak = 0; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].SortieUnitRanged = 0x17; + + this->aics[param_1].DefWalls = 0x28; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 5; + + this->aics[param_1].DefUnit1 = 0x17; + + this->aics[param_1].DefUnit2 = 0x17; + + this->aics[param_1].DefUnit3 = 0x17; + + this->aics[param_1].DefUnit4 = 0x4c; + + this->aics[param_1].DefUnit5 = 0x49; + + this->aics[param_1].HarassingSiegeEnginesMax = 5; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].HarassingSiegeEngine2 = 0x166; + + this->aics[param_1].SortieUnitMelee = 0x1a; + + this->aics[param_1].DefDiggingUnit = 0x1a; + + this->aics[param_1].RaidUnit1 = 0x1a; + + this->aics[param_1].AttForceBase = 0x32; + + this->aics[param_1].AttForceRandom = 0x14; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x32; + + this->aics[param_1].AttForceRallyPercentage = 0x50; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 5; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 8; + + this->aics[param_1].AttCoordinationPreference = 0x32; + + this->aics[param_1].CowThrowInterval = 6; + + this->aics[param_1].SiegeEngine1 = 0x27; + + this->aics[param_1].SiegeEngine2 = 0x27; + + this->aics[param_1].SiegeEngine3 = 0x4d; + + this->aics[param_1].SiegeEngine4 = 0x4d; + + this->aics[param_1].SiegeEngine5 = 0x4d; + + this->aics[param_1].AttMaxEngineers = 10; + + this->aics[param_1].AttDiggingUnit = 0x47; + + this->aics[param_1].AttDiggingUnitMax = 0x50; + + this->aics[param_1].AttMaxAssassins = 10; + + this->aics[param_1].AttUnit2 = 0x1a; + + this->aics[param_1].AttUnit2Max = 10; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0x4c; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x17; + + this->aics[param_1].AttUnitBackupMax = 0x32; + + this->aics[param_1].AttUnitBackupGroupsCount = 1; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0x1a; + + this->aics[param_1].AttUnitSiegeDefMax = 6; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; + + this->aics[param_1].AttUnitMain1 = 0x1a; + + this->aics[param_1].AttUnitMain2 = 0x1a; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 3; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_15.cpp b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp new file mode 100644 index 000000000..db36e5ca0 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp @@ -0,0 +1,275 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CA4D0 + void AICState ::setAICParameters_15(int param_1) + + { + + this->aics[param_1].farm1 = 0x21; + + this->aics[param_1].farm3 = 0x21; + + this->aics[param_1].farm4 = 0x21; + + this->aics[param_1].populationPerFarm = 5; + + this->aics[param_1].minimumHop = 5; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 0xffffffff; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 7; + + this->aics[param_1].populationPerIronmine = 7; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].maxResourceOther = 0xc; + + this->aics[param_1].maxIronmines = 3; + + this->aics[param_1].buildInterval = 3; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 4000; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 8000; + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].taxesMax = 10; + + this->aics[param_1].farm2 = 0x1f; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].minimumCheese = 10; + + this->aics[param_1].tradeAmountFood = 0x14; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 0; + + this->aics[param_1].doubleRationsFoodThreshold = 0x50; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x32; + + this->aics[param_1].maxEquipment = 10; + + this->aics[param_1].maxBeer = 6; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 200; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 1; + + this->aics[param_1].maxWoodcutters = 8; + + this->aics[param_1].maxPitchrigs = 1; + + this->aics[param_1].maxFarms = 9; + + this->aics[param_1].resourceRebuildDelay = 0x28; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource04 = 7; + + this->aics[param_1].sellResource05 = 9; + + this->aics[param_1].sellResource07 = 0x10; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].RecruitIntervalStrong = 4; + + this->aics[param_1].SortieUnitRangedMin = 4; + + this->aics[param_1].SortieUnitMeleeMin = 4; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].RaidUnitsRandom = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].recruitProbRaidWeak = 0x28; + + this->aics[param_1].recruitProbRaidDefault = 0x28; + + this->aics[param_1].recruitProbAttackWeak = 10; + + this->aics[param_1].SortieUnitRanged = 0x16; + + this->aics[param_1].DefDiggingUnit = 0x16; + + this->aics[param_1].DefTotal = 0x28; + + this->aics[param_1].DefUnit1 = 0x16; + + this->aics[param_1].AttForceBase = 10; + + this->aics[param_1].AttForceSupportAllyThreshold = 10; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x32; + + this->aics[param_1].recruitProbDefDefault = 0x1e; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackDefault = 0x1e; + + this->aics[param_1].recruitProbAttackStrong = 0x32; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].RecruitInterval = 1; + + this->aics[param_1].SortieUnitMelee = 0x1c; + + this->aics[param_1].DefWalls = 0x1e; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].RaidUnitsBase = 0x10; + + this->aics[param_1].RaidUnit1 = 0x1c; + + this->aics[param_1].HarassingSiegeEnginesMax = 1; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].AttForceRandom = 0x14; + + this->aics[param_1].AttForceRallyPercentage = 0x32; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x46; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x28; + + this->aics[param_1].SiegeEngine2 = 0x28; + + this->aics[param_1].AttMaxEngineers = 6; + + this->aics[param_1].AttDiggingUnit = 0x16; + + this->aics[param_1].AttDiggingUnitMax = 0x14; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x16; + + this->aics[param_1].AttUnitBackupMax = 0x1e; + + this->aics[param_1].AttUnitBackupGroupsCount = 3; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x1b; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 2; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAICParameters_16.cpp b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp new file mode 100644 index 000000000..98b8a0d26 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp @@ -0,0 +1,277 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CA8A0 + void AICState ::setAICParameters_16(int param_1) + + { + + this->aics[param_1].taxesMax = 0xc; + + this->aics[param_1].farm2 = 0x1e; + + this->aics[param_1].farm3 = 0x1e; + + this->aics[param_1].aiRequestDelay = 0xc; + + this->aics[param_1].maxFarms = 0xc; + + this->aics[param_1].flagType = 0xd; + + this->aics[param_1].unknown002 = 0; + + this->aics[param_1].unknown001 = 0; + + this->aics[param_1].unknown003 = 0; + + this->aics[param_1].unknown004 = 1; + + this->aics[param_1].unknown005 = 1; + + this->aics[param_1].criticalPopularity = 0x1194; + + this->aics[param_1].lowestPopularity = 5000; + + this->aics[param_1].highestPopularity = 9000; + + this->aics[param_1].taxesMin = 2; + + this->aics[param_1].farm1 = 0x1f; + + this->aics[param_1].populationPerFarm = 4; + + this->aics[param_1].unknown011 = 10; + + this->aics[param_1].maxFood = 100; + + this->aics[param_1].minimumApples = 10; + + this->aics[param_1].minimumCheese = 0xffffffff; + + this->aics[param_1].minimumBread = 0xffffffff; + + this->aics[param_1].minimumWheat = 2; + + this->aics[param_1].minimumHop = 2; + + this->aics[param_1].tradeAmountFood = 5; + + this->aics[param_1].tradeAmountEquipment = 0; + + this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; + + this->aics[param_1].doubleRationsFoodThreshold = 0x28; + + this->aics[param_1].maxWood = 0x3c; + + this->aics[param_1].maxStone = 0x28; + + this->aics[param_1].maxResourceOther = 10; + + this->aics[param_1].maxEquipment = 4; + + this->aics[param_1].maxBeer = 5; + + this->aics[param_1].maxResourceVariance = 4; + + this->aics[param_1].recruitGoldThreshold = 0x32; + + this->aics[param_1].populationPerWoodcutter = 7; + + this->aics[param_1].populationPerQuarry = 6; + + this->aics[param_1].populationPerIronmine = 10; + + this->aics[param_1].populationPerPitchrig = 0; + + this->aics[param_1].maxQuarries = 4; + + this->aics[param_1].maxIronmines = 2; + + this->aics[param_1].maxWoodcutters = 10; + + this->aics[param_1].maxPitchrigs = 0; + + this->aics[param_1].buildInterval = 2; + + this->aics[param_1].resourceRebuildDelay = 0x28; + + this->aics[param_1].blacksmithSetting = 0x16; + + this->aics[param_1].fletcherSetting = 0x11; + + this->aics[param_1].poleturnerSetting = 0x13; + + this->aics[param_1].sellResource03 = 6; + + this->aics[param_1].sellResource09 = 0x12; + + this->aics[param_1].sellResource10 = 0x13; + + this->aics[param_1].sellResource11 = 0x14; + + this->aics[param_1].sellResource12 = 0x15; + + this->aics[param_1].sellResource13 = 0x16; + + this->aics[param_1].sellResource14 = 0x17; + + this->aics[param_1].sellResource15 = 0x18; + + this->aics[param_1].defWallPatrolRallyTime = 2; + + this->aics[param_1].defWallPatrolGroups = 3; + + this->aics[param_1].defSiegeEngineGoldThreshold = 100; + + this->aics[param_1].defSiegeEngineBuildDelay = 4; + + this->aics[param_1].unknown072 = 200; + + this->aics[param_1].unknown073 = 0x14; + + this->aics[param_1].recruitProbDefWeak = 0x50; + + this->aics[param_1].recruitProbDefDefault = 0x28; + + this->aics[param_1].recruitProbDefStrong = 0x14; + + this->aics[param_1].recruitProbRaidWeak = 10; + + this->aics[param_1].SortieUnitRangedMin = 4; + + this->aics[param_1].DefDiggingUnitMax = 4; + + this->aics[param_1].RaidRetargetDelay = 4; + + this->aics[param_1].RecruitIntervalWeak = 1; + + this->aics[param_1].RecruitInterval = 1; + + this->aics[param_1].RecruitIntervalStrong = 1; + + this->aics[param_1].SortieUnitRanged = 0x16; + + this->aics[param_1].DefDiggingUnit = 0x16; + + this->aics[param_1].OuterPatrolGroupsCount = 1; + + this->aics[param_1].OuterPatrolGroupsMove = 1; + + this->aics[param_1].OuterPatrolRallyDelay = 2; + + this->aics[param_1].DefUnit1 = 0x16; + + this->aics[param_1].recruitProbRaidDefault = 0x14; + + this->aics[param_1].recruitProbRaidStrong = 0x1e; + + this->aics[param_1].recruitProbAttackWeak = 10; + + this->aics[param_1].recruitProbAttackDefault = 0x28; + + this->aics[param_1].recruitProbAttackStrong = 0x32; + + this->aics[param_1].SortieUnitMeleeMin = 0x14; + + this->aics[param_1].SortieUnitMelee = 0x25; + + this->aics[param_1].DefWalls = 0x1e; + + this->aics[param_1].DefTotal = 0x1e; + + this->aics[param_1].RaidUnitsBase = 0x1e; + + this->aics[param_1].RaidUnitsRandom = 10; + + this->aics[param_1].RaidUnit1 = 0x25; + + this->aics[param_1].HarassingSiegeEnginesMax = 5; + + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; + + this->aics[param_1].AttForceBase = 0x32; + + this->aics[param_1].AttForceRandom = 10; + + this->aics[param_1].AttForceSupportAllyThreshold = 0x28; + + this->aics[param_1].AttForceRallyPercentage = 0x50; + + this->aics[param_1].AttMovingTribesThreshold = 100; + + this->aics[param_1].AttAssaultDelay = 0; + + this->aics[param_1].AttUnitPatrolRecommandDelay = 5; + + this->aics[param_1].AttCoordinationPreference = 0x50; + + this->aics[param_1].CowThrowInterval = 10000; + + this->aics[param_1].SiegeEngine1 = 0x27; + + this->aics[param_1].SiegeEngine2 = 0x27; + + this->aics[param_1].SiegeEngine3 = 0x27; + + this->aics[param_1].SiegeEngine4 = 0x27; + + this->aics[param_1].AttMaxEngineers = 8; + + this->aics[param_1].AttDiggingUnit = 0x16; + + this->aics[param_1].AttDiggingUnitMax = 10; + + this->aics[param_1].AttMaxAssassins = 0; + + this->aics[param_1].AttUnit2 = 0; + + this->aics[param_1].AttUnit2Max = 0; + + this->aics[param_1].AttMaxLaddermen = 0; + + this->aics[param_1].AttMaxTunnelers = 0; + + this->aics[param_1].AttUnitPatrol = 0; + + this->aics[param_1].AttUnitPatrolMax = 0; + + this->aics[param_1].AttUnitPatrolGroupsCount = 0; + + this->aics[param_1].AttUnitBackup = 0x16; + + this->aics[param_1].AttUnitBackupMax = 0x28; + + this->aics[param_1].AttUnitBackupGroupsCount = 1; + + this->aics[param_1].AttUnitEngageMax = 0; + + this->aics[param_1].AttUnitEngage = 0; + + this->aics[param_1].AttUnitSiegeDef = 0; + + this->aics[param_1].AttUnitSiegeDefMax = 0; + + this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; + + this->aics[param_1].AttUnitMain1 = 0x25; + + this->aics[param_1].AttMaxDefault = 200; + + this->aics[param_1].AttMainGroupsCount = 2; + + this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp index 2a27d6607..339f09d84 100644 --- a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp +++ b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp @@ -18,14 +18,14 @@ namespace AI { if (90 < _willingnessPercentage) { _willingnessPercentage = 90; } - int _rng = (int)SEC_RNG::instance.currentNumber2; + int _rngMod100 = (int)(short)SEC_RNG::instance.currentNumber2 % 100; MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - if (_rng % 100 < _willingnessPercentage / 2) { + if (_rngMod100 < _willingnessPercentage / 2) { DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = 2; return; } DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel - = (uint)(_rng % 100 < _willingnessPercentage); + = (uint)(_rngMod100 < _willingnessPercentage); } } } diff --git a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp index 772489730..79dbdfb54 100644 --- a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp +++ b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp @@ -13,14 +13,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF5E0 void AICState::setEightTribe0xc0TribesToAggressiveAndAttack(int playerID) { - int _tribeID; - int iVar1; - short* psVar2; if (DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) { - iVar1 = 0; - psVar2 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xc0; + int iVar1 = 0; + short* psVar2 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xc0; do { - _tribeID = (int)*psVar2; + int _tribeID = (int)*psVar2; if (((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar1 + 0xc0])) diff --git a/src/OpenSHC/AI/AICState/setInitialAIC.cpp b/src/OpenSHC/AI/AICState/setInitialAIC.cpp new file mode 100644 index 000000000..e8bcb8cdb --- /dev/null +++ b/src/OpenSHC/AI/AICState/setInitialAIC.cpp @@ -0,0 +1,52 @@ +#include "OpenSHC/AI/AICState.func.hpp" + +namespace OpenSHC { +namespace AI { + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D18B0 + void AICState ::setInitialAIC() + + { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::wipeAICMemory, this)(); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_01, this)(1); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_02, this)(2); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_03, this)(3); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_04, this)(4); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_05, this)(5); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_06, this)(6); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_07, this)(7); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_08, this)(8); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_09, this)(9); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_10, this)(10); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_11, this)(0xb); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_12, this)(0xc); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_13, this)(0xd); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_14, this)(0xe); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_15, this)(0xf); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_16, this)(0x10); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp b/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp new file mode 100644 index 000000000..072dc6674 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp @@ -0,0 +1,52 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/LandscapeState.func.hpp" +#include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_LandscapeState.hpp" +#include "OpenSHC/Globals/DAT_PathFindingState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CE3B0 + void AICState ::setNextMoveLocationForUnits(int playerID) + + { + + if ((short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX] + != 0) { + + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)( + (int)(short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]); + } + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, + (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY)), -1, -1, 4000, FALSE); + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::setDestinationPairsBasedOnPreviousSearch, + DAT_PathFindingState::ptr)( + playerID + -1, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp new file mode 100644 index 000000000..080fa0a94 --- /dev/null +++ b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp @@ -0,0 +1,196 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIC/AITargetChoice.hpp" +#include "OpenSHC/AI/AIC/AITargetChoiceInt.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" + +#include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIC::AITargetChoice; + using OpenSHC::AI::AIC::AITargetChoiceInt; + using OpenSHC::Game::Player::PlayerData; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CACB0 + void AICState ::setTargetForTribeBasedOnTargetChoiceLogic(int owner, int tribe) + + { + + int _lord; + + int _lordBackup; + + int _minDistance; + + int _distance; + + int _targetPlayer; + + PlayerData* _ptrPlayerData; + + int _playerID_backup; + + int _player; + + PlayerData* _ptrPlayerData_backup; + + int _maxGold; + + int _minPoints; + + int _aiType; + + int _gold; + + int _points; + + int _ownerKeepX; + + int _ownerKeepY; + + AITargetChoiceInt _targetChoice; + + _aiType = DAT_GameState::instance.playerDataArray[owner].aiType; + + _targetPlayer = 0; + + if (_aiType != 0) { + + _ownerKeepY = DAT_GameState::instance.playerDataArray[owner].campground.yEntry; + + _ownerKeepX = DAT_GameState::instance.playerDataArray[owner].campground.xEntry; + + _minDistance = 10000; + + _maxGold = 0; + + _minPoints = 1000000; + + _player = 1; + + _ptrPlayerData = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); + + do { + + if ((DAT_GameState::instance.mapAndTime.playerTeams[_player] + != DAT_GameState::instance.mapAndTime.playerTeams[owner]) + && (_lord = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_player), + _lord != 0)) { + + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, + (_ptrPlayerData->campground).yEntry, _ownerKeepX, _ownerKeepY); + + _targetChoice = this->aics[_aiType + -1].TargetChoice; + + _gold = _maxGold; + + _points = _minPoints; + + if (_targetChoice == OpenSHC::AI::AIC::AITC_PLAYER) { + + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_player] != -1) { + + joined_r0x004cad9a: + _distance = DAT_DirectionAlgorithmState::instance.distanceHigh; + + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _minDistance) { + + LAB_004cadf6: + _minPoints = _points; + + _maxGold = _gold; + + _minDistance = _distance; + + _targetPlayer = _player; + } + } + + } + + else { + + if (_targetChoice == OpenSHC::AI::AIC::AITC_CLOSEST) + goto joined_r0x004cad9a; + + _distance = _minDistance; + + if (_targetChoice == OpenSHC::AI::AIC::AITC_GOLD) { + + _gold = _ptrPlayerData->currentResources[0xf]; + + if (_maxGold <= _ptrPlayerData->currentResources[0xf]) + goto LAB_004cadf6; + + } + + else if ((_targetChoice == OpenSHC::AI::AIC::AITC_BALANCED) + && (_points = _ptrPlayerData->currentPopulation * 5 + _ptrPlayerData->totalTroopValue + + _ptrPlayerData->currentResources[0xf] / 100 + + DAT_DirectionAlgorithmState::instance.distanceHigh * 2, + _points <= _minPoints)) + goto LAB_004cadf6; + } + } + + _player = _player + 1; + + _ptrPlayerData = _ptrPlayerData + 1; + + } while (_player < 9); + + if (_targetPlayer == 0) { + + _playerID_backup = 1; + + _ptrPlayerData_backup = &DAT_GameState::instance.playerDataArray[1]; + + do { + + if (((DAT_GameState::instance.mapAndTime.playerTeams[_playerID_backup] + != DAT_GameState::instance.mapAndTime.playerTeams[owner]) + && (_lordBackup + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_playerID_backup), + _lordBackup != 0)) + && (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData_backup->campground).xEntry, + (_ptrPlayerData_backup->campground).yEntry, _ownerKeepX, _ownerKeepY), + DAT_DirectionAlgorithmState::instance.distanceHigh <= _minDistance)) { + + _minDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + + _targetPlayer = _playerID_backup; + } + + _playerID_backup = _playerID_backup + 1; + + _ptrPlayerData_backup = _ptrPlayerData_backup + 1; + + } while (_playerID_backup < 9); + + if (_targetPlayer == 0) { + + return; + } + } + + DAT_TribesState::instance.tribes[tribe].targetPlayer_outpost = (short)_targetPlayer; + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp new file mode 100644 index 000000000..f7b90a16b --- /dev/null +++ b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp @@ -0,0 +1,152 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" +#include "OpenSHC/Game/Resources/ResourceTypeShort.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Map/Buildings/BuildingTypeShort.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Game::Resources::ResourceType; + using OpenSHC::Game::Resources::ResourceTypeShort; + using OpenSHC::Map::Buildings::BuildingType; + using OpenSHC::Map::Buildings::BuildingTypeShort; + + // FUNCTION: STRONGHOLDCRUSADER 0x004CBE30 + void AICState ::setupWorkshopProductionType(int playerID, int buildingID) + + { + + AITypeInt AVar1; + + int _aiTypeMin1; + + ResourceTypeShort RVar2; + + BuildingTypeShort _buildingType; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 == OpenSHC::AI::AIT_NULL) { + return; + } + + _buildingType = DAT_BuildingsState::instance.buildings[buildingID].buildingType; + + _aiTypeMin1 = AVar1 + ~OpenSHC::AI::AIT_NULL; + RVar2 = OpenSHC::Game::Resources::RT_SWORD; + + if (_buildingType == OpenSHC::Map::Buildings::BT_BLACKSMITH) { + + _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 200); + + if (_aiTypeMin1 == -999) { + + _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, + DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, + OpenSHC::Map::Buildings::BT_BLACKSMITH); + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = (ResourceTypeShort)_aiTypeMin1; + + return; + } + + RVar2 = OpenSHC::Game::Resources::RT_SWORD; + + if (_aiTypeMin1 == 0x16) + goto LAB_004cbf6a; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_MACE; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = OpenSHC::Game::Resources::RT_MACE; + + return; + } + + // orig: cmp dx, 0xe; jne 0x5a (skip poleturner block to fletcher/end) + // poleturner falls through, fletcher and end are jumped to + if (_buildingType == OpenSHC::Map::Buildings::BT_POLETURNER) { + + _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 0xd0); + + if (_aiTypeMin1 == -999) { + + _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, + DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, + OpenSHC::Map::Buildings::BT_POLETURNER); + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = (ResourceTypeShort)_aiTypeMin1; + + return; + } + + RVar2 = OpenSHC::Game::Resources::RT_SPEAR; + + if (_aiTypeMin1 == 0x13) + goto LAB_004cbf6a; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_PIKE; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_PIKE; + + return; + } + + if (_buildingType == OpenSHC::Map::Buildings::BT_FLETCHER) { + + _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 0xcc); + + if (_aiTypeMin1 == -999) { + + _aiTypeMin1 + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, + DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, + OpenSHC::Map::Buildings::BT_FLETCHER); + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType + = (ResourceTypeShort)_aiTypeMin1; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = (ResourceTypeShort)_aiTypeMin1; + + return; + } + + RVar2 = OpenSHC::Game::Resources::RT_BOW; + + if (_aiTypeMin1 == 0x11) + goto LAB_004cbf6a; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemType + = OpenSHC::Game::Resources::RT_CROSSBOW; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = OpenSHC::Game::Resources::RT_CROSSBOW; + } + + return; + + LAB_004cbf6a: + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = RVar2; + + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = RVar2; + + return; + } +} +} diff --git a/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp b/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp new file mode 100644 index 000000000..80ba930bb --- /dev/null +++ b/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp @@ -0,0 +1,203 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/Text/TextManager.func.hpp" +#include "OpenSHC/DE/SHCDE/eTextSections.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_TextManagerObject.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::DE::SHCDE::eTextSections; + using OpenSHC::Game::Player::PlayerData; + + /* + 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 0x004D05D0 + int AICState ::shareGoldAmongTeamMembers(int playerID, int gold) + + { + + int* piVar1; + + char cVar2; + + int _playerOffset; + + int _goldPerPlayer; + + char* pcVar3; + + char* pcVar4; + + PlayerData* _ptrPlayerData; + + int _totalPlayers; + + int _candidates[9]; + + int _targetPlayer; + + int _playerIndex; + + int _playerIndexTracker; + + int* _ptrCurrentGold; + + _totalPlayers = 0; + + _ptrPlayerData = &DAT_GameState::instance.playerDataArray[2]; + + _playerOffset = 0; + + _playerIndex = 3; + + do { + + if ((((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 4) != 0) + || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 4) + != -1)) + && (_playerIndex + -2 != playerID)) + && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 4) + == DAT_GameState::instance.mapAndTime.playerTeams[playerID] + && (DAT_GameState::instance.playerDataArray[1].lordKilledByPlayerID == 0)))) { + + /* + if lord of team member not dead, then: */ + + _candidates[_totalPlayers] = _playerIndex + -2; + + _totalPlayers = _totalPlayers + 1; + } + + if (((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 8) != 0) + || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 8) + != -1)) + && ((_playerIndex + -1 != playerID + && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 8) + == DAT_GameState::instance.mapAndTime.playerTeams[playerID] + && (_ptrPlayerData->lordKilledByPlayerID == 0)))))) { + + _candidates[_totalPlayers] = _playerIndex + -1; + + _totalPlayers = _totalPlayers + 1; + } + + if ((((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 0xc) != 0) + || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 0xc) + != -1)) + && (_playerIndex != playerID)) + && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 0xc) + == DAT_GameState::instance.mapAndTime.playerTeams[playerID] + && (DAT_GameState::instance.playerDataArray[3].lordKilledByPlayerID == 0)))) { + + _candidates[_totalPlayers] = _playerIndex; + + _totalPlayers = _totalPlayers + 1; + } + + if (((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 0x10) != 0) + || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 0x10) + != -1)) + && ((_playerIndex + 1 != playerID + && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 0x10) + == DAT_GameState::instance.mapAndTime.playerTeams[playerID] + && (DAT_GameState::instance.playerDataArray[4].lordKilledByPlayerID == 0)))))) { + + _candidates[_totalPlayers] = _playerIndex + 1; + + _totalPlayers = _totalPlayers + 1; + } + + _playerIndexTracker = _playerIndex + 2; + + _playerOffset = _playerOffset + 16; + + _ptrPlayerData = _ptrPlayerData + 0x39f4; + + _playerIndex = _playerIndex + 4; + + } while (_playerIndexTracker < 9); + + /* + fixme: repurposed variable */ + + if (((_totalPlayers != 0) + && (_goldPerPlayer = gold / _totalPlayers, _playerOffset = _goldPerPlayer, _goldPerPlayer != 0)) + && (_playerIndex = 0, 0 < _totalPlayers)) { + + _ptrCurrentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources + 0xf; + + do { + + _targetPlayer = _candidates[_playerIndex]; + + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_targetPlayer] != -1) { + + /* + "Goods received from ally" + added by script: "Goods received from ally" */ + + pcVar3 = MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::getTextStringInGroupAtOffset, + DAT_TextManagerObject::ptr)(OpenSHC::DE::SHCDE::TEXT_ALLIES2, 1); + + pcVar4 = DAT_GameSynchronyState::instance.receivedChatMessage; + + do { + + cVar2 = *pcVar3; + + *pcVar4 = cVar2; + + pcVar3 = pcVar3 + 1; + + pcVar4 = pcVar4 + 1; + + } while (cVar2 != '\0'); + + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::addChatMessageToDisplayList, + DAT_GameSynchronyState::ptr)(_targetPlayer, 0); + + /* + "Goods types" + added by script: "Gold" */ + + pcVar3 = MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::getTextStringInGroupAtOffset, + DAT_TextManagerObject::ptr)(OpenSHC::DE::SHCDE::TEXT_GOODS, 0xf); + + MACRO_CALL(OpenSHC::OS_Func::_sprintf)( + DAT_GameSynchronyState::instance.receivedChatMessage, "%d %s - ", _goldPerPlayer, pcVar3); + + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::addChatMessageToDisplayList, + DAT_GameSynchronyState::ptr)(_targetPlayer, playerID); + } + + *_ptrCurrentGold = *_ptrCurrentGold - _goldPerPlayer; + + piVar1 = DAT_GameState::instance.playerDataArray[_targetPlayer].currentResources + 0xf; + + *piVar1 = *piVar1 + _goldPerPlayer; + + _playerOffset = _targetPlayer * 0x39f4 + 0x115c304; + + _playerIndex = _playerIndex + 1; + + } while (_playerIndex < _totalPlayers); + } + + return _playerOffset; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp index 47697719a..e16bf1b27 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp @@ -9,11 +9,10 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004ECA90 BOOLEnum AICState::shouldNotBuildKillingPits(int playerID, Commands::CommandBuildingType commandBuildingType) { - BOOLEnum _totalAbove99 = FALSE; if (commandBuildingType == Commands::CBT_KILLINGPIT) { - _totalAbove99 = (BOOLEnum)(DAT_AIVState::instance.mapExtraInfo.playerTotalKillingPits[playerID] >= 100); + return (BOOLEnum)(DAT_AIVState::instance.mapExtraInfo.playerTotalKillingPits[playerID] >= 100); } - return _totalAbove99; + return FALSE; } } } diff --git a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp index 676b02f35..d2a7df33b 100644 --- a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp +++ b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp @@ -9,7 +9,6 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB700 BOOLEnum AICState::shouldWaitWithBuildingAPositiveFearFactor(int playerID, Commands::CommandBuildingType param_2) { - int* piVar1; switch (param_2) { case Commands::CBT_COMMUNAL_GARDEN1: case Commands::CBT_COMMUNAL_GARDEN2: @@ -39,8 +38,7 @@ namespace AI { case Commands::CBT_SMALL_POND_3: case Commands::CBT_LARGE_POND_3: case Commands::CBT_LARGE_POND_4: - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay; - *piVar1 = *piVar1 + 1; + DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay += 1; if (DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay < 200) { return TRUE; } diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp index a7b0d34e6..e4b8ffcd5 100644 --- a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -10,7 +10,7 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC9B0 - int AICState::smallestTribeOfUnitType(int playerID, short* unitType) + int AICState::smallestTribeOfUnitType(int playerID, UnitType unitType) { int iVar7 = 0; int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; @@ -22,15 +22,14 @@ namespace AI { int _tribeID = 0; int local_c = 0; short sVar4 = 1000; - if ((iVar3 < iVar6) - && (((unitType == (short*)0x8 || (unitType == (short*)0xa)) || (unitType == (short*)0x11)))) { + if ((iVar3 < iVar6) && (((unitType == 0x8 || (unitType == 0xa)) || (unitType == 0x11)))) { iVar6 = iVar3; } iVar3 = DAT_SkirmishDefinedData::instance.DAT_AiTribeIDOffsetForUnitType[(int)unitType]; if (0 < iVar6) { - unitType = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar3; + short* _aiTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar3; do { - int iVar5 = (int)*unitType; + int iVar5 = (int)*_aiTribeID; if ((iVar5 == 0) || (DAT_TribesState::instance.tribes[iVar5].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7])) { @@ -44,7 +43,7 @@ namespace AI { local_c = iVar7; sVar4 = sVar1; } - unitType = unitType + 1; + _aiTribeID = _aiTribeID + 1; iVar7 = iVar7 + 1; } while (iVar7 < iVar6); iVar7 = local_c; diff --git a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp new file mode 100644 index 000000000..7a9a56b30 --- /dev/null +++ b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp @@ -0,0 +1,210 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/GameCore.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Commands/GameCommandType.hpp" +#include "OpenSHC/Game/GameMode.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_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::Commands::GameCommandType; + using OpenSHC::Game::GameMode; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + 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 0x004D10B0 + void AICState ::someChatMessageSelection() + + { + + BOOLEnum BVar1; + + DWORD DVar2; + + int iVar3; + + int iVar4; + + int iVar5; + + int iVar6; + + int aiStack_24[9]; + + BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)(); + + if ((BVar1 != FALSE) + && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode == OpenSHC::Game::GM_SKIRMISH_SINGLE_PLAYER)) { + + if (this->aiTauntResponseTimeWindow == 0) { + + return; + } + + DVar2 = timeGetTime(); + + if (DVar2 - this->aiTauntResponseTimeWindow < 2000) { + + return; + } + + iVar6 = 0; + + iVar3 = 0; + + iVar4 = 3; + + do { + + if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 4) != 0) + && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 4) + != DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + + aiStack_24[iVar6] = iVar4 + -2; + + iVar6 = iVar6 + 1; + } + + if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 8) != 0) + && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 8) + != DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + + aiStack_24[iVar6] = iVar4 + -1; + + iVar6 = iVar6 + 1; + } + + if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 0xc) != 0) + && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 0xc) + != DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + + aiStack_24[iVar6] = iVar4; + + iVar6 = iVar6 + 1; + } + + if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 0x10) != 0) + && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 0x10) + != DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + + aiStack_24[iVar6] = iVar4 + 1; + + iVar6 = iVar6 + 1; + } + + iVar5 = iVar4 + 2; + + iVar3 = iVar3 + 0x10; + + iVar4 = iVar4 + 4; + + } while (iVar5 < 9); + + if (0 < iVar6) { + + iVar3 = 0; + + iVar4 = 0; + + if (0 < iVar6) { + + do { + + iVar3 = iVar3 + + DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping + [DAT_GameState::instance.playerDataArray[aiStack_24[iVar4]].aiType + + OpenSHC::AI::AIT_FREDERICK][0]; + + iVar4 = iVar4 + 1; + + } while (iVar4 < iVar6); + + if (iVar3 != 0) { + + iVar5 = (int)SEC_RNG::instance.currentNumber1; + + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber1, SEC_RNG::ptr)(); + + iVar5 = iVar5 % iVar3; + + iVar4 = 0; + + do { + + iVar3 = aiStack_24[iVar4]; + + iVar5 = iVar5 + - DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping + [DAT_GameState::instance.playerDataArray[iVar3].aiType + + OpenSHC::AI::AIT_FREDERICK][0]; + + if (iVar5 < 0) { + + DAT_GameSynchronyState::instance.DAT_ChatTauntOrMessage = -2 + - DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping + [DAT_GameState::instance.playerDataArray[iVar3].aiType + + OpenSHC::AI::AIT_FREDERICK][1]; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[1] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[2] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[3] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[4] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[5] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[6] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[7] = 1; + + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[8] = 1; + + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = iVar3; + + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, + DAT_GameSynchronyState::ptr)(OpenSHC::Commands::GCT_TAUNT_OR_CHAT); + + this->aiTauntResponseTimeWindow = 0; + + return; + } + + iVar4 = iVar4 + 1; + + } while (iVar4 < iVar6); + } + } + } + } + + this->aiTauntResponseTimeWindow = 0; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp index 9633dd0c3..63e7743bd 100644 --- a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp +++ b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp @@ -19,43 +19,43 @@ namespace AI { / _totalEnemyTroopValue); } DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy = _relativeStrength; - if (param_2 == FALSE) { - if (DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue < 100) { - return FALSE; - } + if (param_2 != FALSE) { BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); if (BVar2 != FALSE) { - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 50) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 0x46) { return TRUE; } return FALSE; } if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 250) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 300) { return TRUE; } return FALSE; } - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 75) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 100) { return TRUE; } } else { + if (DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue < 100) { + return FALSE; + } BOOLEnum BVar2 = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); if (BVar2 != FALSE) { - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 0x46) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 50) { return TRUE; } return FALSE; } if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 300) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 250) { return TRUE; } return FALSE; } - if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 100) { + if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 75) { return TRUE; } } diff --git a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp new file mode 100644 index 000000000..258a3215f --- /dev/null +++ b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp @@ -0,0 +1,40 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Game/Skirmish/SkirmishDefinedData.hpp" + +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::Game::Skirmish::SkirmishDefinedData; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CC8D0 + undefined4 AICState ::unitIDIsRangedOrArmored(int unitID) + + { + + SkirmishDefinedData* pSVar1; + + pSVar1 = DAT_SkirmishDefinedData::ptr; + + do { + + if (pSVar1->DAT_UnitTypes_RangedAndArmored[0] + == (int)(short)DAT_UnitsState::instance.units[unitID].unitType) { + + return (undefined4)(1); + } + + pSVar1 = (SkirmishDefinedData*)(pSVar1->DAT_UnitTypes_RangedAndArmored + 1); + + } while ((int)pSVar1 < 0xb3eb50); + + return (undefined4)(0); + } + +} +} diff --git a/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp new file mode 100644 index 000000000..6946450dd --- /dev/null +++ b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp @@ -0,0 +1,165 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/TileMapState.func.hpp" +#include "OpenSHC/AI/AIRecruitUnitChoice.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TileMapState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIRecruitUnitChoice; + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::Game::Player::PlayerData; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D53E0 + void AICState ::updateAIBehaviour() + + { + + AITypeInt AVar1; + + PlayerData* _aiType; + + int _playerID; + + if (DAT_GameState::instance.mapAndTime.dayTicks == 10) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeOutpostTribesAttack, this)(); + } + + _aiType = &DAT_GameState::instance.playerDataArray[1]; + + _playerID = 1; + + do { + + AVar1 = _aiType->aiType; + + if (((AVar1 != OpenSHC::AI::AIT_NULL) && (_aiType->playerDeathRelated == 0)) + && (_aiType->lordKilledByPlayerID == 0)) { + + if (DAT_GameState::instance.mapAndTime.dayTicks == _playerID) { + + if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieRangedUnits, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieMeleeUnits, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitUnits, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recruitHarrassingSiegeEngines, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignMoatDiggers, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCreateSiegeUnits, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineers, this)(_playerID); + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiBuyAndSellGoods, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiGiveRaidInstructions, this)(_playerID); + } + + if (DAT_GameState::instance.mapAndTime.weekTicks == _playerID) { + + if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineerForOilDuty, this)(_playerID); + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateTribeLocations, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIPlayerState, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiUpdateTaxesAndRations, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setFoodBuyPlan, this)(_playerID); + + if (DAT_GameState::instance.mapAndTime.monthTicks != _playerID) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 0); + } + + if (_aiType->aiRequestDelay != 0) { + + _aiType->aiRequestDelay = _aiType->aiRequestDelay + -1; + } + + if (_aiType->nervousBikCountdown != 0) { + + _aiType->nervousBikCountdown = _aiType->nervousBikCountdown + -1; + } + + if (_aiType->someAiCountdown3 != 0) { + + _aiType->someAiCountdown3 = _aiType->someAiCountdown3 + -1; + } + + if (_aiType->someAiCountdown4 != 0) { + + _aiType->someAiCountdown4 = _aiType->someAiCountdown4 + -1; + } + + if (_aiType->someAiCountdown5 != 0) { + + _aiType->someAiCountdown5 = _aiType->someAiCountdown5 + -1; + } + + if (_aiType->someAiCountdown6 != 0) { + + _aiType->someAiCountdown6 = _aiType->someAiCountdown6 + -1; + } + } + + if (DAT_GameState::instance.mapAndTime.monthTicks == _playerID) { + + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::countMoatsOwnedByEachPlayer, DAT_TileMapState::ptr)(); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::instructTribe166ToMove, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToSortieUnits, this)(_playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 1); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectAttackTarget, this)(_playerID); + + if (_aiType->aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_RAIDING) { + + _aiType->canStartSpending = 1; + + } + + else { + + /* + shouldSpend = recruitGoldTreshold < currentGold */ + + _aiType->canStartSpending + = (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0xc4) + < _aiType->currentResources[0xf]); + } + } + } + + _aiType = _aiType + 0xe7d; + + _playerID = _playerID + 1; + + } while ((int)_aiType < 0x117ea8c); + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp new file mode 100644 index 000000000..b864cfc3e --- /dev/null +++ b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp @@ -0,0 +1,567 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" +#include "OpenSHC/Game/GameStateStructures.func.hpp" +#include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" +#include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_BuildingsState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SFXState.hpp" +#include "OpenSHC/Globals/DAT_UnitsState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D49E0 + void AICState ::updateAIPlayerState(int playerID) + + { + + short* psVar1; + + int* piVar2; + + short sVar3; + + AITypeInt AVar4; + + int _aiType; + + int iVar5; + + BOOLEnum _shouldAttack; + + int _attackedPlayerAlive; + + uint _rallyReady; + + BOOLEnum BVar6; + + int _aiPlayerState_2; + + int _aiPlayerState; + + int _playerID; + + AVar4 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar4 == OpenSHC::AI::AIT_NULL) { + + return; + } + + _aiType = AVar4 + ~OpenSHC::AI::AIT_NULL; + + iVar5 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; + + if (((iVar5 != 1) && (iVar5 == 2)) + && (iVar5 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), + iVar5 != 0)) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToPlayerIDsKeepIfPossible, this)( + playerID, (short*)((int)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk))); + + return; + } + + _aiPlayerState = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; + + if (_aiPlayerState == 0) { + + _shouldAttack = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::aiShouldAttackOrWaitForTeamCoordination, this)(playerID); + + if (_shouldAttack == FALSE) { + + /* + Send own units back to keep or campfire */ + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRetreatUnits, this)((short*)playerID); + + return; + } + + /* + proceedwithattack */ + + DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 1; + + DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue = 0; + + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience = 0; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackCoordinationLevel, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackStrength, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackRaidParameter, this)(playerID); + + piVar2 = (int*)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID * 0x39f4 + 0x115e9d4 + + playerID * 0x20); + + *piVar2 = *piVar2 + 1; + + } + + else { + + BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID); + + if ((((BVar6 != FALSE) && (_aiPlayerState != 9)) + || ((0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker + && (_aiPlayerState < 6)))) + || (199 < DAT_GameState::instance.playerDataArray[playerID].attackTicker)) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 8; + } + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); + + _attackedPlayerAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + if (_attackedPlayerAlive == 0) { + + /* + attacked player is dead */ + + iVar5 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; + + if (iVar5 < 4) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + + MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( + playerID); + + } + + else if (iVar5 < 7) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 7; + } + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearOutdatedAITribes, this)(playerID); + + _aiPlayerState_2 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; + + if (_aiPlayerState_2 != 1) { + + if (_aiPlayerState_2 == 2) { + + /* + the general state means to be attacking */ + + _rallyReady + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID); + + if (_rallyReady == 0) { + + return; + } + + /* + send the attacking units to move closer */ + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 3; + + MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setNextMoveLocationForUnits, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToAttackTribes, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0xe_toPlaceTunnels, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playTauntToAttackedPlayerBikFromPlayer, this)(playerID); + + return; + } + + if (_aiPlayerState_2 == 3) { + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + + /* + send the attacking units closer to the castle */ + + *piVar2 = *piVar2 + 1; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + + BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::processAttForceRallyPercentage, this)(playerID); + + if (BVar6 == FALSE) { + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 4; + + DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 0; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); + + return; + } + + if (_aiPlayerState_2 == 4) { + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + + *piVar2 = *piVar2 + 1; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); + + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::countSiegeEngineUnits, this)(playerID); + + if (iVar5 < 1) { + + DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 100; + } + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue; + + *piVar2 = *piVar2 + 1; + + if (DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue + <= *(int*)((int)this + _aiType * 0x2a4 + 0x208)) { + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocationFullVolume, DAT_SFXState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, 0x14); + + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + if (BVar6 == FALSE) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe11StandGroundToGate, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe13DefensiveWave, this)(playerID); + + LAB_004d4ed3: + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; + + return; + } + + } + + else { + + if (_aiPlayerState_2 != 5) { + + if (_aiPlayerState_2 == 6) { + + /* + Enemy castle breached! */ + + if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + } + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + + *piVar2 = *piVar2 + 1; + + _playerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + + DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; + + MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::calculateAttackVectorsToCampFireOfPlayer, + DAT_GameState::ptr)(_playerID); + + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToAttackBreachedCastle, this)( + playerID); + + if (iVar5 != 0) { + + return; + } + + BVar6 = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + if (BVar6 != FALSE) { + + return; + } + + BVar6 + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, + DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + if (BVar6 != FALSE) { + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; + + goto LAB_004d4ed3; + } + + if (_aiPlayerState_2 == 7) { + + piVar2 + = &DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue; + + *piVar2 = *piVar2 + 1; + + if (DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue + <= *(int*)((int)this + _aiType * 0x2a4 + 0x20c)) { + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( + playerID); + + return; + } + + if (_aiPlayerState_2 == 8) { + + /* + Retreat from attack. */ + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; + + DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( + playerID); + + if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) { + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playAnger1BikFromPlayer, this)(playerID); + + return; + } + + if (_aiPlayerState_2 != 9) { + + return; + } + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + + *piVar2 = *piVar2 + 1; + + if (((DAT_GameState::instance.playerDataArray[playerID].attackTicker < 20) + && (BVar6 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::percentageNonMovingTribesGTEAICSpecified, this)( + playerID), + BVar6 == FALSE)) + && (BVar6 + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID), + BVar6 == FALSE)) { + + return; + } + + goto LAB_004d4ff7; + } + + /* + _aiPlayerState_2 is 5 (Attack walls) */ + + if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) { + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + } + + psVar1 = &DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; + + *psVar1 = *psVar1 + 1; + + sVar3 = DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; + + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + + *piVar2 = *piVar2 + 1; + + DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; + + if (3 < sVar3) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandWallAssaultTribes, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + + MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::setTribe0x11ToAggressiveAndAttackIfConditionMet, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setEightTribe0xc0TribesToAggressiveAndAttack, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); + + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xCtoAggressiveAndAttack, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xbToAggressiveAndAttack, this)(playerID); + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + + if ((BVar6 == FALSE) + && (BVar6 + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, + DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID), + BVar6 == FALSE)) { + + return; + } + } + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; + + return; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recreateEngineersTribe, this)(playerID); + + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 2; + + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::initializeGatePathfindingForOwner, + DAT_BuildingsState::ptr)(playerID); + + /* + computes the first siege location for units */ + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeEnemyKeepApproachTile, this)(playerID); + + if (0 < DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackTribesToLocations, this)((short*)playerID); + + return; + } + + LAB_004d4ff7: + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp new file mode 100644 index 000000000..22deecfe3 --- /dev/null +++ b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp @@ -0,0 +1,583 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Random/RNG.func.hpp" +#include "OpenSHC/AI/AINervousDestroyBuildingCategory.hpp" +#include "OpenSHC/AI/AINervousDestroyBuildingCategoryInt.hpp" +#include "OpenSHC/AI/AIRecruitUnitChoice.hpp" +#include "OpenSHC/AI/AIStrengthType.hpp" +#include "OpenSHC/Game/GameMode2.hpp" +#include "OpenSHC/Game/TrailType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/SEC_RNG.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AINervousDestroyBuildingCategory; + using OpenSHC::AI::AINervousDestroyBuildingCategoryInt; + using OpenSHC::AI::AIRecruitUnitChoice; + using OpenSHC::AI::AIStrengthType; + using OpenSHC::Game::GameMode2; + using OpenSHC::Game::TrailType; + using OpenSHC::WindowsHelper::Enums::BOOLEnum; + + /* + this functions info is based on np123 + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3320 + void AICState ::updateAIStrengthState(int playerID, int aiRecruitUnitChoicePreference) + + { + + int* piVar1; + + short* psVar2; + + int _totalTroopCount; + + int _aicOffset; + + int _rng; + + int _raidUnitCount; + + BOOLEnum _teamWeak; + + BOOLEnum _outOfSupplies2; + + BOOLEnum _teamWeak2; + + BOOLEnum _outOfSupplies; + + int _totalRecruitProb; + + bool bVar3; + + int _totalDefenseTroops; + + int _aiType; + + int _currentPopulation; + + int _totalFood; + + int _aiStrengthState; + + int _aiRecruitUnitChoiceState; + + int _subtraction; + + int _aiType_2; + + int _totalRaidTroops; + + int _defTotal; + + int _currentGold_2; + + int _aiNervousActionsTracker; + + AINervousDestroyBuildingCategoryInt _cat; + + int _aiNervousActionsTracker2; + + int _aiBuildingDestroyActionsTracker; + + int _currentGold; + + int _aiTypeMin1; + + AINervousDestroyBuildingCategory _cat2; + + int _recruitProbDefensive; + + int _recruitProbRaid; + + _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + + /* + is human */ + + if (_aiType == 0) { + + return; + } + + if ((char)aiRecruitUnitChoicePreference == '\0') { + + if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) { + + return; + } + + if (DAT_GameCore::instance.isSkirmishTrail != TRUE) { + + return; + } + + if (DAT_GameCore::instance.currentTrailType != OpenSHC::Game::TT_EXTREME) { + + return; + } + } + + _aiTypeMin1 = _aiType + -1; + + _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 0; + + /* + check if current gold less than 200 */ + + if (_currentGold < 200) { + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 0; + + } + + else { + + /* + 2 if currentGold > 1999 else 1 */ + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = (1999 < _currentGold) + 1; + } + + _currentPopulation = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; + + if (15 < _currentPopulation) { + + /* + if currentPopulation more than 14 */ + + if (_currentPopulation < 40) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + /* + if currentPopulation less than 40 */ + + *piVar1 = *piVar1 + 1; + + } + + else { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + /* + if current Population more than 40 */ + + *piVar1 = *piVar1 + 2; + } + } + + /* + check if total food higher than 20 */ + + _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; + + if (20 < _totalFood) { + + if (_totalFood < 200) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + *piVar1 = *piVar1 + 1; + + } + + else { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + *piVar1 = *piVar1 + 2; + } + } + + _totalTroopCount = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + + DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk + + DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; + + /* + check if troop strength above 7 */ + + if (7 < _totalTroopCount) { + + /* + check if troop strength smaller than 40 */ + + if (_totalTroopCount < 40) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + *piVar1 = *piVar1 + 2; + + } + + else { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + *piVar1 = *piVar1 + 4; + } + } + + _aiStrengthState = DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + + if (_aiStrengthState < 3) { + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; + + } + + else if (_aiStrengthState < 8) { + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_DEFAULT; + + } + + else { + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_STRONG; + } + + if ((DAT_GameState::instance.playerDataArray[playerID].aivCurrentPauseIndex == 1) + && (0 < DAT_GameState::instance.playerDataArray[playerID].aivPauses[1])) { + + /* + if pausing at first pause + */ + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; + } + + /* + add the aiStrengthFeeling to (aiType * 169). The AI Personality struct is a + 169*4 long element of an array of 16 elements (all ai types, maybe more?) */ + + _aicOffset = DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + _aiTypeMin1 * 169; + + /* + fetch RecruitProbRaid for current aiType */ + + _recruitProbRaid = *(int*)((int)this + _aicOffset * 4 + 0x134); + + /* + fetch RecruitProbDefensive */ + + _recruitProbDefensive = *(int*)((int)this + _aicOffset * 4 + 0x128); + + /* + add RecruitProbAttack to the other two probs */ + + _totalRecruitProb = *(int*)((int)this + _aicOffset * 4 + 0x140) + _recruitProbRaid + _recruitProbDefensive; + + /* + check if recruitProb = 0 */ + + if (_totalRecruitProb == 0) { + + _aiRecruitUnitChoiceState = aiRecruitUnitChoicePreference; + + if (aiRecruitUnitChoicePreference == 1) { + + LAB_004d34e9: + /* + WARNING: reused variable _aiType */ + + _raidUnitCount = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(_aiTypeMin1, playerID); + + _totalDefenseTroops = DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk; + + bVar3 = (_totalDefenseTroops < _raidUnitCount); + + _subtraction = _totalDefenseTroops - _raidUnitCount; + + goto LAB_004d3515; + } + + if (aiRecruitUnitChoicePreference == 0) + goto LAB_004d3502; + + } + + else { + + _rng = (int)SEC_RNG::instance.currentNumber2; + + /* + WARNING: prob is now randomized */ + + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + + /* + if DAT_01fe7da8 < 4800 */ + + if ((int)DAT_GameCore::instance.mapTimeInTicks < 4800) { + + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; + + LAB_004d3502: + _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; + + /* + true if param1 > param0 */ + + _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); + + bVar3 = (_totalRaidTroops < _defTotal); + + _subtraction = _totalRaidTroops - _defTotal; + + LAB_004d3515: + if (bVar3 != _subtraction < 0) + goto LAB_004d351c; + + } + + else { + + /* + if RecruitProbDefensive > RandomizedRecruitProb */ + + if (_rng % _totalRecruitProb < _recruitProbDefensive) { + + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; + + goto LAB_004d3502; + } + + if (_rng % _totalRecruitProb < _recruitProbRaid + _recruitProbDefensive) { + + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_RAIDING; + + goto LAB_004d34e9; + } + } + + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_ATTACKING; + } + + LAB_004d351c: + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState != _aiRecruitUnitChoiceState) { + + DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = _aiRecruitUnitChoiceState; + } + + if ((char)aiRecruitUnitChoicePreference == '\0') { + + return; + } + + if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) { + + _teamWeak = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, TRUE); + + if (_teamWeak == FALSE) { + + DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = 0; + + return; + } + + /* + WARNING: aiType now means currentGold */ + + _currentGold_2 = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; + + DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; + + /* + if gold <= 500 */ + + if (_currentGold_2 < 500) { + + _aiNervousActionsTracker = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + if (_aiNervousActionsTracker < 8) { + + /* + destroy a good or bad thing */ + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS); + + _cat = OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS; + + } + + else { + + if (5 < _aiNervousActionsTracker) + goto LAB_004d35fb; + + /* + fixme: does this line ever happen? */ + + _cat = OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS; + } + + /* + destroy a workshop (2) or a resource building (iron mine... bakery) (6) */ + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, (AINervousDestroyBuildingCategory)((int)(_cat))); + + } + + else { + + /* + if gold > 2500 and... */ + + if (((2500 < _currentGold_2) + && (psVar2 = &DAT_GameState::instance.playerDataArray[playerID].aiStateCounter, + *psVar2 = *psVar2 + 1, + (DAT_GameState::instance.playerDataArray[playerID].aiStateCounter & 1U) != 0)) + && (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 20)) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::shareGoldAmongTeamMembers, this)( + playerID, _currentGold_2 / 10); + } + } + + LAB_004d35fb: + _aiNervousActionsTracker2 = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + if (_aiNervousActionsTracker2 < 2) { + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = _aiNervousActionsTracker2 + -1; + + return; + } + + /* + ********************************************************* + * From here on we process logic for destroying buildings + ********************************************************* */ + + _aiBuildingDestroyActionsTracker + = DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + + if (_aiBuildingDestroyActionsTracker < 1) { + + _teamWeak2 + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, FALSE); + + if (_teamWeak2 != FALSE) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playNervous2BikFromPlayer, this)(playerID); + + DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = 8; + + DAT_GameState::instance.playerDataArray[playerID].aiStateCounter = 0; + + return; + } + + _outOfSupplies = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); + + if (_outOfSupplies == FALSE) { + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 8; + + return; + } + + _outOfSupplies2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); + + if (_outOfSupplies2 == FALSE) { + + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 0; + + return; + } + + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] = 20; + + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; + + DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; + + if (_aiBuildingDestroyActionsTracker == 8) { + + _cat2 = OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS; + + } + + else { + + if (_aiBuildingDestroyActionsTracker == 7) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + + *piVar1 = *piVar1 + -1; + + return; + } + + if (_aiBuildingDestroyActionsTracker == 6) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_GATEHOUSES_TOWERS_GUILDS); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_BARRACKS_MERCPOST_STABLES); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WATER_BUILDINGS); + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + + *piVar1 = *piVar1 + -1; + + return; + } + + if (_aiBuildingDestroyActionsTracker == 5) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + + *piVar1 = *piVar1 + -1; + + return; + } + + if (_aiBuildingDestroyActionsTracker != 4) + goto LAB_004d3707; + + _cat2 = OpenSHC::AI::AINDBC_FARMS; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)(playerID, _cat2); + + LAB_004d3707: + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + + *piVar1 = *piVar1 + -1; + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/updateTribeLocations.cpp b/src/OpenSHC/AI/AICState/updateTribeLocations.cpp new file mode 100644 index 000000000..65cc46e7b --- /dev/null +++ b/src/OpenSHC/AI/AICState/updateTribeLocations.cpp @@ -0,0 +1,74 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" + +#include "OpenSHC/Globals/DAT_EntityState.hpp" +#include "OpenSHC/Globals/DAT_GameState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004D4940 + void AICState ::updateTribeLocations(int playerID) + + { + + int* piVar1; + + AITypeInt AVar2; + + AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar2 != OpenSHC::AI::AIT_NULL) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter; + + *piVar1 = *piVar1 + 1; + + /* + defWallPatrolRallyTime + */ + + if (*(int*)((int)DAT_EntityState::instance.seagullArray + AVar2 * 0x2a4 + 0x2580) + <= DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter) { + + piVar1 = &DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits; + + *piVar1 = *piVar1 + 1; + + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter = 0; + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::ifHasTribe0SendUnitsToKeep, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeAtOffset1ToCampfire, this)(playerID); + + if (DAT_GameState::instance.mapAndTime.monthTicks == playerID) { + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::digNearestMoat, this)(playerID); + } + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendRangedUnitTribesToAIVSlotsOrKeepIfNervous, this)( + playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed, + this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendWallPatrolUnitTribesToAIVLocations, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendOilMenForOilPickupOrToAIVLocations, this)(playerID); + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiGiveOuterPatrolCommand, this)(playerID); + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp new file mode 100644 index 000000000..8011403c9 --- /dev/null +++ b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp @@ -0,0 +1,206 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/Tribes/AITribeType.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::Tribes::AITribeType; + using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::UnitInstructionType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CEFD0 + void AICState ::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers(int playerID) + + { + + AITypeInt AVar1; + + int iVar2; + + int _counterTill6; + + int _selectionID2; + + int iVar3; + + int* piVar4; + + CommandBuildingType _siegeEngineType; + + int iVar5; + + int _counterTill8; + + int _aiTribeID; + + int* _siegeEngineUnitType; + + int local_18; + + int _requiredEngineers; + + short _currentAttackWave; + + short _size; + + AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + + if (AVar1 != OpenSHC::AI::AIT_NULL) { + + _aiTribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; + + if ((_aiTribeID != 0) + && (DAT_TribesState::instance.tribes[_aiTribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { + + _size = DAT_TribesState::instance.tribes[_aiTribeID].size; + + local_18 = (int)_size; + + iVar3 = 0; + + _siegeEngineUnitType = (int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x214); + + piVar4 = _siegeEngineUnitType; + + iVar5 = 0; + + do { + + if (*piVar4 < 1) + break; + + iVar2 = 0; + + do { + + if (*piVar4 == DAT_SkirmishDefinedData::instance.DAT_SiegeEngineUnitType[iVar2]) { + + _requiredEngineers + = DAT_SkirmishDefinedData::instance.DAT_SiegeEngineTypeRequiredEngineers[iVar2]; + + break; + } + + iVar2 = iVar2 + 1; + + } while (iVar2 < 6); + + iVar2 = _requiredEngineers + iVar5; + + if (local_18 < iVar2) + break; + + iVar3 = iVar3 + 1; + + piVar4 = piVar4 + 1; + + iVar5 = iVar2; + + } while (iVar3 < 8); + + if (0 < iVar5) { + + for (; (_size != 0 && (0 < iVar5)); iVar5 = iVar5 + -1) { + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::popUnitFromTribe, DAT_TribesState::ptr)(_aiTribeID); + + _size = DAT_TribesState::instance.tribes[_aiTribeID].size; + } + + _counterTill8 = 0; + + /* + fixme: parameter reuse */ + + _siegeEngineType = (CommandBuildingType)playerID; + + do { + + if (*_siegeEngineUnitType < 1) { + + return; + } + + _counterTill6 = 0; + + do { + + if (*_siegeEngineUnitType + == DAT_SkirmishDefinedData::instance.DAT_SiegeEngineUnitType[_counterTill6]) { + + _requiredEngineers = DAT_SkirmishDefinedData::instance + .DAT_SiegeEngineTypeRequiredEngineers[_counterTill6]; + + _siegeEngineType = (CommandBuildingType)DAT_SkirmishDefinedData::instance + .DAT_SiegeEngineCommandBuildingTypes[_counterTill6]; + + break; + } + + _counterTill6 = _counterTill6 + 1; + + } while (_counterTill6 < 6); + + if (local_18 < _requiredEngineers) { + + return; + } + + local_18 = local_18 - _requiredEngineers; + + _selectionID2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToSelection, this)( + playerID, _requiredEngineers); + + if (_selectionID2 == 0) { + + return; + } + + _currentAttackWave = (short)DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; + + DAT_TribesState::instance.tribes[_selectionID2].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + + DAT_TribesState::instance.tribes[_selectionID2].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + + DAT_TribesState::instance.tribes[_selectionID2].attackWave = _currentAttackWave; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func:: + placeSiegeTentOrTunnelAtSuitableLocationAndAssignEngineers, + DAT_TroopValueState::ptr)( + _selectionID2, _siegeEngineType, (uint)((int)(60)), (UnitInstructionType)((int)(15))); + + _counterTill8 = _counterTill8 + 1; + + _siegeEngineUnitType = _siegeEngineUnitType + 1; + + } while (_counterTill8 < 8); + } + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp new file mode 100644 index 000000000..ff4f4d85b --- /dev/null +++ b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp @@ -0,0 +1,80 @@ +#include "OpenSHC/AI/AICState.func.hpp" +#include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/Map/Units/TroopValueState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/AI/Tribes/AITribeType.hpp" +#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/Map/Units/UnitInstructionType.hpp" + +#include "OpenSHC/Globals/DAT_GameState.hpp" +#include "OpenSHC/Globals/DAT_TribesState.hpp" +#include "OpenSHC/Globals/DAT_TroopValueState.hpp" + +namespace OpenSHC { +namespace AI { + + using OpenSHC::AI::AIType; + using OpenSHC::AI::Tribes::AITribeType; + using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Map::Units::SomeTribeBehaviorType; + using OpenSHC::Map::Units::UnitInstructionType; + + /* + decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + // FUNCTION: STRONGHOLDCRUSADER 0x004CF180 + void AICState ::useAITribe_0xe_toPlaceTunnels(int playerID) + + { + + int _aiTribeID; + + uint _unitID; + + int _tribeID; + + int _countdown; + + short _size; + + if (((DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) + && (_aiTribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xe], + _aiTribeID != 0)) + && (DAT_TribesState::instance.tribes[_aiTribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xe])) { + + _size = DAT_TribesState::instance.tribes[_aiTribeID].size; + + for (_countdown = (int)_size; (_size != 0 && (0 < _countdown)); _countdown = _countdown + -1) { + + _unitID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::popUnitFromTribe, DAT_TribesState::ptr)(_aiTribeID); + + _tribeID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + + DAT_TribesState::instance.tribes[_tribeID].attackWave + = (short)DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; + + DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_TUNNELERS; + + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x415; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + _unitID, _tribeID); + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func:: + placeSiegeTentOrTunnelAtSuitableLocationAndAssignEngineers, + DAT_TroopValueState::ptr)(_tribeID, OpenSHC::Commands::CBT_TUNNEL_ENTRANCE, (uint)((int)(50)), + (UnitInstructionType)((int)(21))); + + _size = DAT_TribesState::instance.tribes[_aiTribeID].size; + } + } + + return; + } + +} +} diff --git a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp index 20ee5094d..2a2e2abcc 100644 --- a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp +++ b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp @@ -9,14 +9,10 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004C6D30 void AICState::wipeAICMemory() { - AICSpecification* destination = this->aics; - int iVar1 = 20; - do { + for (int i = 0; i < 20; i++) { MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( - 676, '\0', destination); - destination = destination + 1; - iVar1 = iVar1 + -1; - } while (iVar1 != 0); + 676, '\0', &this->aics[i]); + } } } } diff --git a/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp b/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp index 851e01542..975bfa838 100644 --- a/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp +++ b/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp @@ -10,11 +10,8 @@ namespace AI { BOOLEnum AICState::woodCuttersHutWhileNoWoodAvailable( undefined4 playerID, Commands::CommandBuildingType commandBuildingType) { - if ((commandBuildingType == Commands::CBT_WOODCUTTERSHUT) - && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0)) { - return TRUE; - } - return FALSE; + return ((commandBuildingType == Commands::CBT_WOODCUTTERSHUT) + && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0)); } } } From 66addddcd4edce963cb2b4900539912c58c9a37e Mon Sep 17 00:00:00 2001 From: sourcehold Date: Mon, 27 Jul 2026 22:45:08 +0200 Subject: [PATCH 034/242] fit improvements --- .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 6 ++-- src/OpenSHC/AI/AICState/buyRequiredGoods.cpp | 30 ++----------------- .../generateSiegeCreationInformation.cpp | 11 +------ .../AICState/hasNoTroopsOrAllAreDiggers.cpp | 5 ++-- ...BuyWhenLowOnResourceAndSnoozeBuildings.cpp | 3 -- .../AI/AICState/playAnger1BikFromPlayer.cpp | 15 +++++----- .../AICState/playRequestHelpBikFromPlayer.cpp | 2 +- .../AI/AICState/setAttackPrimeInfo.cpp | 16 +++++----- 8 files changed, 25 insertions(+), 63 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp index 20b5496f0..55025b43a 100644 --- a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -43,9 +43,9 @@ namespace AI { if (((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0xaa])) - && ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0xb - && ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk < 0xb - && (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk < 0xb)))))) { + && ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk <= 0xa + && ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk <= 0xa + && (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk <= 0xa)))))) { if (((int)this->aics[_aiType - 1].OuterPatrolGroupsMove == 0) || (_buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)( playerID, _index), diff --git a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp index 27cb9b4c3..9a0ea9e4e 100644 --- a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp +++ b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp @@ -18,20 +18,6 @@ namespace AI { using OpenSHC::Game::Resources::ResourceTypeInt; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - Walks the AIC resource acquisition preference order (up to 25 entries in - DAT_ResourceAcquisitionPreferenceOrder) and attempts to buy the first resource for which the - player has a non-zero resourcesToAcquireArray entry and meets one of the spending conditions: - popularity is below the AIC minimum threshold (only checked for the first 4 entries), the AI is - nervous, or the canStartSpending flag is set. If the AI is nervous, entries 0-11 (non-weapon - resources) are skipped entirely so it only buys weapons. A special override fires first inside - the loop: if the building-destroy tracker is non-zero AND the player has fewer than 20 wood, the - resource type is forced to RT_WOOD regardless of the preference order. Before calling buyGoods() - the required gold is computed via getBuyPrice(); if the AI cannot afford the purchase it calls - requestGoods() from a teammate at double the desired amount instead. On a successful purchase - resourcesToAcquireArray for that resource is cleared and the function returns immediately, - buying at most one resource type per call. */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D39B0 void AICState ::buyRequiredGoods(int param_1) @@ -51,9 +37,6 @@ namespace AI { playerID = param_1; - /* - buying */ - AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; if (AVar1 == OpenSHC::AI::AIT_NULL) { @@ -61,33 +44,24 @@ namespace AI { return; } - /* - reused! playerID now means a counter */ - param_1 = 0; do { resourceType = DAT_SkirmishDefinedData::instance.DAT_ResourceAcqusitionPreferenceOrder[param_1]; - /* - If nervous, only buy from entry 12 onwards, which are weapons */ - - if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) || (12 < param_1)) { + if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0) || (0xb < param_1)) { if ((DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker != 0) && (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] < 20)) { - /* - if short on wood, buy wood! */ - resourceType = OpenSHC::Game::Resources::RT_WOOD; } amount = DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType]; if ((amount != 0) - && ((((param_1 < 4 + && ((((param_1 <= 3 && (DAT_GameState::instance.playerDataArray[playerID].popularity < *(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x18))) || (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker)) diff --git a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp index 581d2e863..bc11333dd 100644 --- a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp +++ b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp @@ -17,15 +17,6 @@ namespace AI { using OpenSHC::Map::Units::UnitType; using OpenSHC::Map::Units::UnitTypeShort; - /* - 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 0x004CC420 void AICState ::generateSiegeCreationInformation(int playerID, int buildingID, int unitID) @@ -73,7 +64,7 @@ namespace AI { _engineIndexUnk = 0; while ((_nextIndex = _engineIndexUnk + 1, - *(int*)(playerID * 0x39f4 + iVar2 * 40 + 0x115eb14 + _engineIndexUnk * 4) < 1 + *(int*)(playerID * 0x39f4 + iVar2 * 40 + 0x115eb14 + _engineIndexUnk * 4) <= 0 || (buildingID != *(int*)(playerID * 0x39f4 + 0x115f494 + (_engineIndexUnk + _siegeIndex * 5) * 0x14)))) { diff --git a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp index d550e65f5..5862623d0 100644 --- a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp +++ b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp @@ -11,9 +11,10 @@ namespace AI { int _totalTroops; int _halfOfDiggingTroops; - int _totalMisc = DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + // reversed order to match orig + int _totalMisc = DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops - + DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops; + + DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops; _halfOfDiggingTroops = 0; if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState == 6) { _totalMisc += DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops; diff --git a/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp index c9b015a83..dd0c5b813 100644 --- a/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp +++ b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp @@ -10,9 +10,6 @@ namespace AI { using OpenSHC::AI::AIType; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CBA50 void AICState ::planToBuyWhenLowOnResourceAndSnoozeBuildings(int playerID) diff --git a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp index d544ada7d..fed855c23 100644 --- a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp @@ -17,18 +17,17 @@ namespace AI { int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); if (iVar2 != 0) { - int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] - != DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) - && (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID - == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { + int _playerTeam = DAT_GameState::instance.mapAndTime.playerTeams[playerID]; + int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + int _curPlayer = DAT_GameSynchronyState::instance.currentPlayerSlotID; + if ((_playerTeam != DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer]) + && (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID == _curPlayer)) { DWORD DVar3 = timeGetTime(); if ((INT_ARRAY_00eb0af0::instance[playerID] == 0) - || (599999 < DVar3 - INT_ARRAY_00eb0af0::instance[playerID])) { + || (DVar3 - INT_ARRAY_00eb0af0::instance[playerID] >= 0x927c0)) { INT_ARRAY_00eb0af0::instance[playerID] = DVar3; MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, - DAT_VideoBikQueue::ptr)(playerID, AVar1 - 1, 5); + DAT_VideoBikQueue::ptr)(playerID, AVar1, 5); } } } diff --git a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp index fc2a1bac2..3be00819a 100644 --- a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp @@ -15,9 +15,9 @@ namespace AI { { int iVar2 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - int iVar1 = DAT_GameSynchronyState::instance.currentPlayerSlotID; if ((iVar2 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 == 0)) { DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 = 0x30; + int iVar1 = DAT_GameSynchronyState::instance.currentPlayerSlotID; if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] == DAT_GameState::instance.mapAndTime.playerTeams[iVar1]) && (DAT_GameState::instance.playerDataArray[iVar1].lordKilledByPlayerID == 0)) { diff --git a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp index 0689b2419..7910e23a0 100644 --- a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp +++ b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp @@ -12,16 +12,16 @@ namespace AI { void AICState::setAttackPrimeInfo(int playerID, int attackedPlayerID) { int _tile = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile; - DAT_TroopValueState::instance.attackInfo.startCon - = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; - DAT_TroopValueState::instance.attackInfo.startZone = (int)(char)DAT_TileMapState::instance.AIZoneLayer[_tile]; - DAT_TroopValueState::instance.attackInfo.zoneSize - = DAT_PathFindingState::instance - .zoneSizesArray[(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]]; + int _zone = (int)(char)DAT_TileMapState::instance.AIZoneLayer[_tile]; + int _pathCon = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; + int _zoneSize = DAT_PathFindingState::instance.zoneSizesArray[_pathCon]; + DAT_TroopValueState::instance.attackInfo.startCon = _pathCon; + int _attackedTile = DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry; + DAT_TroopValueState::instance.attackInfo.startZone = _zone; + DAT_TroopValueState::instance.attackInfo.zoneSize = _zoneSize; DAT_TroopValueState::instance.attackInfo.unknownOne_0x20f90 = 1; DAT_TroopValueState::instance.attackInfo.keepCon - = (int)(short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry]; + = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_attackedTile]; } } } From 6a6f65d681698785ffb6c0c13ef05c782089b27a Mon Sep 17 00:00:00 2001 From: sourcehold Date: Tue, 28 Jul 2026 22:31:19 +0200 Subject: [PATCH 035/242] better or worse --- .../addUnitToSmallestBehaviourTypeTribe.cpp | 21 +- .../AI/AICState/aiCreateSiegeUnits.cpp | 584 ++++----------- .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 20 +- .../AI/AICState/aiGiveRaidInstructions.cpp | 401 ++++------- src/OpenSHC/AI/AICState/aiRecruitUnits.cpp | 583 +++++---------- .../AI/AICState/aiRequiresExtraOxtethers.cpp | 86 +-- ...iShouldAttackOrWaitForTeamCoordination.cpp | 115 ++- src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp | 15 +- .../AI/AICState/aiUpdateTaxesAndRations.cpp | 148 ++-- ...mBuildingIDFromPlayersArrayOfBuildings.cpp | 89 +-- .../clearPlayerDataInformationChunk.cpp | 30 +- .../AI/AICState/computeNervousness.cpp | 56 +- .../AICState/decideOnTribeAttackLocation.cpp | 206 ++---- .../AICState/destroyAnyBuildingInCategory.cpp | 121 ++-- .../AI/AICState/destroyBuildingIfNoWorker.cpp | 45 +- src/OpenSHC/AI/AICState/destroyHouse.cpp | 41 +- ...ndAttackTribePositionAndPathToDefenses.cpp | 110 +-- .../AI/AICState/getDefensiveTribeForUnit.cpp | 28 +- .../AI/AICState/getSmallestPatrolTribe.cpp | 69 +- .../AICState/giveMoveCommandToSortieUnits.cpp | 68 +- .../AI/AICState/giveSomeRaidCommand.cpp | 37 +- .../AICState/hasNoTroopsOrAllAreDiggers.cpp | 15 +- .../AI/AICState/hasNotEnoughSupplies.cpp | 30 +- .../AI/AICState/instructTribe166ToMove.cpp | 73 +- .../processAttForceRallyPercentage.cpp | 88 +-- .../AI/AICState/selectAttackTarget.cpp | 203 ++---- src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 94 +-- .../AICState/sendTribeToAIVLocationSlot.cpp | 80 +-- ...TargetForTribeBasedOnTargetChoiceLogic.cpp | 172 ++--- .../AICState/setupWorkshopProductionType.cpp | 120 +--- .../AICState/shouldDestroyWoodCutterUnk.cpp | 20 +- .../AI/AICState/shouldNotBeBuildingHovel.cpp | 32 +- ...rketArmoryGranaryBarracksMercenarypost.cpp | 19 +- .../AI/AICState/smallestTribeOfUnitType.cpp | 6 +- .../AI/AICState/unitIDIsRangedOrArmored.cpp | 14 +- src/OpenSHC/AI/AICState/updateAIBehaviour.cpp | 198 ++---- .../AI/AICState/updateAIPlayerState.cpp | 664 ++++++------------ .../AI/AICState/updateAIStrengthState.cpp | 567 +++------------ .../AI/AICState/updateTribeLocations.cpp | 23 +- 39 files changed, 1585 insertions(+), 3706 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp index fb1ce9974..402f0e208 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp @@ -24,25 +24,22 @@ namespace AI { int _smallestTribeOffset = 0; short _smallestTribeSize = 1000; dword _groupsCount; - switch (_tribeTypeOffset) { - case 0xf: + + if (_tribeTypeOffset == 0xf) { _groupsCount = this->aics[AVar1 - 1].AttUnitPatrolGroupsCount; - break; - default: - goto switchD_004ccd78_caseD_10; - case 0xba: + } else if (_tribeTypeOffset == 0xba) { _groupsCount = this->aics[AVar1 - 1].AttUnitBackupGroupsCount; - break; - case 0xbe: + } else if (_tribeTypeOffset == 0xbe) { _groupsCount = this->aics[AVar1 - 1].AttUnitSiegeDefGroupsCount; - break; - case 0xc0: + } else if (_tribeTypeOffset == 0xc0) { _groupsCount = this->aics[AVar1 - 1].AttMainGroupsCount; + } else { + _groupsCount = 1; } + int _selectedTribe; int _selectedSlot; - if (((int)_groupsCount < 1) || (_groupsCount == 1)) { - switchD_004ccd78_caseD_10: + if ((int)_groupsCount < 1 || _groupsCount == 1) { int _tribeID_groupsCount1 = (int)DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_tribeTypeOffset]; if ((_tribeID_groupsCount1 != 0) diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index ec0e19d76..704837eaf 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -38,477 +38,167 @@ namespace AI { using OpenSHC::Map::Units::UnitType; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D2000 void AICState ::aiCreateSiegeUnits(int playerID) - { - - int _existingBuildingID; - - int _spawnedUnit; - - int _requiredEngineerCount; - - int _remainingRequiredEngineers; - - int _tribeID; - - int _targetUnitID; - - int _area; - - int _engineersTribe; - - int _aicOffset; - - int _y; - - int _slotIndex; - - int _nextSlotIndex; - - int _tile; - - int _mappingOffset; - - int _incrementsBy5; - - int _siegeInfoIndex; - - int _tribeSize; - - int _requiredGold; - - int _engineersGuildID; - - int _newUID; - - int _newBuildingID; - - int* _pGold; - - int _engineIndex; - - int _uid; - - int _unitID; - - int _location; - - AITypeInt _aiType; - - BuildingTypeShort _existingBuildingType; - + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == OpenSHC::AI::AIT_NULL) + return; + + int _engineersGuildID = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + if (!((0 < _engineersGuildID) + && (DAT_BuildingsState::instance.buildings[_engineersGuildID].buildingType + == OpenSHC::Map::Buildings::BT_ENGINEERSGUILD)) + || DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) + return; + + int _siegeInfoIndex = 0; + int _incrementsBy5 = 0; + int _mappingOffset = 0; int* _pDelay; - UnitType _unitType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType != OpenSHC::AI::AIT_NULL) { - - _engineersGuildID = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + do { + UnitType _unitType = *(UnitType*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].unitType + _mappingOffset); + int _tribeSize = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + _mappingOffset)]; + int _slotIndex = 0; + int _nextSlotIndex; - if (((0 < _engineersGuildID) - && (DAT_BuildingsState::instance.buildings[_engineersGuildID].buildingType - == OpenSHC::Map::Buildings::BT_ENGINEERSGUILD)) - && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) { - - _siegeInfoIndex = 0; - - _incrementsBy5 = 0; - - _mappingOffset = 0; + if (_tribeSize >= 4) + _tribeSize = 3; + if (0 < _tribeSize) { do { + _nextSlotIndex = _slotIndex + 1; + int _location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + _mappingOffset)][_slotIndex]; + + if (0 < _location) { + int _existingBuildingID = (int)(short)DAT_TileMapState::instance.BuildingLayer[_location]; + int _engineIndex = _incrementsBy5 + _slotIndex; + int _unitID = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID; + int _uid = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid; + int _tile = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID; + + if ((_unitID == 0) || (DAT_UnitsState::instance.units[_unitID].uid == _uid)) { + if ((_tile == 0) || (DAT_BuildingsState::instance.buildings[_tile].uid == _uid)) { + if (_unitID == 0) { + if (_tile == 0) { + bool _doPlace = false; + if (_existingBuildingID == 0) { + if (0x1f < _mappingOffset) + _doPlace = true; + } else if ((_mappingOffset < 0x20)) { + BuildingTypeShort _existingBuildingType = DAT_BuildingsState::instance.buildings[_existingBuildingID].buildingType; + if (_existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER4 || _existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER5) + _doPlace = true; + } else { + _doPlace = true; + } - _unitType - = *(UnitType*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].unitType - + _mappingOffset); - - _tribeSize = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*( - int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot - + _mappingOffset)]; - - _slotIndex = 0; - - if (_tribeSize < 4) { - - if (0 < _tribeSize) - goto LAB_004d20c0; - - } - - else { - - _tribeSize = 3; - - LAB_004d20c0: - do { - - _nextSlotIndex = _slotIndex + 1; - - _location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[*( - int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot - + _mappingOffset)][_slotIndex]; - - if (0 < _location) { - - _existingBuildingID = (int)(short)DAT_TileMapState::instance.BuildingLayer[_location]; - - _engineIndex = _incrementsBy5 + _slotIndex; - - _unitID = DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unitID; - - _uid = DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .uid; - - _tile = DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .buildingID; - - if ((_unitID == 0) || (DAT_UnitsState::instance.units[_unitID].uid == _uid)) { - - if ((_tile == 0) || (DAT_BuildingsState::instance.buildings[_tile].uid == _uid)) { - - if (_unitID == 0) { - - if (_tile == 0) { - - if (_existingBuildingID == 0) { - - if (0x1f < _mappingOffset) - goto LAB_004d21d4; - - } - - else if ((_mappingOffset < 0x20) - && ((_existingBuildingType - = DAT_BuildingsState::instance.buildings[_existingBuildingID] - .buildingType, - _existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER4 - || (_existingBuildingType - == OpenSHC::Map::Buildings::BT_TOWER5)))) { - - LAB_004d21d4: - _requiredGold - = DAT_BuildingsState::instance - .buildingCosts[*( - int*)((int)&DAT_SkirmishDefinedData::instance - .DAT_SiegeEngineMetaInfoArray[0] - .buildingType - + _mappingOffset)] - .requiredGold; - - _aicOffset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - - /* - defSiegeEngineGoldThreshold */ - - /* - defSiegeEngineBuildDelay */ - - if ((_requiredGold - <= DAT_GameState::instance.playerDataArray[playerID] - .currentResources[0xf] - + *(int*)((int)this + _aicOffset + 0x118)) - && (_pDelay = &DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay, - *_pDelay = *_pDelay + 1, - *(int*)((int)this + _aicOffset + 0x11c) - <= DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay)) { - - _y = (int)DAT_ViewportRenderState::instance - .DAT_TileTranslationMatrix_YComponent[_location]; - - _tile = _location - - DAT_ViewportRenderState::instance.translationMatrix[_y] - .addXgetTile; - - if (_siegeInfoIndex < 2) { - - _spawnedUnit = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::spawnUnit, - DAT_UnitsState::ptr)(playerID, playerID, _tile * 8 + 4, - _y * 8 + 4, - (int)((int)(DAT_BuildingsState::instance - .buildings[_existingBuildingID] - .terrainHeightUnk)), - _unitType); - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .unitID = _spawnedUnit; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .uid = DAT_UnitsState::instance.units[_spawnedUnit].uid; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .buildingID = 0; - - MACRO_CALL_MEMBER( - OpenSHC::Map::Buildings::BuildingsState_Func:: - processPlacementResourceLossForBuildingType, - DAT_BuildingsState::ptr)(playerID, - (BuildingType)((int)(DAT_SkirmishDefinedData::instance - .DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex] - .buildingType)), - 0); - - } - - else { - - MACRO_CALL_MEMBER( - OpenSHC::Map::TileMapState_Func::placeBuilding, - DAT_TileMapState::ptr)(playerID, _tile, _y, - (CommandBuildingType)((int)((uint)(ushort)(short) - DAT_SkirmishDefinedData::instance - .DAT_SiegeEngineMetaInfoArray - [_siegeInfoIndex] - .commandBuildingType)), - 3, 0xf); - - if (DAT_TileMapState::instance.buildingPlacementFail - == FALSE) { - - _pGold - = DAT_GameState::instance.playerDataArray[playerID] - .currentResources - + 0xf; - - *_pGold = *_pGold - _requiredGold; - - _newBuildingID - = DAT_TileMapState::instance.DAT_PlacedBuildingID; - - _newUID = DAT_BuildingsState::instance - .buildings[DAT_TileMapState::instance - .DAT_PlacedBuildingID] - .uid; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex] - [_slotIndex] - .unitID = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex] - [_slotIndex] - .uid = _newUID; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex] - [_slotIndex] - .buildingID = _newBuildingID; - } - } - - /* - delay = 0 */ - - *(undefined4*)(playerID * 0x39f4 + 0x115f48c + _slotIndex * 20 - + _siegeInfoIndex * 100) = 0; - - return; + if (_doPlace) { + int _requiredGold = DAT_BuildingsState::instance.buildingCosts[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].buildingType + _mappingOffset)].requiredGold; + int _aicOffset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + _pDelay = &DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay; + *_pDelay = *_pDelay + 1; + if ((_requiredGold <= DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] + *(int*)((int)this + _aicOffset + 0x118)) + && (*(int*)((int)this + _aicOffset + 0x11c) <= DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay)) { + int _y = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_location]; + int _placeTile = _location - DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + if (_siegeInfoIndex < 2) { + int _spawnedUnit = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::spawnUnit, DAT_UnitsState::ptr)(playerID, playerID, _placeTile * 8 + 4, _y * 8 + 4, (int)((int)(DAT_BuildingsState::instance.buildings[_existingBuildingID].terrainHeightUnk)), _unitType); + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].unitID = _spawnedUnit; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].uid = DAT_UnitsState::instance.units[_spawnedUnit].uid; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].buildingID = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processPlacementResourceLossForBuildingType, DAT_BuildingsState::ptr)(playerID, (BuildingType)((int)(DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex].buildingType)), 0); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID, _placeTile, _y, (CommandBuildingType)((int)((uint)(ushort)(short)DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex].commandBuildingType)), 3, 0xf); + if (DAT_TileMapState::instance.buildingPlacementFail == FALSE) { + int* _pGold = DAT_GameState::instance.playerDataArray[playerID].currentResources + 0xf; + *_pGold = *_pGold - _requiredGold; + int _newBuildingID = DAT_TileMapState::instance.DAT_PlacedBuildingID; + int _newUID = DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.DAT_PlacedBuildingID].uid; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].uid = _newUID; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].buildingID = _newBuildingID; } } - + *(undefined4*)(playerID * 0x39f4 + 0x115f48c + _slotIndex * 20 + _siegeInfoIndex * 100) = 0; + return; } - - else { - - LAB_004d22d3: - _requiredEngineerCount - = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: - getRequiredEngineerCountForSiegeBuilding, - DAT_BuildingsState::ptr)(_tile); - - if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount - != _requiredEngineerCount) { - - if (_requiredEngineerCount - <= DAT_GameState::instance.playerDataArray[playerID] - .engineerCountRelated) { - - _engineersTribe = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func:: - assignRequiredIdleEngineersToNewTribe, - this)(playerID, _requiredEngineerCount); - - DAT_TribesState::instance.tribes[_engineersTribe].tribeType - = OpenSHC::AI::Tribes::AITT_ENGINEERS; - - DAT_TribesState::instance.tribes[_engineersTribe] - .tribeBehaviorType = OpenSHC::Map::Units:: - STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func:: - giveTribeAnInstruction, - DAT_TribesState::ptr)(_engineersTribe, - OpenSHC::Map::Units:: - UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, - _tile, DAT_BuildingsState::instance.buildings[_tile].uid, - 0); - - return; - } - - DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired - = TRUE; - } + } + } else { + int _requiredEngineerCount = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, DAT_BuildingsState::ptr)(_tile); + if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount != _requiredEngineerCount) { + if (_requiredEngineerCount <= DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { + int _engineersTribe = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _requiredEngineerCount); + DAT_TribesState::instance.tribes[_engineersTribe].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_engineersTribe].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(_engineersTribe, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); + return; } - + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; } - - else { - - if (_tile != 0) - goto LAB_004d22d3; - - _remainingRequiredEngineers = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, - DAT_UnitsState::ptr)(_unitID); - - if (0 < _remainingRequiredEngineers) { - - if (DAT_GameState::instance.playerDataArray[playerID] - .engineerCountRelated - < _remainingRequiredEngineers) { - - DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired - = TRUE; - - } - - else { - - _tribeID - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func:: - assignRequiredIdleEngineersToNewTribe, - this)(playerID, _remainingRequiredEngineers); - - _targetUnitID = (int)DAT_TribesState::instance.tribes[_tribeID] - .selectionTargetUnitID; - - if ((_targetUnitID != 0) - && (_area = MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func:: - calculateCanPlayerUnitsNavigateToAreaFromArea, - DAT_PathFindingState::ptr)(playerID, - (dword)((int)((int)(short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_UnitsState::instance - .units[_unitID] - .tile])), - (dword)((int)((int)(short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_UnitsState::instance - .units[_targetUnitID] - .tile])), - 0), - _area != 0)) { - - DAT_TribesState::instance.tribes[_tribeID].tribeType - = OpenSHC::AI::Tribes::AITT_ENGINEERS; - - DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType - = OpenSHC::Map::Units::STBT_0x41c; - - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, - DAT_UnitsState::ptr)(_tribeID, - OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, _unitID, - DAT_UnitsState::instance.units[_unitID].uid, 0); - - return; - } + } + } else { + if (_tile != 0) { + int _requiredEngineerCount2 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, DAT_BuildingsState::ptr)(_tile); + if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount != _requiredEngineerCount2) { + if (_requiredEngineerCount2 <= DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { + int _engineersTribe2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _requiredEngineerCount2); + DAT_TribesState::instance.tribes[_engineersTribe2].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_engineersTribe2].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(_engineersTribe2, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); + return; + } + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; + } + } else { + int _remainingRequiredEngineers = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, DAT_UnitsState::ptr)(_unitID); + if (0 < _remainingRequiredEngineers) { + if (DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated < _remainingRequiredEngineers) { + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; + } else { + int _tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _remainingRequiredEngineers); + int _targetUnitID = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; + if ((_targetUnitID != 0) + && (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)(playerID, + (dword)((int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[_unitID].tile])), + (dword)((int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[_targetUnitID].tile])), + 0) != 0)) { + DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x41c; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(_tribeID, OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, _unitID, DAT_UnitsState::instance.units[_unitID].uid, 0); + return; } } } - } - - else { - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unitID = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .uid = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unknown = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .buildingID = 0; - } - - } - - else { - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unitID = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .uid = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unknown = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .buildingID = 0; } + } else { + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unknown = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID = 0; } - - _slotIndex = _nextSlotIndex; - - } while (_nextSlotIndex < _tribeSize); + } else { + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unknown = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID = 0; + } } - _siegeInfoIndex = _siegeInfoIndex + 1; - - _incrementsBy5 = _incrementsBy5 + 5; - - _mappingOffset = _mappingOffset + 16; - - if (64 < _mappingOffset) { - - return; - } - - } while (true); + _slotIndex = _nextSlotIndex; + } while (_nextSlotIndex < _tribeSize); } - } - return; + _siegeInfoIndex = _siegeInfoIndex + 1; + _incrementsBy5 = _incrementsBy5 + 5; + _mappingOffset = _mappingOffset + 16; + if (64 < _mappingOffset) + return; + } while (true); } - } } diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp index 55025b43a..a48ad6d5f 100644 --- a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -46,19 +46,22 @@ namespace AI { && ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk <= 0xa && ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk <= 0xa && (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk <= 0xa)))))) { + bool _hasTarget = true; if (((int)this->aics[_aiType - 1].OuterPatrolGroupsMove == 0) || (_buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)( playerID, _index), _buildingID == 0)) { _buildingID2 = MACRO_CALL_MEMBER( AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); - if (_buildingID2 == 0) - goto LAB_004d2a44; - _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID2] - .buildingEntryY] - .addXgetTile; + if (_buildingID2 == 0) { + _hasTarget = false; + } else { + _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID2] + .buildingEntryY] + .addXgetTile; + } } else { _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + DAT_ViewportRenderState::instance @@ -66,7 +69,7 @@ namespace AI { .buildingEntryY] .addXgetTile; } - if (_tile != 0) { + if (_hasTarget && _tile != 0) { sVar2 = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; iVar3 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; _canNavigate = MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( @@ -79,7 +82,6 @@ namespace AI { } } } - LAB_004d2a44: _index = _index + 1; psVar4 = psVar4 + 1; } while (_index < _count); diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp index 3f67ced06..32b7b3685 100644 --- a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -20,287 +20,196 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D2A70 void AICState ::aiGiveRaidInstructions(int playerID) - { + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == 0) + return; - int* piVar1; - - short sVar2; - - int iVar3; - - int _isAlive; - - int _buildingID_2; - - int _buildingID; - - int iVar4; - - int _buildingTile; - - BOOLEnum BVar5; - - int _tribeID3; - - BOOLEnum _indexTo6; - - short* _ptrTribeID3; - - int _aiType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType != 0) { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter; - - *piVar1 = *piVar1 + 1; - - /* - AIC: RaidRetargetDelay */ - - _indexTo6 = FALSE; - - if (*(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x1f0) - <= DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter) { - - DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter = 0; - } - - if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk == 0) { - - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; - - } - - else { - - iVar4 = DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown; - - if (0 < iVar4) { - - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown - = iVar4 + -1; - } - } - - _ptrTribeID3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xb4; - - do { - - _tribeID3 = (int)*_ptrTribeID3; - - DAT_TribesState::instance.tribes[_tribeID3].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - if ((_tribeID3 != 0) - && (DAT_TribesState::instance.tribes[_tribeID3].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_indexTo6 + 0xb4])) { - - if ((DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2) - && (_isAlive = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), - _isAlive != 0)) { - - if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) { - - _buildingID_2 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( - DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk, - (undefined4)((int)(_indexTo6))); - - if (_buildingID_2 == 0) { - - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); - - LAB_004d2d6b: - if (_buildingID != 0) - goto LAB_004d2d6f; - - } - - else { - - LAB_004d2c00: - _buildingTile - = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] - .buildingEntryY] - .addXgetTile; - - LAB_004d2d8d: - if (_buildingTile != 0) { - - sVar2 = DAT_ViewportRenderState::instance - .DAT_TileTranslationMatrix_YComponent[_buildingTile]; - - iVar4 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; - - BVar5 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( - _tribeID3, _buildingTile); - - if (BVar5 == FALSE) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID3, playerID); + int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter; + *piVar1 = *piVar1 + 1; - } + BOOLEnum _indexTo6 = FALSE; - else { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, - DAT_TribesState::ptr)(_tribeID3, (uint)((int)(_buildingTile - iVar4)), - (uint)((int)((int)sVar2)), 0); - } - } - } - } - - } - - else if ((DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown - == 0) - && (iVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, - this)(_aiType + -1, playerID), - DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk < iVar4)) { + if (*(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x1f0) + <= DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter) { + DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter = 0; + } - if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) - && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, TRUE), - BVar5 == FALSE)) { + if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk == 0) { + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; + } else { + int iVar4 = DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown; + if (0 < iVar4) + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = iVar4 + -1; + } + // Helper: do the movement command given a tile + // (was shared LAB_004d2d8d block) + #define DO_MOVE_TO_TILE(_tile, _tribeID3) \ + do { \ + if ((_tile) != 0) { \ + short sVar2_ = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[(_tile)]; \ + int iVar4_ = DAT_ViewportRenderState::instance.translationMatrix[sVar2_].addXgetTile; \ + BOOLEnum BVar5_ = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)((_tribeID3), (_tile)); \ + if (BVar5_ == FALSE) { \ + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)((_tribeID3), playerID); \ + } else { \ + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)((_tribeID3), (uint)((int)((_tile) - iVar4_)), (uint)((int)((int)sVar2_)), 0); \ + } \ + } \ + } while(0) + + short* _ptrTribeID3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xb4; + + do { + int _tribeID3 = (int)*_ptrTribeID3; + DAT_TribesState::instance.tribes[_tribeID3].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + if ((_tribeID3 != 0) + && (DAT_TribesState::instance.tribes[_tribeID3].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_indexTo6 + 0xb4])) { + + int iVar4; + BOOLEnum BVar5; + int _buildingID, _buildingID_2, _buildingTile; + + if ((DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2) + && (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) != 0)) { + + if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) { + _buildingID_2 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk, + (undefined4)((int)(_indexTo6))); + if (_buildingID_2 == 0) { _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( - playerID, (undefined4)((int)(_indexTo6))); - + OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); if (_buildingID != 0) { - - LAB_004d2d6f: _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + DAT_ViewportRenderState::instance .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] .buildingEntryY] .addXgetTile; - - goto LAB_004d2d8d; + DO_MOVE_TO_TILE(_buildingTile, _tribeID3); } + } else { + _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] + .buildingEntryY] + .addXgetTile; + DO_MOVE_TO_TILE(_buildingTile, _tribeID3); + } + } + } else if ((DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown == 0) + && (iVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, + this)(_aiType + -1, playerID), + DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk < iVar4)) { + + if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) + && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, TRUE), + BVar5 == FALSE)) { + + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + playerID, (undefined4)((int)(_indexTo6))); + + if (_buildingID != 0) { + _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] + .buildingEntryY] + .addXgetTile; + DO_MOVE_TO_TILE(_buildingTile, _tribeID3); + } else { _buildingID_2 = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); - - if (_buildingID_2 != 0) - goto LAB_004d2c00; + if (_buildingID_2 != 0) { + _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] + .buildingEntryY] + .addXgetTile; + DO_MOVE_TO_TILE(_buildingTile, _tribeID3); + } } - } - else if ((DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb6) - || (DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb5)) { + } else if ((DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb6) + || (DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb5)) { - if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) - && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, FALSE), - BVar5 == FALSE)) { - - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk, - (undefined4)((int)(_indexTo6))); - - if (_buildingID == 0) { + if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) + && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, FALSE), + BVar5 == FALSE)) { - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, - this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk, + (undefined4)((int)(_indexTo6))); - goto LAB_004d2d6b; - } - - goto LAB_004d2d6f; + if (_buildingID == 0) { + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, + this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); } + if (_buildingID != 0) { + _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] + .buildingEntryY] + .addXgetTile; + DO_MOVE_TO_TILE(_buildingTile, _tribeID3); + } } - else { - - BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, FALSE); - - if (BVar5 == FALSE) { - - iVar4 = (int)DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID; - - if ((((iVar4 == 0) - || (DAT_BuildingsState::instance.buildings[iVar4].uid - != DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID)) - || (DAT_BuildingsState::instance.buildings[iVar4].fireDuration != 0)) - || (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, TRUE), - BVar5 == FALSE)) { - - iVar4 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, - this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); - - if (iVar4 == 0) { - - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; - - DAT_GameState::instance.playerDataArray[playerID] - .someTotalDefenseTroopsRelatedCountdown = 0; - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, - DAT_UnitsState::ptr)(_tribeID3, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, iVar4, - DAT_BuildingsState::instance.buildings[iVar4].uid, 0); - - iVar3 = DAT_BuildingsState::instance.buildings[iVar4].uid; - - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = (short)iVar4; - - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID = iVar3; - - DAT_GameState::instance.playerDataArray[playerID] - .someTotalDefenseTroopsRelatedCountdown = 100; - } - - } - - else { - - if (DAT_GameState::instance.mapAndTime.yearChanged != 0) { - - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; - } - - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown - = 100; + } else { + BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, FALSE); + if (BVar5 == FALSE) { + iVar4 = (int)DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID; + if ((((iVar4 == 0) + || (DAT_BuildingsState::instance.buildings[iVar4].uid + != DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID)) + || (DAT_BuildingsState::instance.buildings[iVar4].fireDuration != 0)) + || (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( + _tribeID3, _indexTo6, TRUE), + BVar5 == FALSE)) { + iVar4 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, + this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + if (iVar4 == 0) { + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, + DAT_UnitsState::ptr)(_tribeID3, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, iVar4, + DAT_BuildingsState::instance.buildings[iVar4].uid, 0); + int iVar3 = DAT_BuildingsState::instance.buildings[iVar4].uid; + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = (short)iVar4; + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID = iVar3; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 100; } + } else { + if (DAT_GameState::instance.mapAndTime.yearChanged != 0) + DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 100; } } } + } - _ptrTribeID3 = _ptrTribeID3 + 1; - - _indexTo6 = _indexTo6 + TRUE; - - } while ((int)_indexTo6 < 6); - } + _ptrTribeID3 = _ptrTribeID3 + 1; + _indexTo6 = _indexTo6 + TRUE; + } while ((int)_indexTo6 < 6); - return; + #undef DO_MOVE_TO_TILE } - } } diff --git a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp index 50877b900..22307f6a7 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp @@ -37,451 +37,202 @@ namespace AI { using OpenSHC::Map::Units::UnitType; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D3AE0 void AICState ::aiRecruitUnits(int playerID) - { - - int* piVar1; - - AIRecruitUnitChoiceInt AVar2; - - bool bVar3; - - int iVar4; - - int iVar5; - + int _playerID2 = playerID; + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + UnitType _unitType = ((UnitType)0); + AICState* _pAICState = this; int _tribeID_defDiggingUnitMax; - int _unitID; - - UnitType _unitType; - - int iVar6; - - AICState* _pAICState; - - int local_8; - - int _aicRecruitInterval; - - int _nervousActionTracker; - - int _buildingID; - - int _unitChoiceIndex; - - AIRecruitUnitChoiceInt _unitTypeChoice; - - int _defTotal; - - AITypeInt _aiType; - - int _playerID2; - - bool _recruitDefDiggingUnit; - - _playerID2 = playerID; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - _unitType = ((UnitType)0); - - _pAICState = this; - - if (_aiType != OpenSHC::AI::AIT_NULL) { - - bVar3 = false; - - _recruitDefDiggingUnit = false; - - iVar6 = _aiType + ~OpenSHC::AI::AIT_NULL; - - if (((DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) - && (DAT_GameCore::instance.isSkirmishTrail == TRUE)) - && (DAT_GameCore::instance.currentTrailType == OpenSHC::Game::TT_EXTREME)) { - - bVar3 = true; - } - - iVar4 = iVar6 * 0xa9; - - _aicRecruitInterval = *(int*)((int)this - + (DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + iVar4) * 4 + 0x164); - - local_8 = -(uint)(_aicRecruitInterval != 0) + 2; - - if (bVar3) { - - local_8 = -(uint)(_aicRecruitInterval != 0) + 3; - } - - _nervousActionTracker = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; - - if (_nervousActionTracker < 1) { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker; + if (_aiType == OpenSHC::AI::AIT_NULL) + return; + + bool bVar3 = false; + bool _recruitDefDiggingUnit = false; + int iVar6 = _aiType + ~OpenSHC::AI::AIT_NULL; + + if (((DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) + && (DAT_GameCore::instance.isSkirmishTrail == TRUE)) + && (DAT_GameCore::instance.currentTrailType == OpenSHC::Game::TT_EXTREME)) + bVar3 = true; + + int iVar4 = iVar6 * 0xa9; + int _aicRecruitInterval = *(int*)((int)this + + (DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + iVar4) * 4 + 0x164); + int local_8 = -(uint)(_aicRecruitInterval != 0) + 2; + if (bVar3) + local_8 = -(uint)(_aicRecruitInterval != 0) + 3; + + int _nervousActionTracker = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + + if (_nervousActionTracker < 1) { + int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker; + *piVar1 = *piVar1 + 1; + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker < _aicRecruitInterval) + return; + } else { + local_8 = 4; + } - *piVar1 = *piVar1 + 1; + int iVar5 = DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount; + DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker = 0; - if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker < _aicRecruitInterval) { + if ((0 < iVar5) && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) { + AIRecruitUnitChoiceInt AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState; + if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { + int _defTotal = *(int*)((int)this + iVar6 * 0x2a4 + 0x170); + if (bVar3) _defTotal = (_defTotal * 4) / 3; + if (0 < _nervousActionTracker) _defTotal = _defTotal * 4; + if (_defTotal <= DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk) return; - } - - } - - else { - - local_8 = 4; + } else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( + iVar6, playerID); + if (iVar5 <= DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk) + return; + } else if ((AVar2 == OpenSHC::AI::AIRUC_ATTACKING) + && (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState != 0)) + return; + + iVar6 = iVar6 * 0x2a4; + + if (((*(int*)((int)this + iVar6 + 0x15c) != 0) + && (iVar5 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, + DAT_TileMapState::ptr)(playerID), iVar5 != 0)) + && ((_tribeID_defDiggingUnitMax = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10], + _tribeID_defDiggingUnitMax == 0 + || ((DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10] + != DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].uid + || ((int)DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].size + < *(int*)((int)this + iVar6 + 0x15c))))))) { + _recruitDefDiggingUnit = true; } - iVar5 = DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount; - - DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker = 0; - - if ((0 < iVar5) && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) { - - AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState; + playerID = 0; + if (0 < local_8) { + do { + // If we should recruit a digging unit but RNG says no, fall through to normal recruit + if (_recruitDefDiggingUnit && ((byte)SEC_RNG::instance.currentNumber2 & 1) != 0) + _recruitDefDiggingUnit = false; - if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { - - _defTotal = *(int*)((int)this + iVar6 * 0x2a4 + 0x170); - - if (bVar3) { - - _defTotal = (_defTotal * 4) / 3; - } - - if (0 < _nervousActionTracker) { - - _defTotal = _defTotal * 4; + if (_recruitDefDiggingUnit) { + if (DAT_GameState::instance.playerDataArray[_playerID2].barracks.id == 0) { + if (DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id == 0) + return; + } + _unitType = *(UnitType*)((int)this + iVar6 + 0x160); + } else { + AIRecruitUnitChoiceInt _unitTypeChoice = + DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; + + if (_unitTypeChoice == OpenSHC::AI::AIRUC_DEFENSIVE) { + if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex) + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; + if (*(int*)((int)this + + (DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex + iVar4) + * 4 + 0x184) == 0) + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; + int _unitChoiceIndex = + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex; + _unitType = *(UnitType*)((int)this + (iVar4 + _unitChoiceIndex) * 4 + 0x184); + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = + _unitChoiceIndex + 1; + } else if (_unitTypeChoice == OpenSHC::AI::AIRUC_RAIDING) { + if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex) + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; + if (*(int*)((int)this + + (DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex + iVar4) + * 4 + 0x1ac) == 0) + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; + iVar5 = DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex; + _unitType = *(UnitType*)((int)this + (iVar4 + iVar5) * 4 + 0x1ac); + DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = iVar5 + 1; + } else if (_unitTypeChoice == OpenSHC::AI::AIRUC_ATTACKING) { + _pAICState = (AICState*)MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::randomlySelectAttackUnitTypeToRecruit, this)(_playerID2); + _unitType = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::getUnitTypeForUnitBehaviourType, this)( + _playerID2, (AIUnitBehaviourType)((int)(_pAICState))); + } } - if (_defTotal <= DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk) { - + if (_unitType == ((UnitType)0)) return; - } - - } - - else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { - - iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( - iVar6, playerID); - - if (iVar5 <= DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk) { + int _buildingID; + if (_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; + else if (_unitType == OpenSHC::Map::Units::UT_E_LADDER) + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; + else if (_unitType == OpenSHC::Map::Units::UT_TUNNELER) + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].tunnelersGuild.id; + else if (_unitType == OpenSHC::Map::Units::UT_E_MONK) + _buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(_playerID2, OpenSHC::Map::Buildings::BT_CATHEDRAL); + else if ((int)_unitType < 0x46) + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].barracks.id; + else + _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id; + + if (_buildingID == 0) return; - } - - } - - else if ((AVar2 == OpenSHC::AI::AIRUC_ATTACKING) - && (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState != 0)) { - - return; - } - - iVar6 = iVar6 * 0x2a4; - - /* - DefDiggingUnitMax */ - - /* - DefDiggingUnitMax */ - - if (((*(int*)((int)this + iVar6 + 0x15c) != 0) - && (iVar5 - = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, - DAT_TileMapState::ptr)(playerID), - iVar5 != 0)) - && ((_tribeID_defDiggingUnitMax - = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10], - _tribeID_defDiggingUnitMax == 0 - || ((DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10] - != DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].uid - || ((int)DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].size - < *(int*)((int)this + iVar6 + 0x15c))))))) { - - _recruitDefDiggingUnit = true; - } - - playerID = 0; - - if (0 < local_8) { - - do { - - if (_recruitDefDiggingUnit) { - - if (((byte)SEC_RNG::instance.currentNumber2 & 1) != 0) { - - _recruitDefDiggingUnit = false; - - goto LAB_004d3cc1; - } - - if (DAT_GameState::instance.playerDataArray[_playerID2].barracks.id == 0) { - - if (DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id == 0) { - - return; - } - - /* - DefDiggingUnit */ - - _unitType = *(UnitType*)((int)this + iVar6 + 0x160); - - } - - else { - - /* - DefDiggingUnit */ - - _unitType = *(UnitType*)((int)this + iVar6 + 0x160); - } - - } - - else { - - LAB_004d3cc1: - _unitTypeChoice - = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; - - if (_unitTypeChoice == OpenSHC::AI::AIRUC_DEFENSIVE) { - - if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex) { - - DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; - } - - /* - DefUnit 1 up to 8 */ - - if (*(int*)((int)this - + (DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex - + iVar4) - * 4 - + 0x184) - == 0) { - DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; - } - - _unitChoiceIndex - = DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex; - - /* - DefUnit 1 up to 8 */ - - _unitType = *(UnitType*)((int)this + (iVar4 + _unitChoiceIndex) * 4 + 0x184); - - DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex - = _unitChoiceIndex + 1; - - } - - else if (_unitTypeChoice == OpenSHC::AI::AIRUC_RAIDING) { - - if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex) { - - DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; - } - - if (*(int*)((int)this - + (DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex - + iVar4) - * 4 - + 0x1ac) - == 0) { - - DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; - } - - iVar5 = DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex; - - _unitType = *(UnitType*)((int)this + (iVar4 + iVar5) * 4 + 0x1ac); - - DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = iVar5 + 1; - - } - - else if (_unitTypeChoice == OpenSHC::AI::AIRUC_ATTACKING) { - - _pAICState = (AICState*)MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::randomlySelectAttackUnitTypeToRecruit, this)( - _playerID2); - - _unitType - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getUnitTypeForUnitBehaviourType, - this)(_playerID2, (AIUnitBehaviourType)((int)(_pAICState))); - } - } - - if (_unitType == ((UnitType)0)) { + int _unitID; + if (((_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) + || (_unitType == OpenSHC::Map::Units::UT_E_LADDER) + || (_unitType == OpenSHC::Map::Units::UT_TUNNELER)) + || ((_unitType == OpenSHC::Map::Units::UT_E_MONK || (0x45 < (int)_unitType)))) { + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); + } else { + _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, + DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); + } + if (_unitID == 0) { + iVar6 = *(int*)((int)this + iVar6 + 0x9c); + if (iVar6 < 1) return; - } - - if (_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) { - - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; - - } - - else if (_unitType == OpenSHC::Map::Units::UT_E_LADDER) { - - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; - - } - - else if (_unitType == OpenSHC::Map::Units::UT_TUNNELER) { - - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].tunnelersGuild.id; - - } - - else if (_unitType == OpenSHC::Map::Units::UT_E_MONK) { - - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, - DAT_BuildingsState::ptr)(_playerID2, OpenSHC::Map::Buildings::BT_CATHEDRAL); - - } - - else if ((int)_unitType < 0x46) { - - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].barracks.id; - - } - - else { - - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id; - } - - if (_buildingID == 0) { - + if (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason != 2) return; - } - - if ((((_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) - || (_unitType == OpenSHC::Map::Units::UT_E_LADDER)) - || (_unitType == OpenSHC::Map::Units::UT_TUNNELER)) - || ((_unitType == OpenSHC::Map::Units::UT_E_MONK || (0x45 < (int)_unitType)))) { - - _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, - DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); - - } - - else { - - _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, - DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); - } - - if (_unitID == 0) { - - /* - tradeAmountEquipment */ - - iVar6 = *(int*)((int)this + iVar6 + 0x9c); - - if (iVar6 < 1) { - - return; - } - - if (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason != 2) { - - return; - } - - if (DAT_GameState::instance.playerDataArray[_playerID2].aiNervousActionsTracker < 1) { - - DAT_GameState::instance.playerDataArray[_playerID2] - .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] - = iVar6; - - return; - } - + if (DAT_GameState::instance.playerDataArray[_playerID2].aiNervousActionsTracker < 1) { DAT_GameState::instance.playerDataArray[_playerID2] - .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = 5; - + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = iVar6; return; } + DAT_GameState::instance.playerDataArray[_playerID2] + .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = 5; + return; + } - if (_recruitDefDiggingUnit) { - - /* - digging units? */ - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); - - } - - else { - - AVar2 = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; - - /* - 0 = defensive, 1 = raid, 2 = army */ - - if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { - - if (DAT_GameState::instance.playerDataArray[_playerID2].totalDefensiveTroopsUnk - < *(int*)((int)this + iVar6 + 0x180)) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignUnitToATribe, this)(_unitID); - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToSmallestPatrolTribe, this)( - _unitID); - } - - } - - else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignUnitToDefensiveTribe, this)( - _unitID); - - } - - else if (AVar2 == OpenSHC::AI::AIRUC_ATTACKING) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToItsTribe, this)( - _unitID, (int)((int)(_pAICState))); - } - } - - playerID = playerID + 1; - - if (local_8 <= playerID) { - - return; + if (_recruitDefDiggingUnit) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); + } else { + AVar2 = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; + if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { + if (DAT_GameState::instance.playerDataArray[_playerID2].totalDefensiveTroopsUnk + < *(int*)((int)this + iVar6 + 0x180)) + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignUnitToATribe, this)(_unitID); + else + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToSmallestPatrolTribe, this)(_unitID); + } else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignUnitToDefensiveTribe, this)(_unitID); + } else if (AVar2 == OpenSHC::AI::AIRUC_ATTACKING) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToItsTribe, this)( + _unitID, (int)((int)(_pAICState))); } + } - } while (true); - } + playerID = playerID + 1; + if (local_8 <= playerID) + return; + } while (true); } } - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp index a1c8bb331..8ccc1c4da 100644 --- a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp +++ b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp @@ -10,117 +10,72 @@ namespace AI { using OpenSHC::Map::Buildings::BuildingType; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CB3A0 undefined4 AICState ::aiRequiresExtraOxtethers(int playerID) { + int _playerID = playerID; - int* piVar1; - - int _buildingID; - - int _oxTetherCount; - - int _linkedTetherID; - - short* _linkedTetherIDs; - - int _linkedTetherCount; - - int _oxTetherLoopIndex; - - int _quarryID; - - int _stoneWaiting; - - int _playerID; - - _playerID = playerID; - - _buildingID + int _buildingID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_QUARRY); - _quarryID = 0; + // _stoneWaiting declared first so it gets lower stack slot + int _stoneWaiting = 0; + int _quarryID = 0; - /* - reuse of playerID!! */ - - playerID = 0; - - _oxTetherCount = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + int _oxTetherCount = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)(_playerID, OpenSHC::Map::Buildings::BT_OXTETHER, 1); - if (9 < _oxTetherCount) { - + if (_oxTetherCount >= 0xa) { return (undefined4)(0); } - piVar1 = &DAT_GameState::instance.playerDataArray[_playerID].highestLoadedQuarryUnk; + int* piVar1 = &DAT_GameState::instance.playerDataArray[_playerID].highestLoadedQuarryUnk; *piVar1 = 0; if (_buildingID != 0) { do { - - _stoneWaiting + int _localStone = DAT_BuildingsState::instance .buildings[(short)DAT_BuildingsState::instance.buildings[_buildingID].quarryStockpileID] .resourceStone; - _linkedTetherCount = 0; + int _linkedTetherCount = 0; - _linkedTetherIDs = DAT_BuildingsState::instance.buildings[_buildingID].quarryLinkedOxTethers; + short* _linkedTetherIDs = DAT_BuildingsState::instance.buildings[_buildingID].quarryLinkedOxTethers; - _oxTetherLoopIndex = 3; + int _oxTetherLoopIndex = 3; do { - - _linkedTetherID = (int)*_linkedTetherIDs; + int _linkedTetherID = (int)*_linkedTetherIDs; if (_linkedTetherID != 0) { - if ((DAT_BuildingsState::instance.buildings[_linkedTetherID].buildingType == OpenSHC::Map::Buildings::BT_OXTETHER) && (DAT_BuildingsState::instance.buildings[_linkedTetherID].oxtetherLinkedQuarryID == _buildingID)) { - _linkedTetherCount = _linkedTetherCount + 1; - - } - - else { - + } else { *_linkedTetherIDs = 0; } } _linkedTetherIDs = _linkedTetherIDs + 1; - _oxTetherLoopIndex = _oxTetherLoopIndex + -1; } while (_oxTetherLoopIndex != 0); - if (_linkedTetherCount < 1) { - + if (_linkedTetherCount <= 0) { *piVar1 = _buildingID; - return (undefined4)(1); } - /* - store the highest ratio of stone in quarry stockpile divided by linked ox - tethers */ - - if (playerID < _stoneWaiting / _linkedTetherCount) { - - playerID = _stoneWaiting / _linkedTetherCount; - + if (_stoneWaiting < _localStone / _linkedTetherCount) { _quarryID = _buildingID; + _stoneWaiting = _localStone / _linkedTetherCount; } _buildingID @@ -129,13 +84,8 @@ namespace AI { } while (_buildingID != 0); - /* - if the highest ratio is larger than 20, return true */ - - if (20 < playerID) { - + if (0x14 < _stoneWaiting) { *piVar1 = _quarryID; - return (undefined4)(1); } } diff --git a/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp index 173aa0643..1f3a4f198 100644 --- a/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp @@ -35,74 +35,71 @@ namespace AI { return FALSE; } - if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 1) { - return TRUE; - } - - int _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; - if (DAT_GameState::instance.playerDataArray[_attackedPlayerID].totalTroopValue < 100) { - DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 0; - } + if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk != 1) { + int _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + if (DAT_GameState::instance.playerDataArray[_attackedPlayerID].totalTroopValue < 100) { + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 0; + } - int _attForceBase = *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 500); - int _currentWaveStrength = DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; - int _totalAttack = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops - - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops; + int _attForceBase = *(int*)((int)this + (_aiType - 1) * 0x2a4 + 0x1f4); + int _currentWaveStrength = DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; + int _totalAttack = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops; - if (_totalAttack < _attForceBase + _currentWaveStrength) { - return FALSE; - } + if (_totalAttack < _attForceBase + _currentWaveStrength) { + return FALSE; + } - if (DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel == 0) { - return TRUE; - } + if (DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel == 0) { + return TRUE; + } - int _readyTeamMembers = 0; - int _unreadyTeamMembers = 0; - int _iPlayer = 1; - PlayerData* _pPlayerData = &DAT_GameState::instance.playerDataArray[1]; - - do { - if (_iPlayer != playerID) { - int _isAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_iPlayer); - if (_isAlive != 0) { - BOOLEnum _isAI = MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, - DAT_GameSynchronyState::ptr)(_iPlayer); - if (_isAI != FALSE) { - if (DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] - == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { - if (_pPlayerData->aiPlayerState != 0) { - return TRUE; - } - if (_pPlayerData->totalAttackTroops - _pPlayerData->totalAttackingEngineerTroops - < *(int*)((int)DAT_EntityState::instance.seagullArray + _pPlayerData->aiType * 0x2a4 - + 0x2664) - + _pPlayerData->currentWaveRandomAttackingStrength) { - _unreadyTeamMembers = _unreadyTeamMembers + 1; - } - else { - _readyTeamMembers = _readyTeamMembers + 1; + int _readyTeamMembers = 0; + int _unreadyTeamMembers = 0; + int _iPlayer = 1; + PlayerData* _pPlayerData = &DAT_GameState::instance.playerDataArray[1]; + + do { + if (_iPlayer != playerID) { + int _isAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_iPlayer); + if (_isAlive != 0) { + BOOLEnum _isAI = MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, + DAT_GameSynchronyState::ptr)(_iPlayer); + if (_isAI != FALSE) { + if (DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + if (_pPlayerData->aiPlayerState != 0) { + return TRUE; + } + if (_pPlayerData->totalAttackTroops - _pPlayerData->totalAttackingEngineerTroops + >= *(int*)((int)this + (_pPlayerData->aiType - 1) * 0x2a4 + 0x1f4) + + _pPlayerData->currentWaveRandomAttackingStrength) { + _readyTeamMembers = _readyTeamMembers + 1; + } + else { + _unreadyTeamMembers = _unreadyTeamMembers + 1; + } } } } } - } - _iPlayer = _iPlayer + 1; - _pPlayerData = _pPlayerData + 1; - } while (_iPlayer < 9); + _iPlayer = _iPlayer + 1; + _pPlayerData = _pPlayerData + 1; + } while (_iPlayer < 9); - if (_readyTeamMembers >= DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel) { - return TRUE; - } - if (_unreadyTeamMembers == 0) { - return TRUE; - } - DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience = - DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience + 1; - if (DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience <= 0x30 - || (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CAMPAIGN_MISSION)) { - return FALSE; + if (_readyTeamMembers >= DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel) { + return TRUE; + } + if (_unreadyTeamMembers == 0) { + return TRUE; + } + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience = + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience + 1; + if (DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience <= 0x30 + || (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CAMPAIGN_MISSION)) { + return FALSE; + } } return TRUE; diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp index 29132eb9c..8f0775778 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp @@ -11,22 +11,21 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB220 BOOLEnum AICState::aiShouldBuildFarm(int playerID) { - int const _playerID = playerID; - unsigned int aiType = DAT_GameState::instance.playerDataArray[_playerID].aiType; + unsigned int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (aiType == AITA_NULL) { - return aiType; // return 0 => return + return (BOOLEnum)aiType; } aiType -= 1; int const _farmCount - = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countFarms, DAT_BuildingsState::ptr)(_playerID, 1); + = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countFarms, DAT_BuildingsState::ptr)(playerID, 1); if (_farmCount <= 0) { return TRUE; } - if (_farmCount >= (int)this->aics[aiType].maxFarms) { - return FALSE; + if (_farmCount < (int)this->aics[aiType].maxFarms) { + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / _farmCount + >= (int)this->aics[aiType].populationPerFarm; } - return DAT_GameState::instance.playerDataArray[_playerID].currentPopulation / _farmCount - >= (int)this->aics[aiType].populationPerFarm; + return FALSE; } } } diff --git a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp index 8bf86d291..7bd2e0f18 100644 --- a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp +++ b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp @@ -11,147 +11,95 @@ namespace AI { using OpenSHC::AI::AITypeInt; // FUNCTION: STRONGHOLDCRUSADER 0x004CAEA0 - void AICState ::aiUpdateTaxesAndRations(int playerID) + void AICState::aiUpdateTaxesAndRations(int playerID) { - int _offset; - int _newTaxesVal; - int _newTaxes; - int _popularity; - int _currentTaxes; - int _taxesMin; - int _taxesMax; - int _peasants; - int _decision; - int _totalFood_2; - int _totalFood_1; - int _taxes; - AITypeInt _aiType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType == OpenSHC::AI::AIT_NULL) { + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == OpenSHC::AI::AIT_NULL) return; - } - _offset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + _aiType = _aiType - 1; + int const _popularity = DAT_GameState::instance.playerDataArray[playerID].popularity; - _popularity = DAT_GameState::instance.playerDataArray[playerID].popularity; - - // criticalPopularity - comparison order matches original: first jg sets decision=2 (critical) - if (*(int*)((int)this + _offset + 0x18) >= _popularity) { + if (_popularity <= (int)this->aics[_aiType].criticalPopularity) { DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 2; - } else if (*(int*)((int)this + _offset + 0x1c) < _popularity) { - // highestPopularity - if (*(int*)((int)this + _offset + 0x20) >= _popularity) { - DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 0; - } - } else { + } else if (_popularity <= (int)this->aics[_aiType].lowestPopularity) { DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 1; + } else if (_popularity >= (int)this->aics[_aiType].highestPopularity) { + DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 0; } - _decision = DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue; + int const _decision = DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue; if (_decision == 2) { - _totalFood_2 = DAT_GameState::instance.playerDataArray[playerID].totalFood; + int const _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 2; - - if (_totalFood_2 <= 0) { + if (_totalFood <= 0) { DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; - } else if (_totalFood_2 < 5) { + } else if (_totalFood <= 4) { DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; } else { - int _r = 0; - if (_totalFood_2 > 8) _r = 1; - DAT_GameState::instance.playerDataArray[playerID].rationsSetting = _r + 3; + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = (_totalFood > 8) + 3; } - - goto LAB_004cb010; - } - - if (_decision == 1) { - _currentTaxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; - _taxesMin = *(int*)((int)this + _offset + 0x24); - - if (_taxesMin < _currentTaxes) { + } else if (_decision == 1) { + int const _currentTaxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; + int const _taxesMin = (int)this->aics[_aiType].taxesMin; + if (_currentTaxes > _taxesMin) { DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _currentTaxes - 1; } else { DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxesMin; } - - _totalFood_1 = DAT_GameState::instance.playerDataArray[playerID].totalFood; - - if (_totalFood_1 <= 0) { + int const _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; + if (_totalFood <= 0) { DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; + } else if (_totalFood <= 10) { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; } else { - if (_totalFood_1 <= 0xa) - goto LAB_004caff1; DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 3; } - } else { - if (_decision != 0) - goto LAB_004cb010; - - _taxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; - _taxesMax = *(int*)((int)this + _offset + 0x28); + int const _rationsMod = (int)this->aics[_aiType].doubleRationsFoodThreshold; + if (_rationsMod != 0 && _totalFood >= _rationsMod) + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; + } else if (_decision == 0) { + int const _taxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; + int const _taxesMax = (int)this->aics[_aiType].taxesMax; if (_taxes < _taxesMax) { - _peasants = DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants; - int _r2 = 0; - if (_peasants < 0xf) { - if (_peasants >= 0xa) _r2 = 1; - _newTaxesVal = _r2 + 4; - } else { + int const _peasants = DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants; + int _newTaxesVal; + if (_peasants >= 0xf) { _newTaxesVal = 6; + } else { + _newTaxesVal = (_peasants >= 0xa) + 4; } - if (DAT_GameState::instance.playerDataArray[playerID].storedPopularityPercent > _popularity) { - if (_taxes <= _newTaxesVal) - goto LAB_004cafcd; - _newTaxes = _taxes - 1; - } else { - _newTaxes = _taxes + 1; + if (!(DAT_GameState::instance.playerDataArray[playerID].storedPopularityPercent > _popularity)) { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxes + 1; + } else if (_taxes > _newTaxesVal) { + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxes - 1; } - DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _newTaxes; } else { DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxesMax; } - LAB_004cafcd: - _totalFood_1 = DAT_GameState::instance.playerDataArray[playerID].totalFood; - - if (_totalFood_1 < 0xb) { + int const _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; + if (_totalFood <= 10) { DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; - goto LAB_004cb010; + } else { + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; + int const _rationsMod = (int)this->aics[_aiType].doubleRationsFoodThreshold; + if (_rationsMod != 0 && _totalFood >= _rationsMod) + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; } - - LAB_004caff1: - DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; - } - - _newTaxes = *(int*)((int)this + _offset + 0xa8); - - if ((_newTaxes != 0) && (_newTaxes <= _totalFood_1)) { - DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; } - LAB_004cb010: - if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting < 0) { + if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting < 0) DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 0; - } - - if (11 < DAT_GameState::instance.playerDataArray[playerID].taxesSetting) { + if (11 < DAT_GameState::instance.playerDataArray[playerID].taxesSetting) DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 11; - } - - if (DAT_GameState::instance.playerDataArray[playerID].rationsSetting < 0) { + if (DAT_GameState::instance.playerDataArray[playerID].rationsSetting < 0) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; - } - - if (4 < DAT_GameState::instance.playerDataArray[playerID].rationsSetting) { + if (4 < DAT_GameState::instance.playerDataArray[playerID].rationsSetting) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; - } - - return; } } } diff --git a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp index 595a02e11..b180166d0 100644 --- a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp +++ b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp @@ -11,91 +11,64 @@ namespace AI { using OpenSHC::Map::Buildings::BuildingTypeInt; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CDB20 int AICState ::chooseRandomBuildingIDFromPlayersArrayOfBuildings(int playerID) { - int _chosenBuilding; - - int _selectionIndex; - - int _chosenBuildingTypeIndex; - - short* _ptr_buildingIDArray; - - int _buildingID; - - BuildingTypeInt _buildingType; - - bool bVar1; - - _selectionIndex = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + int _count = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; - _chosenBuilding = 0; + int _chosenBuilding = 0; - _chosenBuildingTypeIndex = 46; + int _chosenBuildingTypeIndex = 46; - if (0 < _selectionIndex) { + if (0 < _count) { - _ptr_buildingIDArray = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings; + int _rng = (int)(unsigned char)SEC_RNG::instance.currentNumber2 & 7; - playerID = _selectionIndex; + short* _ptr = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings; do { - _buildingID = (int)*_ptr_buildingIDArray; - - if ((_buildingID != 0) && (_selectionIndex = 0, 0 < _chosenBuildingTypeIndex)) { - - _buildingType - = (BuildingTypeInt)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType; - - do { - - if (((byte)SEC_RNG::instance.currentNumber2 & 7) < 2) { - - bVar1 = _buildingType - == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet3[_selectionIndex]; - - } - - else if (((byte)SEC_RNG::instance.currentNumber2 & 7) < 4) { + int _buildingID = (int)*_ptr; - bVar1 = _buildingType - == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet2[_selectionIndex]; + if (_buildingID != 0) { - } + int _selectionIndex = 0; - else { + if (0 < _chosenBuildingTypeIndex) { - bVar1 = _buildingType - == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_selectionIndex]; - } + BuildingTypeInt _buildingType = + (BuildingTypeInt)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType; - if (bVar1) { + do { - /* - very unique way to break from a loop ;) */ + BuildingTypeInt _cmpType; - _chosenBuilding = _buildingID; + if (_rng < 2) { + _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet3[_selectionIndex]; + } else if (_rng < 4) { + _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet2[_selectionIndex]; + } else { + _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_selectionIndex]; + } - _chosenBuildingTypeIndex = _selectionIndex; - } + if (_buildingType == _cmpType) { + _chosenBuilding = _buildingID; + _chosenBuildingTypeIndex = _selectionIndex; + } - _selectionIndex = _selectionIndex + 1; + _selectionIndex = _selectionIndex + 1; - } while (_selectionIndex < _chosenBuildingTypeIndex); + } while (_selectionIndex < _chosenBuildingTypeIndex); + } } - _ptr_buildingIDArray = _ptr_buildingIDArray + 1; + _ptr = _ptr + 1; - playerID = playerID + -1; + _count = _count - 1; - } while (playerID != 0); + } while (_count != 0); } return _chosenBuilding; diff --git a/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp index ca0fa349b..5d3637d4c 100644 --- a/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp +++ b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp @@ -10,40 +10,24 @@ namespace AI { using OpenSHC::Synchrony::GameSynchronyState; - /* - 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 0x004CAC70 void AICState ::clearPlayerDataInformationChunk() { - - GameSynchronyState* piVar1; - - int* _Dst; - - _Dst = &DAT_GameState::instance.playerDataArray[0].aiFarmIndex; - - piVar1 = (GameSynchronyState*)DAT_GameSynchronyState::instance.currentAIArray; + int* _Dst = &DAT_GameState::instance.playerDataArray[0].aiFarmIndex; + int* _pAI = DAT_GameSynchronyState::instance.currentAIArray; + int* _pFullID = DAT_GameSynchronyState::instance.currentPlayerFullIDArray; do { - - if ((piVar1->currentPlayerFullIDArray[0] != -1) || (piVar1->currentAIArray[0] == 0)) { - + if (*_pFullID != -1 || *_pAI == 0) { MACRO_CALL(OpenSHC::OS_Func::_memset)(_Dst, 0, (size_t)((int)(3748))); } - piVar1 = (GameSynchronyState*)(piVar1->currentAIArray + 1); - + _pAI = _pAI + 1; + _pFullID = _pFullID + 1; _Dst = _Dst + 3709; - } while ((int)piVar1 < 0x191dea0); + } while ((int)_pAI < 0x191dea0); return; } diff --git a/src/OpenSHC/AI/AICState/computeNervousness.cpp b/src/OpenSHC/AI/AICState/computeNervousness.cpp index 2d0d9f26e..ca79afa7c 100644 --- a/src/OpenSHC/AI/AICState/computeNervousness.cpp +++ b/src/OpenSHC/AI/AICState/computeNervousness.cpp @@ -11,75 +11,43 @@ namespace AI { void AICState ::computeNervousness(int playerID) { + int _one = 1; - int iVar1; - - int _someCutoff; - - int _totalTroopValueOfEnemy; - - iVar1 = DAT_TroopValueState::instance.attackInfo.playerTotalTroopValueOfTroopsNearKeep[playerID]; + int iVar1 = DAT_TroopValueState::instance.attackInfo.playerTotalTroopValueOfTroopsNearKeep[playerID]; - _totalTroopValueOfEnemy = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; + int _totalTroopValueOfEnemy = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; - int _one = 1; + int _someCutoff; if (_totalTroopValueOfEnemy < 50) { - _someCutoff = _one - 0x15; - - } - - else if (_totalTroopValueOfEnemy < 100) { - + } else if (_totalTroopValueOfEnemy < 100) { _someCutoff = 0; - - } - - else if (_totalTroopValueOfEnemy < 200) { - + } else if (_totalTroopValueOfEnemy < 200) { _someCutoff = 20; - - } - - else if (_totalTroopValueOfEnemy < 400) { - + } else if (_totalTroopValueOfEnemy < 400) { _someCutoff = 100; - - } - - else if (_totalTroopValueOfEnemy < 600) { - + } else if (_totalTroopValueOfEnemy < 600) { _someCutoff = 200; - - } - - else { - + } else { _someCutoff = ((_totalTroopValueOfEnemy >= 800) - _one & 0xffffff38) + 500; } if (iVar1 > _someCutoff + _totalTroopValueOfEnemy) { - DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue = 0; - return; } if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue == 0) { - - if (iVar1 < DAT_GameState::instance.playerDataArray[playerID] - .totalEnemyTroopValueByPlayerID[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { - + if (DAT_GameState::instance.playerDataArray[playerID] + .totalEnemyTroopValueByPlayerID[DAT_GameSynchronyState::instance.currentPlayerSlotID] + > iVar1) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playNervous1BikFromPlayer, this)(playerID); } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playRequestHelpBikFromPlayer, this)(playerID); } DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue = _one; - - return; } } diff --git a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp index 59f8a77c5..5e71e48dc 100644 --- a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp +++ b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp @@ -23,265 +23,147 @@ namespace AI { using OpenSHC::Map::Units::UnitInstructionType; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D1A00 void AICState ::decideOnTribeAttackLocation(uint tribeID_OR_moatWasHit) - { + uint _tribeID = tribeID_OR_moatWasHit; - short* psVar1; - - short sVar2; - - bool bVar3; - - BOOLEnum _canHaveActivity; - - int _unitID; - - BOOLEnum BVar4; - - int _targetBuilding; - - int _buildingID; - - int _buildingID_2; - - int iVar5; - - int _destinationX; - - int _targetPlayer; - - int _destinationY; - - int _y; - - int _x; - - int _buildingUID; - - int _rng; - - int _destinationTile; - - uint _tribeID; - - _tribeID = tribeID_OR_moatWasHit; - - _canHaveActivity + BOOLEnum _canHaveActivity = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(tribeID_OR_moatWasHit, FALSE, TRUE); - if (_canHaveActivity != FALSE) { - DAT_TribesState::instance.tribes[_tribeID].counter = 0; - return; } - _targetPlayer = (int)DAT_TribesState::instance.tribes[_tribeID].targetPlayer_outpost; + int _targetPlayer = (int)DAT_TribesState::instance.tribes[_tribeID].targetPlayer_outpost; if (DAT_TribesState::instance.tribes[_tribeID].randomNumber == 0) { - DAT_TribesState::instance.tribes[_tribeID].randomNumber = (int)SEC_RNG::instance.currentNumber2; - MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); } - _rng = DAT_TribesState::instance.tribes[_tribeID].randomNumber; - - psVar1 = &DAT_TribesState::instance.tribes[_tribeID].counter; - + int _rng = DAT_TribesState::instance.tribes[_tribeID].randomNumber; + short* psVar1 = &DAT_TribesState::instance.tribes[_tribeID].counter; *psVar1 = *psVar1 + 1; if ((int)DAT_TribesState::instance.tribes[_tribeID].counter == _rng % 6 + 7) { - DAT_TribesState::instance.tribes[_tribeID].counter = 0; - - /* - WARNING: tribeID has a new purpose */ - tribeID_OR_moatWasHit = tribeID_OR_moatWasHit & 0xffffff00; - - _x = 0; - - _y = 0; - - _unitID = MACRO_CALL_MEMBER( + int _x = 0; + int _y = 0; + int _unitID = MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::getUnitIDForIndexInTribe, DAT_TribesState::ptr)(_tribeID, 0); - if ((_unitID != 0) - && (bVar3 = MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, - DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[_tribeID].owner, _targetPlayer, - (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), - (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), (byte*)&tribeID_OR_moatWasHit, - &_x, &_y), - bVar3)) { - + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, + DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[_tribeID].owner, _targetPlayer, + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), (byte*)&tribeID_OR_moatWasHit, + &_x, &_y)) { if ((char)tribeID_OR_moatWasHit != '\0') { - - /* - moat was not hit */ - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( _tribeID, ((UnitInstructionType)0x23), DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile + _x, 0, 0); - return; } - - /* - moat was hit */ - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( _tribeID, OpenSHC::Map::Units::UIT_FILL_MOAT, _x, _y, 1000); - return; } } - sVar2 = DAT_TribesState::instance.tribes[_tribeID].tribeSubtype1; + short sVar2 = DAT_TribesState::instance.tribes[_tribeID].tribeSubtype1; if ((sVar2 != 0xb6) && (sVar2 != 0xb9)) { - - BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, FALSE); - - if (BVar4 != FALSE) { - + BOOLEnum BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, FALSE); + if (BVar4 != FALSE) return; - } - - _targetBuilding = (int)DAT_TribesState::instance.tribes[_tribeID].targetBuildingID; + int _targetBuilding = (int)DAT_TribesState::instance.tribes[_tribeID].targetBuildingID; if ((((_targetBuilding != 0) && (DAT_BuildingsState::instance.buildings[_targetBuilding].uid == DAT_TribesState::instance.tribes[_tribeID].targetBuildingUID)) && (DAT_BuildingsState::instance.buildings[_targetBuilding].fireDuration == 0)) && (BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, TRUE), BVar4 != FALSE)) { - - if (DAT_GameState::instance.mapAndTime.yearChanged == 0) { - + if (DAT_GameState::instance.mapAndTime.yearChanged == 0) return; - } - DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = 0; - return; } - _buildingID = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + int _buildingID = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, DAT_GameState::ptr)(_targetPlayer); - if (_buildingID != 0) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( _tribeID, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, _buildingID, DAT_BuildingsState::instance.buildings[_buildingID].uid, 0); - - _buildingUID = DAT_BuildingsState::instance.buildings[_buildingID].uid; - + int _buildingUID = DAT_BuildingsState::instance.buildings[_buildingID].uid; DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = (short)_buildingID; - DAT_TribesState::instance.tribes[_tribeID].targetBuildingUID = _buildingUID; - return; } - _destinationX = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; - + int _destinationX = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = 0; - - _destinationY = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry; - + int _destinationY = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry; BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(_tribeID, DAT_ViewportRenderState::instance.translationMatrix[_destinationY].addXgetTile + _destinationX); - - if (BVar4 == FALSE) { - + if (BVar4 == FALSE) return; - } - - goto LAB_004d1c59; + // was LAB_004d1c59 + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + _tribeID, (uint)((int)(_destinationX)), (uint)((int)(_destinationY)), 1); + return; } - _buildingID_2 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + int _buildingID_2 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, DAT_GameState::ptr)(_targetPlayer); - if (_buildingID_2 == 0) { + int _destinationTile; + int _destinationX2; + int _destinationY2; - iVar5 = DAT_ViewportRenderState::instance + if (_buildingID_2 == 0) { + int iVar5 = DAT_ViewportRenderState::instance .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] .addXgetTile; - - LAB_004d1d11: _destinationTile = iVar5 + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; - - } - - else { - - iVar5 = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; - + } else { + int iVar5 = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; if (iVar5 == 0) { - _destinationTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + DAT_ViewportRenderState::instance .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryY] .addXgetTile; - - } - - else { - + } else { MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathfindingForAttacksUnk, DAT_PathFindingState::ptr)(_tribeID, _buildingID_2, 1, (dword)((int)((int)(short)DAT_TileMapState::instance .PathConnectionLayer[DAT_UnitsState::instance.units[iVar5].tile])), _targetPlayer); - _destinationTile = DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile1; - if (DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper == 0) { - - iVar5 = DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer] - .campground.yEntry] + // was LAB_004d1d11 + int iVar5b = DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] .addXgetTile; - - goto LAB_004d1d11; + _destinationTile = iVar5b + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; } } } if (_destinationTile != 0) { - - _destinationY - = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_destinationTile]; - - _destinationX - = _destinationTile - DAT_ViewportRenderState::instance.translationMatrix[_destinationY].addXgetTile; - - BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( + _destinationY2 = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_destinationTile]; + _destinationX2 = _destinationTile - DAT_ViewportRenderState::instance.translationMatrix[_destinationY2].addXgetTile; + BOOLEnum BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( _tribeID, _destinationTile); - if (BVar4 != FALSE) { - - LAB_004d1c59: MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( - _tribeID, (uint)((int)(_destinationX)), (uint)((int)(_destinationY)), 1); - + _tribeID, (uint)((int)(_destinationX2)), (uint)((int)(_destinationY2)), 1); return; } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(_tribeID, _targetPlayer); } - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp index 55622a561..42b5dde68 100644 --- a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp +++ b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp @@ -11,98 +11,61 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0280 void AICState::destroyAnyBuildingInCategory(int playerID, AINervousDestroyBuildingCategory buildingCategory) { - Map::Buildings::BuildingTypeShort BVar1; - int _buildingID; - bool bVar2; - - _buildingID = 1; + int _buildingID = 1; if (1 < DAT_BuildingsState::instance.maxBuildingsCount) { Map::Buildings::Building* pBVar2 = &DAT_BuildingsState::instance.buildings[1]; do { if (((pBVar2->logicalState != 0) && (pBVar2->logicalState != Map::Buildings::BLS_REMOVE)) && (pBVar2->owner == playerID)) { + + bool _matches = false; + Map::Buildings::BuildingTypeShort BVar1 = pBVar2->buildingType; + if (buildingCategory == AINDBC_FEAR_FACTOR_BUILDINGS) { - BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_CESSPIT) && (BVar1 != Map::Buildings::BT_BURNINGSTAKE)) - && (((BVar1 != Map::Buildings::BT_GIBBET - && (((BVar1 != Map::Buildings::BT_DUNGEON - && (BVar1 != Map::Buildings::BT_STRETCHINGRACK)) - && (BVar1 != Map::Buildings::BT_RACKFLOGGING)))) - && (((BVar1 != Map::Buildings::BT_CHOPPINGBLOCK - && (BVar1 != Map::Buildings::BT_DUNKINGSTOOL)) - && ((BVar1 != Map::Buildings::BT_DOGCAGE - && (( - (BVar1 != Map::Buildings::BT_STATUE && (BVar1 != Map::Buildings::BT_SHRINE)) - && ((BVar1 != Map::Buildings::BT_DANCINGBEAR - && ((((BVar1 != Map::Buildings::BT_POND - && (BVar1 != Map::Buildings::BT_GALLOWS)) - && (BVar1 != Map::Buildings::BT_STOCKS)) - && ((BVar1 != Map::Buildings::BT_WITCHHOIST - && (BVar1 != Map::Buildings::BT_MAYPOLE)))))))))))))))) { - bVar2 = BVar1 == Map::Buildings::BT_GARDEN; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_CESSPIT || BVar1 == Map::Buildings::BT_BURNINGSTAKE + || BVar1 == Map::Buildings::BT_GIBBET || BVar1 == Map::Buildings::BT_DUNGEON + || BVar1 == Map::Buildings::BT_STRETCHINGRACK || BVar1 == Map::Buildings::BT_RACKFLOGGING + || BVar1 == Map::Buildings::BT_CHOPPINGBLOCK || BVar1 == Map::Buildings::BT_DUNKINGSTOOL + || BVar1 == Map::Buildings::BT_DOGCAGE || BVar1 == Map::Buildings::BT_STATUE + || BVar1 == Map::Buildings::BT_SHRINE || BVar1 == Map::Buildings::BT_DANCINGBEAR + || BVar1 == Map::Buildings::BT_POND || BVar1 == Map::Buildings::BT_GALLOWS + || BVar1 == Map::Buildings::BT_STOCKS || BVar1 == Map::Buildings::BT_WITCHHOIST + || BVar1 == Map::Buildings::BT_MAYPOLE || BVar1 == Map::Buildings::BT_GARDEN); } else if (buildingCategory == AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS) { - BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_FLETCHER) && (BVar1 != Map::Buildings::BT_BLACKSMITH)) - && (((BVar1 != Map::Buildings::BT_POLETURNER - && (((BVar1 != Map::Buildings::BT_ARMOURER && (BVar1 != Map::Buildings::BT_TANNER)) - && (BVar1 != Map::Buildings::BT_INN)))) - && (((BVar1 != Map::Buildings::BT_APOTHECARY && (BVar1 != Map::Buildings::BT_CHAPEL)) - && (BVar1 != Map::Buildings::BT_CHURCH)))))) { - bVar2 = BVar1 == Map::Buildings::BT_CATHEDRAL; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_FLETCHER || BVar1 == Map::Buildings::BT_BLACKSMITH + || BVar1 == Map::Buildings::BT_POLETURNER || BVar1 == Map::Buildings::BT_ARMOURER + || BVar1 == Map::Buildings::BT_TANNER || BVar1 == Map::Buildings::BT_INN + || BVar1 == Map::Buildings::BT_APOTHECARY || BVar1 == Map::Buildings::BT_CHAPEL + || BVar1 == Map::Buildings::BT_CHURCH || BVar1 == Map::Buildings::BT_CATHEDRAL); } else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) { - BVar1 = pBVar2->buildingType; - if (((((BVar1 != Map::Buildings::BT_GATEHOUSELARGE) - && (BVar1 != Map::Buildings::BT_GATEHOUSESMALL)) - && ((BVar1 != Map::Buildings::BT_DRAWBRIDGE - && ((((BVar1 != Map::Buildings::BT_TOWER1 && (BVar1 != Map::Buildings::BT_TOWER2)) - && (BVar1 != Map::Buildings::BT_TOWER3)) - && ((BVar1 != Map::Buildings::BT_TOWER4 - && (BVar1 != Map::Buildings::BT_TOWER5)))))))) - && (BVar1 != Map::Buildings::BT_ENGINEERSGUILD)) - && (BVar1 != Map::Buildings::BT_TUNNELERSGUILD)) { - bVar2 = BVar1 == Map::Buildings::BT_OILSMELTER; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_GATEHOUSELARGE || BVar1 == Map::Buildings::BT_GATEHOUSESMALL + || BVar1 == Map::Buildings::BT_DRAWBRIDGE || BVar1 == Map::Buildings::BT_TOWER1 + || BVar1 == Map::Buildings::BT_TOWER2 || BVar1 == Map::Buildings::BT_TOWER3 + || BVar1 == Map::Buildings::BT_TOWER4 || BVar1 == Map::Buildings::BT_TOWER5 + || BVar1 == Map::Buildings::BT_ENGINEERSGUILD || BVar1 == Map::Buildings::BT_TUNNELERSGUILD + || BVar1 == Map::Buildings::BT_OILSMELTER); } else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) { - BVar1 = pBVar2->buildingType; - if ((BVar1 != Map::Buildings::BT_MERCENARYPOST) && (BVar1 != Map::Buildings::BT_BARRACKS)) { - bVar2 = BVar1 == Map::Buildings::BT_STABLES; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_MERCENARYPOST || BVar1 == Map::Buildings::BT_BARRACKS + || BVar1 == Map::Buildings::BT_STABLES); } else if (buildingCategory == AINDBC_WATER_BUILDINGS) { - if (pBVar2->buildingType != Map::Buildings::BT_WELL) { - bVar2 = pBVar2->buildingType == Map::Buildings::BT_WATERPOT; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_WELL || BVar1 == Map::Buildings::BT_WATERPOT); } else if (buildingCategory == AINDBC_RESOURCE_BUILDINGS) { - BVar1 = pBVar2->buildingType; - if (((BVar1 != Map::Buildings::BT_OXTETHER) && (BVar1 != Map::Buildings::BT_IRONMINE)) - && ((BVar1 != Map::Buildings::BT_PITCHRIG - && (((BVar1 != Map::Buildings::BT_BAKERY && (BVar1 != Map::Buildings::BT_BREWERY)) - && (BVar1 != Map::Buildings::BT_QUARRY)))))) { - bVar2 = BVar1 == Map::Buildings::BT_MILL; - LAB_004d04de: - if (!bVar2) - goto LAB_004d04f9; - } - } else { - if (((buildingCategory == AINDBC_FARMS) - && (BVar1 = pBVar2->buildingType, BVar1 != Map::Buildings::BT_WHEATFARM)) - && ((BVar1 != Map::Buildings::BT_HOPFARM && (BVar1 != Map::Buildings::BT_APPLEFARM)))) { - bVar2 = BVar1 == Map::Buildings::BT_DAIRYFARM; - goto LAB_004d04de; - } + _matches = (BVar1 == Map::Buildings::BT_OXTETHER || BVar1 == Map::Buildings::BT_IRONMINE + || BVar1 == Map::Buildings::BT_PITCHRIG || BVar1 == Map::Buildings::BT_BAKERY + || BVar1 == Map::Buildings::BT_BREWERY || BVar1 == Map::Buildings::BT_QUARRY + || BVar1 == Map::Buildings::BT_MILL); + } else if (buildingCategory == AINDBC_FARMS) { + _matches = (BVar1 == Map::Buildings::BT_WHEATFARM || BVar1 == Map::Buildings::BT_HOPFARM + || BVar1 == Map::Buildings::BT_APPLEFARM || BVar1 == Map::Buildings::BT_DAIRYFARM); + } + + if (_matches) { + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( + _buildingID); } - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( - _buildingID); } - LAB_004d04f9: _buildingID = _buildingID + 1; pBVar2 = pBVar2 + 1; } while (_buildingID < DAT_BuildingsState::instance.maxBuildingsCount); diff --git a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp index e34daac0d..29895258e 100644 --- a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp +++ b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp @@ -14,31 +14,32 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB940 undefined4 AICState::destroyBuildingIfNoWorker(int buildingID) { - short _value; - int _owner; - _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; - _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; - if ((((0 < _value) && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1)) - && (DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0)) - && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY)) { + short _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; + int _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; + + if (0 < _value && DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1 + && DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0 + && DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY) { + if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] != 0) { -LAB_CHECK_MONTH: - if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) { + if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = _value + -1; - } - } else { - if (!((short)0x14 <= _value)) { - goto LAB_CHECK_MONTH; - } - MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( - (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, - (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( - buildingID); - return 1; + return 0; } + + // workers == 0: check if old enough + if ((short)_value < (short)0x14) + return 0; + + // old enough: destroy + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, + (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( + buildingID); + return 1; } return 0; } diff --git a/src/OpenSHC/AI/AICState/destroyHouse.cpp b/src/OpenSHC/AI/AICState/destroyHouse.cpp index e04f4d87f..108bf6d85 100644 --- a/src/OpenSHC/AI/AICState/destroyHouse.cpp +++ b/src/OpenSHC/AI/AICState/destroyHouse.cpp @@ -13,22 +13,31 @@ namespace AI { BOOLEnum AICState::destroyHouse(int playerID) { int _hovelID; - if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) - && (_hovelID = DAT_GameState::instance.playerDataArray[playerID].currentPopulation, - _hovelID <= DAT_GameState::instance.playerDataArray[playerID].populationCap)) - && (8 < _hovelID)) - && (0x14 < DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk)) { - _hovelID = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, - DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_HOVEL); - if (_hovelID == 0) { - return FALSE; - } - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(_hovelID, playerID, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hovelID); - return TRUE; - } - return FALSE; + + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) + return FALSE; + + _hovelID = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; + + if (_hovelID > DAT_GameState::instance.playerDataArray[playerID].populationCap) + return FALSE; + + if (_hovelID <= 8) + return FALSE; + + if (DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk <= 0x14) + return FALSE; + + _hovelID = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_HOVEL); + + if (_hovelID == 0) + return FALSE; + + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(_hovelID, playerID, 0x32); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hovelID); + return TRUE; } } } diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp index 68b449749..2420b23f2 100644 --- a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -11,107 +11,57 @@ namespace OpenSHC { namespace AI { - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000This function finds the first active AI - attack tribe for a player (validating it's still alive via UID matching), then traces a path from - that tribe's position toward the player's own defenses, storing the resulting tile coordinates in - the player's game state. It's likely used by the AI to rally or redirect attacking forces — - perhaps pulling them back toward defensive structures when needed, or seeding a waypoint for a - retreat/regroup maneuver. */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CE930 void AICState ::findAttackTribePositionAndPathToDefenses(int playerID) - { + uint local_8 = 0; + uint local_4 = 0; + int* local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; - int iVar1; - - int _tile; - - int iVar2; - - short* psVar3; - - int* local_c; - - uint local_8; - - uint local_4; - - short _y; - - local_8 = 0; - - local_4 = 0; - - local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; - + bool _found = false; do { - - iVar2 = 0; - + int iVar2 = 0; if (0 < *local_c) { - - psVar3 - = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + (*(int (*)[2])(local_c + -1))[0]; - + short* psVar3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + + (*(int (*)[2])(local_c + -1))[0]; do { - - iVar1 = (int)*psVar3; - + int iVar1 = (int)*psVar3; if ((iVar1 != 0) && (DAT_TribesState::instance.tribes[iVar1].uid == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[iVar2 + (*(int (*)[2])(local_c + -1))[0]])) { - + .aiTribeUIDs[iVar2 + (*(int (*)[2])(local_c + -1))[0]])) { iVar2 = (int)DAT_TribesState::instance.tribes[iVar1].selectionTargetUnitID; - local_8 = (uint)DAT_UnitsState::instance.units[iVar2].x; - local_4 = (uint)DAT_UnitsState::instance.units[iVar2].y; - - if (iVar2 != 0) - goto LAB_004ce9f1; - + if (iVar2 != 0) { + _found = true; + break; + } break; } - iVar2 = iVar2 + 1; - psVar3 = psVar3 + 1; - } while (iVar2 < *local_c); } - + if (_found) + break; local_c = local_c + 2; - - if (0xb42a2b < (int)local_c) { - - LAB_004ce9f1: - DAT_GameState::instance.playerDataArray[playerID].someTile = 0; - - if ((local_8 != 0) - && (_tile = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: - tracePathToFriendlyDefensesAndReturnTileUnk, - DAT_PathFindingState::ptr)(playerID, local_8, local_4), - 0 < _tile)) { - - _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; - - DAT_GameState::instance.playerDataArray[playerID].someTile = _tile; - - iVar2 = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; - - DAT_GameState::instance.playerDataArray[playerID].someY = (int)_y; - - DAT_GameState::instance.playerDataArray[playerID].someX = _tile - iVar2; - } - - return; + } while ((int)local_c <= 0xb42a2b); + + DAT_GameState::instance.playerDataArray[playerID].someTile = 0; + + if (local_8 != 0) { + int _tile = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::tracePathToFriendlyDefensesAndReturnTileUnk, + DAT_PathFindingState::ptr)(playerID, local_8, local_4); + if (0 < _tile) { + short _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + DAT_GameState::instance.playerDataArray[playerID].someTile = _tile; + int iVar2 = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + DAT_GameState::instance.playerDataArray[playerID].someY = (int)_y; + DAT_GameState::instance.playerDataArray[playerID].someX = _tile - iVar2; } - - } while (true); + } } - } } diff --git a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp index 0007cf995..24934a4df 100644 --- a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp +++ b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp @@ -23,26 +23,23 @@ namespace AI { break; if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1]) || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1])) { - _index = _index + 1; - break; + _index = _index + 1; break; } if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2]) || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2])) { - _index = _index + 2; - break; + _index = _index + 2; break; } if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3]) || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3])) { - _index = _index + 3; - break; + _index = _index + 3; break; } if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4]) || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4])) { - _index = _index + 4; - break; + _index = _index + 4; break; } _index = _index + 5; } while (_index < 0x14); + int _tribeIndex; if (_index < 1) { _tribeIndex = 0xb4; @@ -54,19 +51,16 @@ namespace AI { _tribeIndex = 0xb7; } else if (_index < 0xf) { _tribeIndex = 0xb8; - } else { - if (19 < _index) { - return 0; - } + } else if (_index < 0x14) { _tribeIndex = 0xb9; + } else { + return 0; } + short* _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeIndex; int _tribeID = (int)*_pTribeID; - if ((_tribeID == 0) - || (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex])) { - _tribeID - = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + if ((_tribeID == 0) || (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex])) { + _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; *_pTribeID = (short)_tribeID; DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex] = _tribeUID; diff --git a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp index 3b82b7d3d..daeffb4e5 100644 --- a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp +++ b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp @@ -7,94 +7,49 @@ namespace OpenSHC { namespace AI { - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CCAF0 int AICState ::getSmallestPatrolTribe(int playerID, int tribeCount) - { - - int _selectedTribeID; - - int _tribeID; - - int _tribeNumber; - - short* _pTribeID; - - int _selectedTribeNumber; - - short _lowestTribeUnitCount; - - short _tribeSize; - - _selectedTribeID = 0; - - _tribeNumber = 0; - - _selectedTribeNumber = 0; - - _lowestTribeUnitCount = 1000; + int _selectedTribeID = 0; + int _tribeNumber = 0; + int _selectedTribeNumber = 0; + short _lowestTribeUnitCount = 1000; if (0 < tribeCount) { - - _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; - + short* _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; do { - - _tribeID = (int)*_pTribeID; - + int _tribeID = (int)*_pTribeID; if ((_tribeID == 0) || (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeNumber + 0xaa])) { - _selectedTribeID = MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - _selectedTribeNumber = _tribeNumber; - - goto LAB_004ccb9d; + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_selectedTribeNumber + 0xaa] + = (short)_selectedTribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_selectedTribeNumber + 0xaa] + = DAT_TribesState::instance.tribes[_selectedTribeID].uid; + return _selectedTribeID; } - - _tribeSize = DAT_TribesState::instance.tribes[_tribeID].size; - + short _tribeSize = DAT_TribesState::instance.tribes[_tribeID].size; if (_tribeSize < _lowestTribeUnitCount) { - _selectedTribeID = _tribeID; - _selectedTribeNumber = _tribeNumber; - _lowestTribeUnitCount = _tribeSize; } - _tribeNumber = _tribeNumber + 1; - _pTribeID = _pTribeID + 1; - } while (_tribeNumber < tribeCount); if (_selectedTribeID != 0) { - - LAB_004ccb9d: - /* - pTribeID = selectedTribeID */ - DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_selectedTribeNumber + 0xaa] = (short)_selectedTribeID; - - /* - pTribeUID = selectedTribeUID */ - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_selectedTribeNumber + 0xaa] = DAT_TribesState::instance.tribes[_selectedTribeID].uid; - return _selectedTribeID; } } - return 0; } - } } diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp index 6c36b0a2e..a46324383 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp @@ -18,88 +18,64 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CD8F0 void AICState ::giveMoveCommandToSortieUnits(int playerID) - { - - int iVar1; - - int _tribeID; - - int _aiType; - - int _unitID; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType == 0) { + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == 0) return; - } - - _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa7]; - if (_tribeID == 0) { + int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa7]; + if (_tribeID == 0) return; - } - if (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa7]) { + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa7]) return; - } if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 + -1) { + < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 + -1) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::syncBehaviourType7UnitTribes, this)(playerID); - } if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { - goto LAB_sendToKeep; + // nervous: send to keep then set stance + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + return; } - /* - SortieUnitMeleeMin */ - if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x154)) - goto LAB_004cda3c; - - _unitID = DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitID; + < *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x154)) { + // tribe too small: just set stance + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + return; + } + int _unitID = DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitID; + int iVar1; if (((_unitID != 0) && (DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitUID == DAT_UnitsState::instance.units[_unitID].uid)) && (iVar1 = MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)(playerID, - (dword)(( - int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance - .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID] - .tile])), + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID].tile])), (dword)((int)((int)(short)DAT_TileMapState::instance .PathConnectionLayer[DAT_UnitsState::instance.units[_unitID].tile])), 0), iVar1 != 0)) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)(_tribeID); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(_tribeID, (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), + DAT_TribesState::ptr)(_tribeID, + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - return; } - LAB_sendToKeep: MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); - - LAB_004cda3c: DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp index 0228ab5f7..eb6658bc8 100644 --- a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp +++ b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp @@ -12,39 +12,29 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CF920 undefined4 AICState ::giveSomeRaidCommand(int tribeIndex, int tribeType) { + int _tribeOffset = tribeIndex * 0x334; + int _attacked = DAT_TribesState::instance.tribes[tribeIndex].owner; + int _targetBuildingID = (int)DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID; - int _chosenBuildingID; - - int _targetBuildingID; - - int _attacked; - - _targetBuildingID = (int)DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID; - - if ((((tribeType != 0xba) && (tribeType != 0x12)) && (tribeType != 0xe)) && (tribeType != 0xd)) { - - if (((_targetBuildingID != 0) - && (DAT_BuildingsState::instance.buildings[_targetBuildingID].uid - == DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID)) - && (DAT_BuildingsState::instance.buildings[_targetBuildingID].fireDuration == 0)) { + if (tribeType != 0xba && tribeType != 0x12 && tribeType != 0xe && tribeType != 0xd) { + if (_targetBuildingID != 0 + && DAT_BuildingsState::instance.buildings[_targetBuildingID].uid + == DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID + && DAT_BuildingsState::instance.buildings[_targetBuildingID].fireDuration == 0) { return (undefined4)(1); } - _attacked = DAT_GameState::instance.playerDataArray[DAT_TribesState::instance.tribes[tribeIndex].owner] - .attackedPlayerID; + int _attackedPlayerID = DAT_GameState::instance.playerDataArray[_attacked].attackedPlayerID; DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = 0; - _chosenBuildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)(_attacked); + int _chosenBuildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)(_attackedPlayerID); if (_chosenBuildingID != 0) { @@ -52,13 +42,14 @@ namespace AI { DAT_UnitsState::ptr)(tribeIndex, 9, (undefined4)((int)(_chosenBuildingID)), (undefined4)((int)(DAT_BuildingsState::instance.buildings[_chosenBuildingID].uid))); + // Store UID before targetBuildingID (matching orig order) DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID = DAT_BuildingsState::instance.buildings[_chosenBuildingID].uid; - DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = (short)_chosenBuildingID; - DAT_TribesState::instance.tribes[tribeIndex].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = (short)_chosenBuildingID; + return (undefined4)(1); } } diff --git a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp index 5862623d0..fe3050b27 100644 --- a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp +++ b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp @@ -8,14 +8,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CFFD0 BOOLEnum AICState::hasNoTroopsOrAllAreDiggers(int playerID) { - int _totalTroops; - int _halfOfDiggingTroops; - - // reversed order to match orig int _totalMisc = DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops; - _halfOfDiggingTroops = 0; + int _halfOfDiggingTroops = 0; + int _totalTroops; + if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState == 6) { _totalMisc += DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops; int _attackTicker = DAT_GameState::instance.playerDataArray[playerID].attackTicker; @@ -48,8 +46,11 @@ namespace AI { + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops; } - if ((1 < _totalTroops) && ((4 < _totalTroops) || (_halfOfDiggingTroops <= _totalTroops + _totalTroops))) { - return FALSE; + + if (1 < _totalTroops) { + if (4 < _totalTroops || _halfOfDiggingTroops <= _totalTroops + _totalTroops) { + return FALSE; + } } return TRUE; } diff --git a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp index 8a56546ea..28dffd267 100644 --- a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp +++ b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp @@ -10,20 +10,24 @@ namespace AI { BOOLEnum AICState::hasNotEnoughSupplies(int playerID) { BOOLEnum BVar1 = TRUE; - if (((((DAT_GameState::instance.playerDataArray[playerID].marketplace.id != 0) - || (DAT_BuildingsState::instance.buildingCosts[0x1a].requiredWood - <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) - || (0 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)) - && (((DAT_GameState::instance.playerDataArray[playerID].granary.id != 0 - || (DAT_BuildingsState::instance.buildingCosts[0x13].requiredWood - <= DAT_GameState::instance.playerDataArray[playerID].currentResources[2])) - || (1 < DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount)))) - && (((0 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] - || (25 < DAT_GameState::instance.playerDataArray[playerID].popularity)) - || (0 < DAT_GameState::instance.playerDataArray[playerID].totalFood)))) { - BVar1 = FALSE; + if (DAT_GameState::instance.playerDataArray[playerID].marketplace.id == 0 + && DAT_GameState::instance.playerDataArray[playerID].currentResources[2] + < DAT_BuildingsState::instance.buildingCosts[0x1a].requiredWood + && DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 1) { + return BVar1; } - return BVar1; + if (DAT_GameState::instance.playerDataArray[playerID].granary.id == 0 + && DAT_GameState::instance.playerDataArray[playerID].currentResources[2] + < DAT_BuildingsState::instance.buildingCosts[0x13].requiredWood + && DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount <= 1) { + return BVar1; + } + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] <= 0 + && DAT_GameState::instance.playerDataArray[playerID].popularity <= 25 + && DAT_GameState::instance.playerDataArray[playerID].totalFood <= 0) { + return BVar1; + } + return FALSE; } } } diff --git a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp index 414d34b99..620439b22 100644 --- a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp +++ b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp @@ -19,98 +19,59 @@ namespace AI { using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CD7B0 void AICState ::instructTribe166ToMove(int playerID) - { - - BOOLEnum _keepEnclosed; - - int _tribeID; - - int _counter; - - AITypeInt _aiType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType == OpenSHC::AI::AIT_NULL) { - + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == OpenSHC::AI::AIT_NULL) return; - } - - _counter = DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01; - - if (0 < _counter) { + int _counter = DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01; + if (0 < _counter) DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 = _counter + -1; - } - - if (50 < DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01) { - + if (50 < DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01) DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 = 50; - } - _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; - - _keepEnclosed = MACRO_CALL_MEMBER( + int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; + BOOLEnum _keepEnclosed = MACRO_CALL_MEMBER( OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); - if (_tribeID == 0) { - + if (_tribeID == 0) return; - } - if (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa6]) { - + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa6]) return; - } if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 + -5) { - + < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 + -5) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitsToTribe166, this)(playerID); - } if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) || (_keepEnclosed != FALSE)) { - /* - SortieUnitRangedMin */ - if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x14c)) - goto LAB_004cd86b; + < *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x14c)) { + // tribe too small: just set stance + DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + return; + } if ((0 < DAT_GameState::instance.playerDataArray[playerID].someXPosition) && (0 < DAT_GameState::instance.playerDataArray[playerID].someYPosition)) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)(_tribeID); - - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(_tribeID, (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someXPosition)), (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someYPosition)), 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - return; } } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); - - LAB_004cd86b: DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp index 7eaedffbb..a6a3f9d47 100644 --- a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp @@ -16,79 +16,51 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CEEA0 BOOLEnum AICState ::processAttForceRallyPercentage(int playerID) { + AITypeInt AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - AITypeInt AVar1; - - int iVar2; - - int iVar3; - - int _tribeID; - - short* psVar4; - - int iVar5; - - int _tribeTotal; - - int _notReallyMoving; - - int* local_c; - - AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) { - + if (AVar1 == OpenSHC::AI::AIT_NULL) return FALSE; - } - - _tribeTotal = 0; - _notReallyMoving = 0; + AITypeInt _aiTypeMinus1 = AVar1 - 1; + int _tribeTotal = 0; + int _notReallyMoving = 0; - local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + int* local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; do { + int iVar2 = (*(int (*)[2])(local_c + -1))[0]; + int iVar3 = *local_c; - iVar2 = (*(int (*)[2])(local_c + -1))[0]; - - iVar3 = *local_c; - - if ((((iVar2 != 0x12) && (iVar2 != 0xbe)) && (iVar2 != 0xf)) && (iVar5 = 0, 0 < iVar3)) { - - psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar2; + if (iVar2 != 0x12 && iVar2 != 0xbe && iVar2 != 0xf) { + int iVar5 = 0; + if (0 < iVar3) { + short* psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar2; - do { + do { + int _tribeID = (int)*psVar4; - _tribeID = (int)*psVar4; + if (_tribeID != 0 + && DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar5 + iVar2]) { - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar5 + iVar2])) { + _tribeTotal = _tribeTotal + 1; - _tribeTotal = _tribeTotal + 1; + if (DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0x14) + _notReallyMoving = _notReallyMoving + 1; - if (DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0x14) { - - _notReallyMoving = _notReallyMoving + 1; + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; } - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; - } - - iVar5 = iVar5 + 1; - - psVar4 = psVar4 + 1; + iVar5 = iVar5 + 1; + psVar4 = psVar4 + 1; - } while (iVar5 < iVar3); + } while (iVar5 < iVar3); + } } local_c = local_c + 2; @@ -96,12 +68,8 @@ namespace AI { } while ((int)local_c < 0xb42a2c); if (0 < _tribeTotal) { - - /* - AttForceRallyPercentage */ - - return (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x200) - <= (_notReallyMoving * 100) / _tribeTotal); + return (BOOLEnum)((_notReallyMoving * 100) / _tribeTotal + >= *(int*)((int)this + _aiTypeMinus1 * 0x2a4 + 0x200)); } return FALSE; diff --git a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp index b9af53ac5..be79bfac5 100644 --- a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp +++ b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp @@ -21,234 +21,127 @@ namespace AI { using OpenSHC::AI::AIC::AITargetChoiceInt; using OpenSHC::Game::Player::PlayerData; - /* - 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 0x004D4680 void AICState ::selectAttackTarget(int playerID) - { - - int fromXPosition; - - int fromYPosition; - - int iVar1; - - int _alive1; - - int _isLordAlive; - - int _lord; - - int _selectedPlayer; - - PlayerData* _pPlayerData2; - - int _iPlayer2; - - int _iPlayer; - - PlayerData* _ptrPlayerData; - - int _lowestDistance; - - int _highestGold; - - int _lowestPoints; - - int _currentGoldValue; - - int _points; - - int _reqState; - - int _reqState2; - - AITypeInt _aiType; - - AITargetChoiceInt _targetChoiceType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - _selectedPlayer = 0; + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + int _selectedPlayer = 0; if (_aiType != OpenSHC::AI::AIT_NULL) { - - fromXPosition = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; - - fromYPosition = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; - - _lowestDistance = 10000; - - _highestGold = 0; - - _lowestPoints = 1000000; + int fromXPosition = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; + int fromYPosition = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; + int _lowestDistance = 10000; + int _highestGold = 0; + int _lowestPoints = 1000000; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeNervousness, this)(playerID); - _reqState = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; - + int _reqState = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; if (((_reqState == 2) || (_reqState == 1)) - && (iVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), - iVar1 == 0)) { - + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) == 0) { DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; } - _reqState2 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; - + int _reqState2 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; if (_reqState2 == 2) { - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = 0; - return; } - if (_reqState2 == 1) { - - _alive1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk); - - if (_alive1 != 0) { - + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk) != 0) { DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk; - return; } - DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; } - _pPlayerData2 = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); - - _iPlayer = 1; + PlayerData* _pPlayerData2 = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); + int _iPlayer = 1; do { - if ((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) - && (_isLordAlive = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_iPlayer), - _isLordAlive != 0)) { - - /* - fixme:improve: use pythagoras */ + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_iPlayer) != 0) { MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, DAT_DirectionAlgorithmState::ptr)((_pPlayerData2->campground).xEntry, (_pPlayerData2->campground).yEntry, fromXPosition, fromYPosition); - _targetChoiceType = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].TargetChoice; - - _currentGoldValue = _highestGold; - - _points = _lowestPoints; + AITargetChoiceInt _targetChoiceType = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].TargetChoice; + int _currentGoldValue = _highestGold; + int _points = _lowestPoints; if (_targetChoiceType == OpenSHC::AI::AIC::AITC_PLAYER) { - if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_iPlayer] != -1) { - - LAB_004d47c5: if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance) { - _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; - - LAB_004d4845: _lowestPoints = _points; - _highestGold = _currentGoldValue; - _selectedPlayer = _iPlayer; } } - - } - - else { - - if (_targetChoiceType == OpenSHC::AI::AIC::AITC_CLOSEST) - goto LAB_004d47c5; - - if (_targetChoiceType == OpenSHC::AI::AIC::AITC_GOLD) { - - _currentGoldValue = _pPlayerData2->currentResources[0xf]; - - if (_highestGold <= _pPlayerData2->currentResources[0xf]) - goto LAB_004d4845; - + } else if (_targetChoiceType == OpenSHC::AI::AIC::AITC_CLOSEST) { + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance) { + _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + _lowestPoints = _points; + _highestGold = _currentGoldValue; + _selectedPlayer = _iPlayer; + } + } else if (_targetChoiceType == OpenSHC::AI::AIC::AITC_GOLD) { + _currentGoldValue = _pPlayerData2->currentResources[0xf]; + if (_highestGold <= _pPlayerData2->currentResources[0xf]) { + _lowestPoints = _points; + _highestGold = _currentGoldValue; + _selectedPlayer = _iPlayer; + } + } else if (_targetChoiceType == OpenSHC::AI::AIC::AITC_BALANCED) { + _points = _pPlayerData2->currentPopulation * 5 + _pPlayerData2->totalTroopValue + + _pPlayerData2->currentResources[0xf] / 100 + + DAT_DirectionAlgorithmState::instance.distanceHigh * 2; + if (_points <= _lowestPoints) { + _lowestPoints = _points; + _highestGold = _currentGoldValue; + _selectedPlayer = _iPlayer; } - - else if ((_targetChoiceType == OpenSHC::AI::AIC::AITC_BALANCED) - && (_points = _pPlayerData2->currentPopulation * 5 + _pPlayerData2->totalTroopValue - + _pPlayerData2->currentResources[0xf] / 100 - + DAT_DirectionAlgorithmState::instance.distanceHigh * 2, - _points <= _lowestPoints)) - goto LAB_004d4845; } } _iPlayer = _iPlayer + 1; - - _pPlayerData2 = _pPlayerData2 + 0x39f4; - + _pPlayerData2 = _pPlayerData2 + 0xe7d; } while (_iPlayer < 9); if (_selectedPlayer == 0) { - - _iPlayer2 = 1; - - _ptrPlayerData = &DAT_GameState::instance.playerDataArray[1]; - + int _iPlayer2 = 1; + PlayerData* _ptrPlayerData = &DAT_GameState::instance.playerDataArray[1]; do { - if (((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer2] != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) - && (_lord = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_iPlayer2), - _lord != 0)) + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_iPlayer2) != 0) && (MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, (_ptrPlayerData->campground).yEntry, fromXPosition, fromYPosition), DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance)) { - _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; - _selectedPlayer = _iPlayer2; } - _iPlayer2 = _iPlayer2 + 1; - - /* - next player */ - _ptrPlayerData = _ptrPlayerData + 0xe7d; - } while (_iPlayer2 < 9); - if (_selectedPlayer == 0) { - + if (_selectedPlayer == 0) return; - } } DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk = _selectedPlayer; - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = _selectedPlayer; } - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp index 412497ce2..f4283f86e 100644 --- a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -21,46 +21,21 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D1D60 void AICState ::sellExcessGoods(int param_1) - { - - AITypeInt AVar1; - - ResourceType resourceType; - - AIResourceTradeCategoryInt AVar2; - - int iVar3; - - uint uVar4; - - int iVar5; - - int iVar6; - - ResourceType* pRVar7; - - AIResourceTradeCategoryInt* local_18; - - AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) { + AITypeInt AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; + if (AVar1 == OpenSHC::AI::AIT_NULL) return; - } - iVar3 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - - local_18 = &DAT_SkirmishDefinedData::instance.DAT_AIResourceTradeAICMapping[0].aic; + int iVar3 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; + AIResourceTradeCategoryInt* local_18 = &DAT_SkirmishDefinedData::instance.DAT_AIResourceTradeAICMapping[0].aic; do { - - resourceType + ResourceType resourceType = (OpenSHC::Game::Resources::ResourceType)((ResourceAICResourceMappingEntry*)(local_18 + -1))->game; + AIResourceTradeCategoryInt AVar2 = *local_18; - AVar2 = *local_18; - - iVar6 = *(int*)((int)this + iVar3 + 0xc0); - + int iVar6 = *(int*)((int)this + iVar3 + 0xc0); + int iVar5; if (AVar2 == OpenSHC::AI::Trading::AIRTC_WOOD) { iVar5 = *(int*)((int)this + iVar3 + 0xac); } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { @@ -75,73 +50,62 @@ namespace AI { iVar5 = *(int*)((int)this + iVar3 + 0xb4); } - uVar4 = iVar5 + iVar6; + uint uVar4 = iVar5 + iVar6; if ((DAT_GameState::instance.playerDataArray[param_1].aiNervousActionsTracker <= 0) || (DAT_GameState::instance.playerDataArray[param_1].currentResources[0xf] >= 0x1f4)) { if (DAT_GameState::instance.playerDataArray[param_1].popularity < *(int*)((int)this + iVar3 + 0x18)) { - if (AVar2 != OpenSHC::AI::Trading::AIRTC_FOOD) { - if (AVar2 == OpenSHC::AI::Trading::AIRTC_WEAPONS) { uVar4 = 0; iVar6 = 0; - goto LAB_004d1e81; + } else { + uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; + iVar6 = 0; } - - uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; + } else { + iVar6 = 0; } - - iVar6 = 0; - } else { uVar4 = uVar4 + DAT_GameState::instance.playerDataArray[param_1].resourcesToAcquireArray[resourceType]; } } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { - uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; iVar6 = 0; - } else { - uVar4 = (AVar2 != OpenSHC::AI::Trading::AIRTC_WEAPONS) - 1 & 10000; iVar6 = 0; } - LAB_004d1e81: - iVar5 = 0; - - pRVar7 = (ResourceType*)((int)this + iVar3 + 0xd4); - - do { - if (resourceType == *pRVar7) { - uVar4 = 0; - iVar6 = 0; - break; - } - iVar5 = iVar5 + 1; - pRVar7 = pRVar7 + 1; - } while (iVar5 < 0xf); + // Check no-sell list (was LAB_004d1e81) + { + int iVar5_2 = 0; + ResourceType* pRVar7 = (ResourceType*)((int)this + iVar3 + 0xd4); + do { + if (resourceType == *pRVar7) { + uVar4 = 0; + iVar6 = 0; + break; + } + iVar5_2 = iVar5_2 + 1; + pRVar7 = pRVar7 + 1; + } while (iVar5_2 < 0xf); + } if ((int)uVar4 < DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType]) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellGoods, this)(param_1, resourceType, (DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType] - uVar4) + iVar6); - return; } local_18 = local_18 + 2; - - if (0xb4252b < (int)local_18) { + if (0xb4252b < (int)local_18) return; - } } while (true); } - } } diff --git a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp index 3cd363930..73e501ba0 100644 --- a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp @@ -13,78 +13,38 @@ namespace AI { using OpenSHC::AI::AIVUnitType; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - [doc] - @param slotIndex int slotIndex to browse to - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D2E00 void AICState ::sendTribeToAIVLocationSlot(int tribeID, AIVUnitType aivUnitType, int slotIndex) - { + int _owner = DAT_TribesState::instance.tribes[tribeID].owner; + int _tile = 0; + int _slotIndex = 0; + int* _ptrSlot = (int*)(_owner * 0x39f4 + 0x115eb14 + aivUnitType * 0x28); - int _slotIndex; - - BOOLEnum _canNavigate; - - int* _ptrSlot; - - int _tile; - - int _x; - - int _owner; - - short _y; - - /* - all experimental, heavy local reuse... */ - - _owner = DAT_TribesState::instance.tribes[tribeID].owner; - - _tile = 0; - - _slotIndex = 0; - - /* - aivUnitLocationSlots */ - - _ptrSlot = (int*)(_owner * 0x39f4 + 0x115eb14 + aivUnitType * 0x28); - - while ((*_ptrSlot == 0 || (slotIndex = slotIndex + -1, -1 < slotIndex))) { - + // Find the slot at slotIndex, skipping empty entries + while (*_ptrSlot == 0 || (slotIndex = slotIndex + -1, -1 < slotIndex)) { _slotIndex = _slotIndex + 1; - _ptrSlot = _ptrSlot + 1; + if (9 < _slotIndex) + break; + } - if (9 < _slotIndex) { - - LAB_004d2e6d: - _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; - - _x = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; - - _canNavigate = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, _tile); - - if (_canNavigate == FALSE) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, _owner); + if (_slotIndex <= 9) + _tile = DAT_GameState::instance.playerDataArray[_owner].aivUnitLocationSlots[aivUnitType][_slotIndex]; - return; - } + short _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + int _x = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( - tribeID, (uint)((int)(_tile - _x)), (uint)((int)((int)_y)), 0); + BOOLEnum _canNavigate = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, _tile); - return; - } + if (_canNavigate == FALSE) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, _owner); + return; } - _tile = DAT_GameState::instance.playerDataArray[_owner].aivUnitLocationSlots[aivUnitType][_slotIndex]; - - goto LAB_004d2e6d; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + tribeID, (uint)((int)(_tile - _x)), (uint)((int)((int)_y)), 0); } - } } diff --git a/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp index 080fa0a94..3c35fb36f 100644 --- a/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp +++ b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp @@ -23,165 +23,121 @@ namespace AI { { - int _lord; + int _aiType = DAT_GameState::instance.playerDataArray[owner].aiType; - int _lordBackup; - - int _minDistance; - - int _distance; - - int _targetPlayer; - - PlayerData* _ptrPlayerData; - - int _playerID_backup; - - int _player; - - PlayerData* _ptrPlayerData_backup; - - int _maxGold; - - int _minPoints; - - int _aiType; - - int _gold; - - int _points; - - int _ownerKeepX; - - int _ownerKeepY; - - AITargetChoiceInt _targetChoice; - - _aiType = DAT_GameState::instance.playerDataArray[owner].aiType; - - _targetPlayer = 0; + int _targetPlayer = 0; if (_aiType != 0) { - _ownerKeepY = DAT_GameState::instance.playerDataArray[owner].campground.yEntry; - - _ownerKeepX = DAT_GameState::instance.playerDataArray[owner].campground.xEntry; - - _minDistance = 10000; - - _maxGold = 0; + int _ownerKeepY = DAT_GameState::instance.playerDataArray[owner].campground.yEntry; + int _ownerKeepX = DAT_GameState::instance.playerDataArray[owner].campground.xEntry; - _minPoints = 1000000; + int _minDistance = 10000; + int _maxGold = 0; + int _minPoints = 1000000; - _player = 1; - - _ptrPlayerData = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); + int _player = 1; + PlayerData* _ptrPlayerData = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); do { if ((DAT_GameState::instance.mapAndTime.playerTeams[_player] - != DAT_GameState::instance.mapAndTime.playerTeams[owner]) - && (_lord = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_player), - _lord != 0)) { - - MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, - DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, - (_ptrPlayerData->campground).yEntry, _ownerKeepX, _ownerKeepY); - - _targetChoice = this->aics[_aiType + -1].TargetChoice; + != DAT_GameState::instance.mapAndTime.playerTeams[owner])) { - _gold = _maxGold; + int _lord = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_player); - _points = _minPoints; + if (_lord != 0) { - if (_targetChoice == OpenSHC::AI::AIC::AITC_PLAYER) { + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, + (_ptrPlayerData->campground).yEntry, _ownerKeepX, _ownerKeepY); - if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_player] != -1) { + AITargetChoiceInt _targetChoice = this->aics[_aiType - 1].TargetChoice; - joined_r0x004cad9a: - _distance = DAT_DirectionAlgorithmState::instance.distanceHigh; + if (_targetChoice == OpenSHC::AI::AIC::AITC_PLAYER) { - if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _minDistance) { + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_player] != -1) { - LAB_004cadf6: - _minPoints = _points; + int _distance = DAT_DirectionAlgorithmState::instance.distanceHigh; + if (_distance <= _minDistance) { + _minDistance = _distance; + _targetPlayer = _player; + } + } - _maxGold = _gold; + } else if (_targetChoice == OpenSHC::AI::AIC::AITC_CLOSEST) { + int _distance = DAT_DirectionAlgorithmState::instance.distanceHigh; + if (_distance <= _minDistance) { _minDistance = _distance; - _targetPlayer = _player; } - } - - } - - else { - - if (_targetChoice == OpenSHC::AI::AIC::AITC_CLOSEST) - goto joined_r0x004cad9a; - _distance = _minDistance; + } else if (_targetChoice == OpenSHC::AI::AIC::AITC_GOLD) { - if (_targetChoice == OpenSHC::AI::AIC::AITC_GOLD) { - - _gold = _ptrPlayerData->currentResources[0xf]; + int _gold = _ptrPlayerData->currentResources[0xf]; + if (_maxGold <= _gold) { + _minDistance = _minDistance; + _maxGold = _gold; + _minPoints = _minPoints; + _targetPlayer = _player; + } - if (_maxGold <= _ptrPlayerData->currentResources[0xf]) - goto LAB_004cadf6; + } else if (_targetChoice == OpenSHC::AI::AIC::AITC_BALANCED) { + int _points = _ptrPlayerData->currentPopulation * 5 + + _ptrPlayerData->totalTroopValue + + _ptrPlayerData->currentResources[0xf] / 100 + + DAT_DirectionAlgorithmState::instance.distanceHigh * 2; + if (_points <= _minPoints) { + _minDistance = _minDistance; + _maxGold = _maxGold; + _minPoints = _points; + _targetPlayer = _player; + } } - - else if ((_targetChoice == OpenSHC::AI::AIC::AITC_BALANCED) - && (_points = _ptrPlayerData->currentPopulation * 5 + _ptrPlayerData->totalTroopValue - + _ptrPlayerData->currentResources[0xf] / 100 - + DAT_DirectionAlgorithmState::instance.distanceHigh * 2, - _points <= _minPoints)) - goto LAB_004cadf6; } } _player = _player + 1; - _ptrPlayerData = _ptrPlayerData + 1; } while (_player < 9); if (_targetPlayer == 0) { - _playerID_backup = 1; - - _ptrPlayerData_backup = &DAT_GameState::instance.playerDataArray[1]; + int _playerID_backup = 1; + PlayerData* _ptrPlayerData_backup = &DAT_GameState::instance.playerDataArray[1]; do { - if (((DAT_GameState::instance.mapAndTime.playerTeams[_playerID_backup] - != DAT_GameState::instance.mapAndTime.playerTeams[owner]) - && (_lordBackup - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_playerID_backup), - _lordBackup != 0)) - && (MACRO_CALL_MEMBER( + if ((DAT_GameState::instance.mapAndTime.playerTeams[_playerID_backup] + != DAT_GameState::instance.mapAndTime.playerTeams[owner])) { + + int _lordBackup = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + DAT_UnitsState::ptr)(_playerID_backup); + + if (_lordBackup != 0) { + + MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData_backup->campground).xEntry, - (_ptrPlayerData_backup->campground).yEntry, _ownerKeepX, _ownerKeepY), - DAT_DirectionAlgorithmState::instance.distanceHigh <= _minDistance)) { + (_ptrPlayerData_backup->campground).yEntry, _ownerKeepX, _ownerKeepY); - _minDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; - - _targetPlayer = _playerID_backup; + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _minDistance) { + _minDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + _targetPlayer = _playerID_backup; + } + } } _playerID_backup = _playerID_backup + 1; - _ptrPlayerData_backup = _ptrPlayerData_backup + 1; } while (_playerID_backup < 9); if (_targetPlayer == 0) { - return; } } diff --git a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp index f7b90a16b..2ce935755 100644 --- a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp +++ b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp @@ -22,130 +22,74 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CBE30 void AICState ::setupWorkshopProductionType(int playerID, int buildingID) - { + AITypeInt AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - AITypeInt AVar1; - - int _aiTypeMin1; - - ResourceTypeShort RVar2; - - BuildingTypeShort _buildingType; - - AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) { + if (AVar1 == OpenSHC::AI::AIT_NULL) return; - } - _buildingType = DAT_BuildingsState::instance.buildings[buildingID].buildingType; - - _aiTypeMin1 = AVar1 + ~OpenSHC::AI::AIT_NULL; - RVar2 = OpenSHC::Game::Resources::RT_SWORD; + BuildingTypeShort _buildingType = DAT_BuildingsState::instance.buildings[buildingID].buildingType; + int _aiTypeMin1 = AVar1 + ~OpenSHC::AI::AIT_NULL; if (_buildingType == OpenSHC::Map::Buildings::BT_BLACKSMITH) { - _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 200); - if (_aiTypeMin1 == -999) { - _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, OpenSHC::Map::Buildings::BT_BLACKSMITH); - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = (ResourceTypeShort)_aiTypeMin1; - + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)_aiTypeMin1; return; } - - RVar2 = OpenSHC::Game::Resources::RT_SWORD; - - if (_aiTypeMin1 == 0x16) - goto LAB_004cbf6a; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_MACE; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = OpenSHC::Game::Resources::RT_MACE; - + if (_aiTypeMin1 == 0x16) { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_SWORD; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_SWORD; + } else { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_MACE; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_MACE; + } return; } - // orig: cmp dx, 0xe; jne 0x5a (skip poleturner block to fletcher/end) - // poleturner falls through, fletcher and end are jumped to if (_buildingType == OpenSHC::Map::Buildings::BT_POLETURNER) { - _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 0xd0); - if (_aiTypeMin1 == -999) { - _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, OpenSHC::Map::Buildings::BT_POLETURNER); - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = (ResourceTypeShort)_aiTypeMin1; - + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)_aiTypeMin1; return; } - - RVar2 = OpenSHC::Game::Resources::RT_SPEAR; - - if (_aiTypeMin1 == 0x13) - goto LAB_004cbf6a; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_PIKE; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_PIKE; - + if (_aiTypeMin1 == 0x13) { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_SPEAR; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_SPEAR; + } else { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_PIKE; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_PIKE; + } return; } if (_buildingType == OpenSHC::Map::Buildings::BT_FLETCHER) { - _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 0xcc); - if (_aiTypeMin1 == -999) { - - _aiTypeMin1 - = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, - DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, - OpenSHC::Map::Buildings::BT_FLETCHER); - - DAT_BuildingsState::instance.buildings[buildingID].producedItemType - = (ResourceTypeShort)_aiTypeMin1; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = (ResourceTypeShort)_aiTypeMin1; - + _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, + DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, + OpenSHC::Map::Buildings::BT_FLETCHER); + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)_aiTypeMin1; return; } - - RVar2 = OpenSHC::Game::Resources::RT_BOW; - - if (_aiTypeMin1 == 0x11) - goto LAB_004cbf6a; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemType - = OpenSHC::Game::Resources::RT_CROSSBOW; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = OpenSHC::Game::Resources::RT_CROSSBOW; + if (_aiTypeMin1 == 0x11) { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_BOW; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_BOW; + } else { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_CROSSBOW; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_CROSSBOW; + } } - return; - - LAB_004cbf6a: - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = RVar2; - - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = RVar2; - return; } } diff --git a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp index d374436ea..c0e9f4f2a 100644 --- a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp +++ b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp @@ -15,27 +15,25 @@ namespace AI { BOOLEnum AICState::shouldDestroyWoodCutterUnk(int playerID) { int _hut; - if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) return FALSE; - } - if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable < 1) { + + if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0) { _hut = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT); } else { - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] < 0x15) { + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] <= 0x14) return FALSE; - } - if (DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 2) { + if (DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 2) return FALSE; - } - if (DAT_GameState::instance.playerDataArray[playerID].someCount10 < 25) { + if (DAT_GameState::instance.playerDataArray[playerID].someCount10 < 25) return FALSE; - } _hut = DAT_GameState::instance.playerDataArray[playerID].someCount11; } - if (_hut == 0) { + + if (_hut == 0) return FALSE; - } + MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( (int)(short)DAT_BuildingsState::instance.buildings[_hut].x, (int)(short)DAT_BuildingsState::instance.buildings[_hut].y); diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp index 43483ef0a..4ba346293 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp @@ -9,18 +9,28 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB5B0 BOOLEnum AICState::shouldNotBeBuildingHovel(PlayerID playerID, Commands::CommandBuildingType param_2) { - if (param_2 == Commands::CBT_HOVEL) { - int const populationCap = DAT_GameState::instance.playerDataArray[playerID].populationCap; - if (12 < populationCap) { - if (((populationCap <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation) - && (DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants < 5)) - && (DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk < 5)) { - return DAT_GameState::instance.playerDataArray[playerID].popularity < 5000; - } - return TRUE; - } + if (param_2 != Commands::CBT_HOVEL) { + return FALSE; } - return FALSE; + + int const populationCap = DAT_GameState::instance.playerDataArray[playerID].populationCap; + if (populationCap <= 12) { + return FALSE; + } + + if (populationCap <= DAT_GameState::instance.playerDataArray[playerID].currentPopulation) { + return TRUE; + } + + if (DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants >= 5) { + return TRUE; + } + + if (DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk >= 5) { + return TRUE; + } + + return DAT_GameState::instance.playerDataArray[playerID].popularity < 5000; } } } diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp index 52613f2ef..544c8e381 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp @@ -10,15 +10,20 @@ namespace AI { BOOLEnum AICState::shouldNotBuildMarketArmoryGranaryBarracksMercenarypost( int playerID, Commands::CommandBuildingType param_2) { - if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) { - if ((0 < DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker) - && (param_2 != Commands::CBT_MARKETPLACE)) { + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { + // nervous: reject market/mercenarypost/barracks/armory types + if (param_2 != Commands::CBT_MARKETPLACE + && param_2 != Commands::CBT_MERCENARYPOST + && param_2 != Commands::CBT_BARRACKS + && param_2 != Commands::CBT_ARMORY) { + return param_2 != Commands::CBT_GRANARY; + } + } else { + // not nervous: only reject if destroy tracker > 0 and not marketplace + if (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker > 0 + && param_2 != Commands::CBT_MARKETPLACE) { return param_2 != Commands::CBT_GRANARY; } - } else if ((((param_2 != Commands::CBT_MARKETPLACE) && (param_2 != Commands::CBT_MERCENARYPOST)) - && (param_2 != Commands::CBT_BARRACKS)) - && (param_2 != Commands::CBT_ARMORY)) { - return param_2 != Commands::CBT_GRANARY; } return FALSE; } diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp index e4b8ffcd5..086bf9485 100644 --- a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -35,7 +35,10 @@ namespace AI { != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7])) { _tribeID = MACRO_CALL_MEMBER( Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - goto LAB_004ccaae; + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[iVar3 + iVar7] = (short)_tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] + = DAT_TribesState::instance.tribes[_tribeID].uid; + return _tribeID; } short sVar1 = DAT_TribesState::instance.tribes[iVar5].size; if (sVar1 < sVar4) { @@ -48,7 +51,6 @@ namespace AI { } while (iVar7 < iVar6); iVar7 = local_c; if (_tribeID != 0) { - LAB_004ccaae: DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[iVar3 + iVar7] = (short)_tribeID; DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] = DAT_TribesState::instance.tribes[_tribeID].uid; diff --git a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp index 258a3215f..eda86856b 100644 --- a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp +++ b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp @@ -9,25 +9,17 @@ namespace AI { using OpenSHC::Game::Skirmish::SkirmishDefinedData; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CC8D0 undefined4 AICState ::unitIDIsRangedOrArmored(int unitID) { + int _unitType = (int)(short)DAT_UnitsState::instance.units[unitID].unitType; - SkirmishDefinedData* pSVar1; - - pSVar1 = DAT_SkirmishDefinedData::ptr; + SkirmishDefinedData* pSVar1 = DAT_SkirmishDefinedData::ptr; do { - - if (pSVar1->DAT_UnitTypes_RangedAndArmored[0] - == (int)(short)DAT_UnitsState::instance.units[unitID].unitType) { - + if (pSVar1->DAT_UnitTypes_RangedAndArmored[0] == _unitType) return (undefined4)(1); - } pSVar1 = (SkirmishDefinedData*)(pSVar1->DAT_UnitTypes_RangedAndArmored + 1); diff --git a/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp index 6946450dd..094883871 100644 --- a/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp +++ b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp @@ -16,149 +16,89 @@ namespace AI { using OpenSHC::AI::AITypeInt; using OpenSHC::Game::Player::PlayerData; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D53E0 - void AICState ::updateAIBehaviour() - + void AICState::updateAIBehaviour() { - - AITypeInt AVar1; - - PlayerData* _aiType; - - int _playerID; - if (DAT_GameState::instance.mapAndTime.dayTicks == 10) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeOutpostTribesAttack, this)(); } - _aiType = &DAT_GameState::instance.playerDataArray[1]; - - _playerID = 1; - - do { - - AVar1 = _aiType->aiType; - - if (((AVar1 != OpenSHC::AI::AIT_NULL) && (_aiType->playerDeathRelated == 0)) - && (_aiType->lordKilledByPlayerID == 0)) { - - if (DAT_GameState::instance.mapAndTime.dayTicks == _playerID) { - - if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieRangedUnits, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieMeleeUnits, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitUnits, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recruitHarrassingSiegeEngines, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignMoatDiggers, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCreateSiegeUnits, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineers, this)(_playerID); - } - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiBuyAndSellGoods, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiGiveRaidInstructions, this)(_playerID); + for (int _playerID = 1; _playerID < 9; _playerID++) { + // Compiler doesn't optimize it with ADJ() like it should, not sure why it doesn't do it. + PlayerData* const _pPlayerData = &DAT_GameState::instance.playerDataArray[_playerID]; + AITypeInt const _aiType = _pPlayerData->aiType; + + if (_aiType == OpenSHC::AI::AIT_NULL) + continue; + if (_pPlayerData->playerDeathRelated != 0) + continue; + if (_pPlayerData->lordKilledByPlayerID != 0) + continue; + + if (DAT_GameState::instance.mapAndTime.dayTicks == _playerID) { + if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieRangedUnits, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieMeleeUnits, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitUnits, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recruitHarrassingSiegeEngines, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignMoatDiggers, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCreateSiegeUnits, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineers, this)(_playerID); } + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiBuyAndSellGoods, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiGiveRaidInstructions, this)(_playerID); + } - if (DAT_GameState::instance.mapAndTime.weekTicks == _playerID) { - - if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineerForOilDuty, this)(_playerID); - } - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateTribeLocations, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIPlayerState, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiUpdateTaxesAndRations, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setFoodBuyPlan, this)(_playerID); - - if (DAT_GameState::instance.mapAndTime.monthTicks != _playerID) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 0); - } - - if (_aiType->aiRequestDelay != 0) { - - _aiType->aiRequestDelay = _aiType->aiRequestDelay + -1; - } - - if (_aiType->nervousBikCountdown != 0) { - - _aiType->nervousBikCountdown = _aiType->nervousBikCountdown + -1; - } - - if (_aiType->someAiCountdown3 != 0) { - - _aiType->someAiCountdown3 = _aiType->someAiCountdown3 + -1; - } - - if (_aiType->someAiCountdown4 != 0) { - - _aiType->someAiCountdown4 = _aiType->someAiCountdown4 + -1; - } - - if (_aiType->someAiCountdown5 != 0) { - - _aiType->someAiCountdown5 = _aiType->someAiCountdown5 + -1; - } - - if (_aiType->someAiCountdown6 != 0) { - - _aiType->someAiCountdown6 = _aiType->someAiCountdown6 + -1; - } + if (DAT_GameState::instance.mapAndTime.weekTicks == _playerID) { + if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineerForOilDuty, this)(_playerID); } + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateTribeLocations, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIPlayerState, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiUpdateTaxesAndRations, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setFoodBuyPlan, this)(_playerID); - if (DAT_GameState::instance.mapAndTime.monthTicks == _playerID) { - - MACRO_CALL_MEMBER( - OpenSHC::Map::TileMapState_Func::countMoatsOwnedByEachPlayer, DAT_TileMapState::ptr)(); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::instructTribe166ToMove, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToSortieUnits, this)(_playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 1); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectAttackTarget, this)(_playerID); - - if (_aiType->aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_RAIDING) { - - _aiType->canStartSpending = 1; - - } - - else { - - /* - shouldSpend = recruitGoldTreshold < currentGold */ + if (DAT_GameState::instance.mapAndTime.monthTicks != _playerID) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 0); + } - _aiType->canStartSpending - = (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0xc4) - < _aiType->currentResources[0xf]); - } + if (_pPlayerData->aiRequestDelay != 0) { + _pPlayerData->aiRequestDelay -= 1; + } + if (_pPlayerData->nervousBikCountdown != 0) { + _pPlayerData->nervousBikCountdown -= 1; + } + if (_pPlayerData->someAiCountdown3 != 0) { + _pPlayerData->someAiCountdown3 -= 1; + } + if (_pPlayerData->someAiCountdown4 != 0) { + _pPlayerData->someAiCountdown4 -= 1; + } + if (_pPlayerData->someAiCountdown5 != 0) { + _pPlayerData->someAiCountdown5 -= 1; + } + if (_pPlayerData->someAiCountdown6 != 0) { + _pPlayerData->someAiCountdown6 -= 1; } } - _aiType = _aiType + 0xe7d; - - _playerID = _playerID + 1; - - } while ((int)_aiType < 0x117ea8c); - - return; + if (DAT_GameState::instance.mapAndTime.monthTicks == _playerID) { + MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::countMoatsOwnedByEachPlayer, DAT_TileMapState::ptr)(); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::instructTribe166ToMove, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToSortieUnits, this)(_playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 1); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectAttackTarget, this)(_playerID); + + if (_pPlayerData->aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_RAIDING) { + _pPlayerData->canStartSpending = 1; + } else { + // shouldSpend = recruitGoldThreshold < currentGold + _pPlayerData->canStartSpending = (uint)(((int)this->aics[_aiType - 1].recruitGoldThreshold) + < _pPlayerData->currentResources[0xf]); + } + } + } } } diff --git a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp index b864cfc3e..88a716c36 100644 --- a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp @@ -19,549 +19,285 @@ namespace AI { using OpenSHC::AI::AITypeInt; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + // Helper shared by state 4 (canNavigate==FALSE) and state 6 (canUnitsNavigate==FALSE) + static void recomputeAndReset(OpenSHC::AI::AICState* pThis, int playerID) + { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, pThis)(playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, pThis)(playerID); + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; + } // FUNCTION: STRONGHOLDCRUSADER 0x004D49E0 void AICState ::updateAIPlayerState(int playerID) - { - - short* psVar1; - - int* piVar2; - - short sVar3; - - AITypeInt AVar4; - - int _aiType; - - int iVar5; - - BOOLEnum _shouldAttack; - - int _attackedPlayerAlive; - - uint _rallyReady; - - BOOLEnum BVar6; - - int _aiPlayerState_2; - - int _aiPlayerState; - - int _playerID; - - AVar4 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar4 == OpenSHC::AI::AIT_NULL) { - + AITypeInt AVar4 = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (AVar4 == OpenSHC::AI::AIT_NULL) return; - } - _aiType = AVar4 + ~OpenSHC::AI::AIT_NULL; - - iVar5 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; + int _aiType = AVar4 + ~OpenSHC::AI::AIT_NULL; + int iVar5 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; if (((iVar5 != 1) && (iVar5 == 2)) && (iVar5 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), iVar5 != 0)) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToPlayerIDsKeepIfPossible, this)( playerID, (short*)((int)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk))); - return; } - _aiPlayerState = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; + int _aiPlayerState = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; if (_aiPlayerState == 0) { - - _shouldAttack = MACRO_CALL_MEMBER( + BOOLEnum _shouldAttack = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::aiShouldAttackOrWaitForTeamCoordination, this)(playerID); - if (_shouldAttack == FALSE) { - - /* - Send own units back to keep or campfire */ - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRetreatUnits, this)((short*)playerID); - return; } - - /* - proceedwithattack */ - DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 1; - DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue = 0; - DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience = 0; - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackCoordinationLevel, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackStrength, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackRaidParameter, this)(playerID); - - piVar2 = (int*)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID * 0x39f4 + 0x115e9d4 - + playerID * 0x20); - + int* piVar2 = (int*)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID * 0x39f4 + + 0x115e9d4 + playerID * 0x20); *piVar2 = *piVar2 + 1; - - } - - else { - - BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID); - + } else { + BOOLEnum BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID); if ((((BVar6 != FALSE) && (_aiPlayerState != 9)) || ((0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker && (_aiPlayerState < 6)))) - || (199 < DAT_GameState::instance.playerDataArray[playerID].attackTicker)) { - + || (199 < DAT_GameState::instance.playerDataArray[playerID].attackTicker)) DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 8; - } } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); - _attackedPlayerAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + int _attackedPlayerAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); if (_attackedPlayerAlive == 0) { - - /* - attacked player is dead */ - iVar5 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; - if (iVar5 < 4) { - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - - MACRO_CALL_MEMBER( - OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)( DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( - playerID); - - } - - else if (iVar5 < 7) { - + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)(playerID); + } else if (iVar5 < 7) { DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 7; } } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearOutdatedAITribes, this)(playerID); - _aiPlayerState_2 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; - - if (_aiPlayerState_2 != 1) { - - if (_aiPlayerState_2 == 2) { - - /* - the general state means to be attacking */ - - _rallyReady - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID); - - if (_rallyReady == 0) { - - return; - } - - /* - send the attacking units to move closer */ - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 3; - - MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setNextMoveLocationForUnits, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToAttackTribes, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0xe_toPlaceTunnels, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)( - playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playTauntToAttackedPlayerBikFromPlayer, this)(playerID); + int _aiPlayerState_2 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; + BOOLEnum BVar6; + int* piVar2; + if (_aiPlayerState_2 == 1) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recreateEngineersTribe, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::initializeGatePathfindingForOwner, + DAT_BuildingsState::ptr)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeEnemyKeepApproachTile, this)(playerID); + if (0 < DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackTribesToLocations, this)((short*)playerID); return; } + // state 1 with no path: reset to 0 + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + return; + } - if (_aiPlayerState_2 == 3) { - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - - /* - send the attacking units closer to the castle */ - - *piVar2 = *piVar2 + 1; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); - - BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::processAttForceRallyPercentage, this)(playerID); - - if (BVar6 == FALSE) { - - return; - } - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 4; + if (_aiPlayerState_2 == 2) { + uint _rallyReady = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID); + if (_rallyReady == 0) + return; + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 3; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers, + this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setNextMoveLocationForUnits, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveMoveCommandToAttackTribes, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0xe_toPlaceTunnels, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playTauntToAttackedPlayerBikFromPlayer, this)(playerID); + return; + } - DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 0; + if (_aiPlayerState_2 == 3) { + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + *piVar2 = *piVar2 + 1; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::processAttForceRallyPercentage, this)(playerID); + if (BVar6 == FALSE) + return; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 4; + DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 0; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); + return; + } + if (_aiPlayerState_2 == 4) { + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + *piVar2 = *piVar2 + 1; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::countSiegeEngineUnits, this)(playerID); + if (iVar5 < 1) + DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 100; + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue; + *piVar2 = *piVar2 + 1; + if (DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue + <= *(int*)((int)this + _aiType * 0x2a4 + 0x208)) + return; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocationFullVolume, DAT_SFXState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, 0x14); + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + if (BVar6 == FALSE) { + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); - + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe11StandGroundToGate, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe13DefensiveWave, this)(playerID); + recomputeAndReset(this, playerID); return; } + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; + return; + } - if (_aiPlayerState_2 == 4) { - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - - *piVar2 = *piVar2 + 1; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); - - iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::countSiegeEngineUnits, this)(playerID); - - if (iVar5 < 1) { - - DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 100; - } - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue; - - *piVar2 = *piVar2 + 1; - - if (DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue - <= *(int*)((int)this + _aiType * 0x2a4 + 0x208)) { - - return; - } - + if (_aiPlayerState_2 == 5) { + if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + short* psVar1 = &DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; + *psVar1 = *psVar1 + 1; + short sVar3 = DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + *piVar2 = *piVar2 + 1; + DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; + if (3 < sVar3) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocationFullVolume, DAT_SFXState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, - DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, 0x14); - - BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - - if (BVar6 == FALSE) { - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe11StandGroundToGate, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe13DefensiveWave, this)(playerID); - - LAB_004d4ed3: - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); - - DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; - - return; - } - - } - - else { - - if (_aiPlayerState_2 != 5) { - - if (_aiPlayerState_2 == 6) { - - /* - Enemy castle breached! */ - - if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) { - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; - } - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - - *piVar2 = *piVar2 + 1; - - _playerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; - - DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; - - MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::calculateAttackVectorsToCampFireOfPlayer, - DAT_GameState::ptr)(_playerID); - - iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToAttackBreachedCastle, this)( - playerID); - - if (iVar5 != 0) { - - return; - } - - BVar6 = MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - - if (BVar6 != FALSE) { - - return; - } - - BVar6 - = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, - DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - - if (BVar6 != FALSE) { - - return; - } - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; - - goto LAB_004d4ed3; - } - - if (_aiPlayerState_2 == 7) { - - piVar2 - = &DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue; - - *piVar2 = *piVar2 + 1; - - if (DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue - <= *(int*)((int)this + _aiType * 0x2a4 + 0x20c)) { - - return; - } - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)( - playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( - playerID); - - return; - } - - if (_aiPlayerState_2 == 8) { - - /* - Retreat from attack. */ - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; - - DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)( - playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( - playerID); - - if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) { - - return; - } - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playAnger1BikFromPlayer, this)(playerID); - - return; - } - - if (_aiPlayerState_2 != 9) { - - return; - } - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - - *piVar2 = *piVar2 + 1; - - if (((DAT_GameState::instance.playerDataArray[playerID].attackTicker < 20) - && (BVar6 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::percentageNonMovingTribesGTEAICSpecified, this)( - playerID), - BVar6 == FALSE)) - && (BVar6 - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID), - BVar6 == FALSE)) { - - return; - } - - goto LAB_004d4ff7; - } - - /* - _aiPlayerState_2 is 5 (Attack walls) */ - - if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) { - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; - } - - psVar1 = &DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; - - *psVar1 = *psVar1 + 1; - - sVar3 = DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; - - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - - *piVar2 = *piVar2 + 1; - - DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; - - if (3 < sVar3) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandWallAssaultTribes, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); - - MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::setTribe0x11ToAggressiveAndAttackIfConditionMet, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setEightTribe0xc0TribesToAggressiveAndAttack, this)( - playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); - - DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)( - playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xCtoAggressiveAndAttack, this)(playerID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xbToAggressiveAndAttack, this)(playerID); - } - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); - - BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - - if ((BVar6 == FALSE) - && (BVar6 - = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, - DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID), - BVar6 == FALSE)) { - - return; - } + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandWallAssaultTribes, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0x11ToAggressiveAndAttackIfConditionMet, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setEightTribe0xc0TribesToAggressiveAndAttack, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xCtoAggressiveAndAttack, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xbToAggressiveAndAttack, this)(playerID); } - + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + if ((BVar6 == FALSE) + && (BVar6 = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID), + BVar6 == FALSE)) + return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; - return; } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recreateEngineersTribe, this)(playerID); - - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 2; - - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::initializeGatePathfindingForOwner, - DAT_BuildingsState::ptr)(playerID); - - /* - computes the first siege location for units */ - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeEnemyKeepApproachTile, this)(playerID); - - if (0 < DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackTribesToLocations, this)((short*)playerID); + if (_aiPlayerState_2 == 6) { + if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + *piVar2 = *piVar2 + 1; + int _playerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; + MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::calculateAttackVectorsToCampFireOfPlayer, + DAT_GameState::ptr)(_playerID); + iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToAttackBreachedCastle, this)(playerID); + if (iVar5 != 0) + return; + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + if (BVar6 != FALSE) + return; + BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + if (BVar6 != FALSE) + return; + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; + recomputeAndReset(this, playerID); + return; + } + if (_aiPlayerState_2 == 7) { + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue; + *piVar2 = *piVar2 + 1; + if (DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue + <= *(int*)((int)this + _aiType * 0x2a4 + 0x20c)) + return; + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)(playerID); return; } - LAB_004d4ff7: - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + if (_aiPlayerState_2 == 8) { + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; + DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)(playerID); + if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) + return; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playAnger1BikFromPlayer, this)(playerID); + return; + } - return; + if (_aiPlayerState_2 == 9) { + piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; + *piVar2 = *piVar2 + 1; + if (((DAT_GameState::instance.playerDataArray[playerID].attackTicker < 20) + && (BVar6 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::percentageNonMovingTribesGTEAICSpecified, this)(playerID), + BVar6 == FALSE)) + && (BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID), + BVar6 == FALSE)) + return; + // was LAB_004d4ff7 + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; + } } - } } diff --git a/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp index 22deecfe3..8ff7b1851 100644 --- a/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp @@ -23,561 +23,228 @@ namespace AI { using OpenSHC::Game::TrailType; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - this functions info is based on np123 - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D3320 void AICState ::updateAIStrengthState(int playerID, int aiRecruitUnitChoicePreference) - { - - int* piVar1; - - short* psVar2; - - int _totalTroopCount; - - int _aicOffset; - - int _rng; - - int _raidUnitCount; - - BOOLEnum _teamWeak; - - BOOLEnum _outOfSupplies2; - - BOOLEnum _teamWeak2; - - BOOLEnum _outOfSupplies; - - int _totalRecruitProb; - - bool bVar3; - - int _totalDefenseTroops; - - int _aiType; - - int _currentPopulation; - - int _totalFood; - - int _aiStrengthState; - - int _aiRecruitUnitChoiceState; - - int _subtraction; - - int _aiType_2; - - int _totalRaidTroops; - - int _defTotal; - - int _currentGold_2; - - int _aiNervousActionsTracker; - - AINervousDestroyBuildingCategoryInt _cat; - - int _aiNervousActionsTracker2; - - int _aiBuildingDestroyActionsTracker; - - int _currentGold; - - int _aiTypeMin1; - - AINervousDestroyBuildingCategory _cat2; - - int _recruitProbDefensive; - - int _recruitProbRaid; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - /* - is human */ - - if (_aiType == 0) { - + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == 0) return; - } if ((char)aiRecruitUnitChoicePreference == '\0') { - - if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) { - + if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) return; - } - - if (DAT_GameCore::instance.isSkirmishTrail != TRUE) { - + if (DAT_GameCore::instance.isSkirmishTrail != TRUE) return; - } - - if (DAT_GameCore::instance.currentTrailType != OpenSHC::Game::TT_EXTREME) { - + if (DAT_GameCore::instance.currentTrailType != OpenSHC::Game::TT_EXTREME) return; - } } - _aiTypeMin1 = _aiType + -1; - - _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; - + int _aiTypeMin1 = _aiType + -1; + int _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 0; - /* - check if current gold less than 200 */ - - if (_currentGold < 200) { - - DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 0; - - } - - else { - - /* - 2 if currentGold > 1999 else 1 */ - + if (_currentGold >= 200) DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = (1999 < _currentGold) + 1; - } - - _currentPopulation = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; + int _currentPopulation = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; if (15 < _currentPopulation) { - - /* - if currentPopulation more than 14 */ - - if (_currentPopulation < 40) { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - - /* - if currentPopulation less than 40 */ - + int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + if (_currentPopulation < 40) *piVar1 = *piVar1 + 1; - - } - - else { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - - /* - if current Population more than 40 */ - + else *piVar1 = *piVar1 + 2; - } } - /* - check if total food higher than 20 */ - - _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; - + int _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; if (20 < _totalFood) { - - if (_totalFood < 200) { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - + int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + if (_totalFood < 200) *piVar1 = *piVar1 + 1; - - } - - else { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - + else *piVar1 = *piVar1 + 2; - } } - _totalTroopCount = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + int _totalTroopCount = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk + DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; - - /* - check if troop strength above 7 */ - if (7 < _totalTroopCount) { - - /* - check if troop strength smaller than 40 */ - - if (_totalTroopCount < 40) { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - + int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + if (_totalTroopCount < 40) *piVar1 = *piVar1 + 2; - - } - - else { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - + else *piVar1 = *piVar1 + 4; - } } - _aiStrengthState = DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - - if (_aiStrengthState < 3) { - + int _aiStrengthState = DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + if (_aiStrengthState < 3) DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; - - } - - else if (_aiStrengthState < 8) { - + else if (_aiStrengthState < 8) DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_DEFAULT; - - } - - else { - + else DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_STRONG; - } if ((DAT_GameState::instance.playerDataArray[playerID].aivCurrentPauseIndex == 1) - && (0 < DAT_GameState::instance.playerDataArray[playerID].aivPauses[1])) { - - /* - if pausing at first pause - */ - + && (0 < DAT_GameState::instance.playerDataArray[playerID].aivPauses[1])) DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; - } - - /* - add the aiStrengthFeeling to (aiType * 169). The AI Personality struct is a - 169*4 long element of an array of 16 elements (all ai types, maybe more?) */ - - _aicOffset = DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + _aiTypeMin1 * 169; - - /* - fetch RecruitProbRaid for current aiType */ - _recruitProbRaid = *(int*)((int)this + _aicOffset * 4 + 0x134); + int _aicOffset = DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + _aiTypeMin1 * 169; + int _recruitProbRaid = *(int*)((int)this + _aicOffset * 4 + 0x134); + int _recruitProbDefensive = *(int*)((int)this + _aicOffset * 4 + 0x128); + int _totalRecruitProb = *(int*)((int)this + _aicOffset * 4 + 0x140) + _recruitProbRaid + _recruitProbDefensive; - /* - fetch RecruitProbDefensive */ - - _recruitProbDefensive = *(int*)((int)this + _aicOffset * 4 + 0x128); - - /* - add RecruitProbAttack to the other two probs */ - - _totalRecruitProb = *(int*)((int)this + _aicOffset * 4 + 0x140) + _recruitProbRaid + _recruitProbDefensive; - - /* - check if recruitProb = 0 */ + int _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_ATTACKING; + bool bVar3 = false; + int _subtraction = 0; + bool _needsCheck = false; if (_totalRecruitProb == 0) { - _aiRecruitUnitChoiceState = aiRecruitUnitChoicePreference; - if (aiRecruitUnitChoicePreference == 1) { - - LAB_004d34e9: - /* - WARNING: reused variable _aiType */ - - _raidUnitCount = MACRO_CALL_MEMBER( + int _raidUnitCount = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(_aiTypeMin1, playerID); - - _totalDefenseTroops = DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk; - - bVar3 = (_totalDefenseTroops < _raidUnitCount); - - _subtraction = _totalDefenseTroops - _raidUnitCount; - - goto LAB_004d3515; + int _totalDefTroops = DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk; + bVar3 = (_totalDefTroops < _raidUnitCount); + _subtraction = _totalDefTroops - _raidUnitCount; + _needsCheck = true; + } else if (aiRecruitUnitChoicePreference == 0) { + int _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; + int _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); + bVar3 = (_totalRaidTroops < _defTotal); + _subtraction = _totalRaidTroops - _defTotal; + _needsCheck = true; } - - if (aiRecruitUnitChoicePreference == 0) - goto LAB_004d3502; - - } - - else { - - _rng = (int)SEC_RNG::instance.currentNumber2; - - /* - WARNING: prob is now randomized */ - + } else { + int _rng = (int)SEC_RNG::instance.currentNumber2; MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - /* - if DAT_01fe7da8 < 4800 */ - if ((int)DAT_GameCore::instance.mapTimeInTicks < 4800) { - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - - LAB_004d3502: - _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; - - /* - true if param1 > param0 */ - - _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); - + int _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; + int _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); bVar3 = (_totalRaidTroops < _defTotal); - _subtraction = _totalRaidTroops - _defTotal; - - LAB_004d3515: - if (bVar3 != _subtraction < 0) - goto LAB_004d351c; - - } - - else { - - /* - if RecruitProbDefensive > RandomizedRecruitProb */ - - if (_rng % _totalRecruitProb < _recruitProbDefensive) { - - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - - goto LAB_004d3502; - } - - if (_rng % _totalRecruitProb < _recruitProbRaid + _recruitProbDefensive) { - - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_RAIDING; - - goto LAB_004d34e9; - } + _needsCheck = true; + } else if (_rng % _totalRecruitProb < _recruitProbDefensive) { + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; + int _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; + int _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); + bVar3 = (_totalRaidTroops < _defTotal); + _subtraction = _totalRaidTroops - _defTotal; + _needsCheck = true; + } else if (_rng % _totalRecruitProb < _recruitProbRaid + _recruitProbDefensive) { + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_RAIDING; + int _raidUnitCount = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(_aiTypeMin1, playerID); + int _totalDefTroops = DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk; + bVar3 = (_totalDefTroops < _raidUnitCount); + _subtraction = _totalDefTroops - _raidUnitCount; + _needsCheck = true; } - - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_ATTACKING; } - LAB_004d351c: - if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState != _aiRecruitUnitChoiceState) { + if (!_needsCheck || !(bVar3 == (_subtraction < 0))) + _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_ATTACKING; + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState != _aiRecruitUnitChoiceState) DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = _aiRecruitUnitChoiceState; - } - - if ((char)aiRecruitUnitChoicePreference == '\0') { + if ((char)aiRecruitUnitChoicePreference == '\0') return; - } if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) { - - _teamWeak = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, TRUE); - + BOOLEnum _teamWeak = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, TRUE); if (_teamWeak == FALSE) { - DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = 0; - return; } - - /* - WARNING: aiType now means currentGold */ - - _currentGold_2 = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; - + int _currentGold_2 = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; - DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - /* - if gold <= 500 */ - if (_currentGold_2 < 500) { - - _aiNervousActionsTracker = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; - - if (_aiNervousActionsTracker < 8) { - - /* - destroy a good or bad thing */ - + int _aiNervAct = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + if (_aiNervAct < 8) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( playerID, OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS); - - _cat = OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS; - - } - - else { - - if (5 < _aiNervousActionsTracker) - goto LAB_004d35fb; - - /* - fixme: does this line ever happen? */ - - _cat = OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); + } else if (!(5 < _aiNervAct)) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); } - - /* - destroy a workshop (2) or a resource building (iron mine... bakery) (6) */ - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, (AINervousDestroyBuildingCategory)((int)(_cat))); - - } - - else { - - /* - if gold > 2500 and... */ - - if (((2500 < _currentGold_2) - && (psVar2 = &DAT_GameState::instance.playerDataArray[playerID].aiStateCounter, - *psVar2 = *psVar2 + 1, - (DAT_GameState::instance.playerDataArray[playerID].aiStateCounter & 1U) != 0)) + } else { + short* psVar2 = &DAT_GameState::instance.playerDataArray[playerID].aiStateCounter; + *psVar2 = *psVar2 + 1; + if ((2500 < _currentGold_2) + && ((DAT_GameState::instance.playerDataArray[playerID].aiStateCounter & 1U) != 0) && (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 20)) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::shareGoldAmongTeamMembers, this)( playerID, _currentGold_2 / 10); } } - LAB_004d35fb: - _aiNervousActionsTracker2 = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; - - if (_aiNervousActionsTracker2 < 2) { - + int _aiNervAct2 = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + if (_aiNervAct2 < 2) return; - } - - DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = _aiNervousActionsTracker2 + -1; - + DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = _aiNervAct2 + -1; return; } - /* - ********************************************************* - * From here on we process logic for destroying buildings - ********************************************************* */ - - _aiBuildingDestroyActionsTracker - = DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; - - if (_aiBuildingDestroyActionsTracker < 1) { - - _teamWeak2 - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, FALSE); + int _aiBuildDestroyTracker = DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + if (_aiBuildDestroyTracker < 1) { + BOOLEnum _teamWeak2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, FALSE); if (_teamWeak2 != FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playNervous2BikFromPlayer, this)(playerID); - DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = 8; - DAT_GameState::instance.playerDataArray[playerID].aiStateCounter = 0; - return; } - - _outOfSupplies = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); - - if (_outOfSupplies == FALSE) { - + BOOLEnum _outOfSupplies = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); + if (_outOfSupplies == FALSE) return; - } - DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 8; - return; } - _outOfSupplies2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); - + BOOLEnum _outOfSupplies2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); if (_outOfSupplies2 == FALSE) { - DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 0; - return; } DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] = 20; - DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; - DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - if (_aiBuildingDestroyActionsTracker == 8) { - - _cat2 = OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS; - - } - - else { - - if (_aiBuildingDestroyActionsTracker == 7) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; - - *piVar1 = *piVar1 + -1; - - return; - } - - if (_aiBuildingDestroyActionsTracker == 6) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_GATEHOUSES_TOWERS_GUILDS); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_BARRACKS_MERCPOST_STABLES); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_WATER_BUILDINGS); - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; - - *piVar1 = *piVar1 + -1; - - return; - } - - if (_aiBuildingDestroyActionsTracker == 5) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; - - *piVar1 = *piVar1 + -1; - - return; - } - - if (_aiBuildingDestroyActionsTracker != 4) - goto LAB_004d3707; - - _cat2 = OpenSHC::AI::AINDBC_FARMS; + if (_aiBuildDestroyTracker == 8) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS); + } else if (_aiBuildDestroyTracker == 7) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; + return; + } else if (_aiBuildDestroyTracker == 6) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_GATEHOUSES_TOWERS_GUILDS); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_BARRACKS_MERCPOST_STABLES); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WATER_BUILDINGS); + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; + return; + } else if (_aiBuildDestroyTracker == 5) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; + return; + } else if (_aiBuildDestroyTracker == 4) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_FARMS); } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)(playerID, _cat2); - - LAB_004d3707: - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; - - *piVar1 = *piVar1 + -1; - - return; + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; } - } } diff --git a/src/OpenSHC/AI/AICState/updateTribeLocations.cpp b/src/OpenSHC/AI/AICState/updateTribeLocations.cpp index 65cc46e7b..d84f52f91 100644 --- a/src/OpenSHC/AI/AICState/updateTribeLocations.cpp +++ b/src/OpenSHC/AI/AICState/updateTribeLocations.cpp @@ -11,36 +11,25 @@ namespace AI { using OpenSHC::AI::AIType; using OpenSHC::AI::AITypeInt; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D4940 void AICState ::updateTribeLocations(int playerID) { - int* piVar1; - AITypeInt AVar2; AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiType; if (AVar2 != OpenSHC::AI::AIT_NULL) { - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter; - - *piVar1 = *piVar1 + 1; - - /* - defWallPatrolRallyTime - */ - - if (*(int*)((int)DAT_EntityState::instance.seagullArray + AVar2 * 0x2a4 + 0x2580) - <= DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter) { + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter = + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter + 1; - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits; + if (DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter + >= *(int*)((int)this + AVar2 * 0x2a4 - 0x194)) { - *piVar1 = *piVar1 + 1; + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits = + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits + 1; DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter = 0; } From c2f19927c33f52daa200eb55dc25340d3ecf7014 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Tue, 28 Jul 2026 22:59:25 +0200 Subject: [PATCH 036/242] param change --- src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 11 ++-- .../AICState/moveAttackTribesToLocations.cpp | 10 ++-- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 11 ++-- .../AI/AICState/updateAIPlayerState.cpp | 56 ++++++++++--------- 4 files changed, 47 insertions(+), 41 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp index d2308602d..68d583f0e 100644 --- a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -21,7 +21,7 @@ namespace AI { decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CE4D0 - void AICState ::aiRetreatUnits(short* playerID) + void AICState ::aiRetreatUnits(int playerID) { @@ -37,7 +37,7 @@ namespace AI { int _groupCount; - short* _playerID; + int _playerID; _playerID = playerID; @@ -55,11 +55,12 @@ namespace AI { if (0 < _groupCount) { - playerID = DAT_GameState::instance.playerDataArray[(int)_playerID].aiTribeIDs + _aiBehaviourType; + short* __playerID + = DAT_GameState::instance.playerDataArray[(int)_playerID].aiTribeIDs + _aiBehaviourType; do { - _tribeID = (int)*playerID; + _tribeID = (int)*__playerID; if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid @@ -104,7 +105,7 @@ namespace AI { } } - playerID = playerID + 1; + __playerID = __playerID + 1; _counter = _counter + 1; diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp index 46999d708..69cfc4111 100644 --- a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -19,7 +19,7 @@ namespace AI { decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CE830 - void AICState ::moveAttackTribesToLocations(short* playerID) + void AICState ::moveAttackTribesToLocations(int playerID) { @@ -27,7 +27,7 @@ namespace AI { int iVar2; - short* psVar3; + int psVar3; int tribeID; @@ -55,11 +55,11 @@ namespace AI { if (0 < iVar1) { - playerID = DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeIDs + iVar2; + short* __playerID = DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeIDs + iVar2; do { - tribeID = (int)*playerID; + tribeID = (int)*__playerID; if ((tribeID != 0) && (DAT_TribesState::instance.tribes[tribeID].uid @@ -85,7 +85,7 @@ namespace AI { iVar4 = iVar4 + 1; } - playerID = playerID + 1; + __playerID = __playerID + 1; iVar5 = iVar5 + 1; diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index db61864a8..50779533e 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -23,7 +23,7 @@ namespace AI { decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CE5F0 - void AICState ::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, short* playerID2) + void AICState ::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, int playerID2) { @@ -49,7 +49,7 @@ namespace AI { uint _p1_keepCampfireY; - short* _playerID2; + int _playerID2; _playerID2 = playerID2; @@ -92,11 +92,12 @@ namespace AI { /* fixme: reused parameter */ - playerID2 = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _aiTribeBehaviourTypeOffset; + short* __playerID2 + = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _aiTribeBehaviourTypeOffset; do { - _tribeID = (int)*playerID2; + _tribeID = (int)*__playerID2; if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid @@ -147,7 +148,7 @@ namespace AI { } } - playerID2 = playerID2 + 1; + __playerID2 = __playerID2 + 1; _counter = _counter + 1; diff --git a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp index 88a716c36..607b9a752 100644 --- a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp @@ -20,7 +20,7 @@ namespace AI { using OpenSHC::WindowsHelper::Enums::BOOLEnum; // Helper shared by state 4 (canNavigate==FALSE) and state 6 (canUnitsNavigate==FALSE) - static void recomputeAndReset(OpenSHC::AI::AICState* pThis, int playerID) + __forceinline static void recomputeAndReset(OpenSHC::AI::AICState* pThis, int playerID) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, pThis)(playerID, 0); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, pThis)(playerID); @@ -63,8 +63,8 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackCoordinationLevel, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackStrength, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackRaidParameter, this)(playerID); - int* piVar2 = (int*)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID * 0x39f4 - + 0x115e9d4 + playerID * 0x20); + int* piVar2 = (int*)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID * 0x39f4 + 0x115e9d4 + + playerID * 0x20); *piVar2 = *piVar2 + 1; } else { BOOLEnum BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID); @@ -85,13 +85,14 @@ namespace AI { if (iVar5 < 4) { DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)( + MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( + playerID); } else if (iVar5 < 7) { DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 7; } @@ -119,13 +120,13 @@ namespace AI { } if (_aiPlayerState_2 == 2) { - uint _rallyReady = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID); + uint _rallyReady + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID); if (_rallyReady == 0) return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 3; - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers, - this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers, this)( + playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setNextMoveLocationForUnits, this)(playerID); @@ -167,7 +168,7 @@ namespace AI { piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue; *piVar2 = *piVar2 + 1; if (DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue - <= *(int*)((int)this + _aiType * 0x2a4 + 0x208)) + <= ((int)this->aics[_aiType].AttAssaultDelay)) return; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); @@ -181,7 +182,9 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe11StandGroundToGate, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe13DefensiveWave, this)(playerID); - recomputeAndReset(this, playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; return; } DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; @@ -202,11 +205,14 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandWallAssaultTribes, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0x11ToAggressiveAndAttackIfConditionMet, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setEightTribe0xc0TribesToAggressiveAndAttack, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0x11ToAggressiveAndAttackIfConditionMet, this)( + playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setEightTribe0xc0TribesToAggressiveAndAttack, this)( + playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::removeOrganismsAndSetMoveDestinationPairs, this)( + playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::commandFourTribesToMove, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xCtoAggressiveAndAttack, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xbToAggressiveAndAttack, this)(playerID); @@ -216,9 +222,8 @@ namespace AI { DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); if ((BVar6 == FALSE) && (BVar6 = MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID, - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID), + OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID), BVar6 == FALSE)) return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; @@ -246,7 +251,9 @@ namespace AI { if (BVar6 != FALSE) return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; - recomputeAndReset(this, playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; return; } @@ -254,13 +261,12 @@ namespace AI { piVar2 = &DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue; *piVar2 = *piVar2 + 1; if (DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue - <= *(int*)((int)this + _aiType * 0x2a4 + 0x20c)) + <= ((int)this->aics[_aiType].AttUnitPatrolRecommandDelay)) return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); @@ -273,8 +279,7 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); @@ -286,8 +291,7 @@ namespace AI { } if (_aiPlayerState_2 == 9) { - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - *piVar2 = *piVar2 + 1; + DAT_GameState::instance.playerDataArray[playerID].attackTicker += 1; if (((DAT_GameState::instance.playerDataArray[playerID].attackTicker < 20) && (BVar6 = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::percentageNonMovingTribesGTEAICSpecified, this)(playerID), From 0f559419c1f1b89b9b576e9e7ff6d1f9a144e5e6 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 00:16:57 +0200 Subject: [PATCH 037/242] improvements --- src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 144 +++++------------ .../AICState/moveAttackTribesToLocations.cpp | 104 ++++-------- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 150 +++++------------- 3 files changed, 121 insertions(+), 277 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp index 68d583f0e..ba171bf29 100644 --- a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -2,7 +2,7 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" +#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" @@ -10,115 +10,59 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - doc:| - Retreat units to campfire or keep - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; // FUNCTION: STRONGHOLDCRUSADER 0x004CE4D0 - void AICState ::aiRetreatUnits(int playerID) - + void AICState::aiRetreatUnits(int playerID) { - - BOOLEnum BVar1; - - int _counter; - - int _tribeID; - - int* local_8; - - int _aiBehaviourType; - - int _groupCount; - - int _playerID; - - _playerID = playerID; - - if (DAT_GameState::instance.playerDataArray[(int)playerID].aiType != OpenSHC::AI::AIT_NULL) { - - local_8 = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; - - do { - - _groupCount = *local_8; - - _aiBehaviourType = (*(int (*)[2])(local_8 + -1))[0]; - - _counter = 0; - - if (0 < _groupCount) { - - short* __playerID - = DAT_GameState::instance.playerDataArray[(int)_playerID].aiTribeIDs + _aiBehaviourType; - - do { - - _tribeID = (int)*__playerID; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[(int)_playerID] - .aiTribeUIDs[_counter + _aiBehaviourType])) { - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - if (_aiBehaviourType == 0xbe) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, (int)((int)(_playerID))); - - } - - else if (_aiBehaviourType == 0xd) { - + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; + + for (int _index1 = 0; _index1 < 11; _index1++) { + int* _mappingPtr + = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[_index1] + 1; + int const _maxTribeCount = *_mappingPtr; + int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr - 1))[0]; + int _tribeIndex = 0; + + if (0 < _maxTribeCount) { + + for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { + int const _tribeID + = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart + _tribeIndex]; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + if (_tribeTypeStart == 0xbe) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID); + } else if (_tribeTypeStart == 0xd) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID); + } else { + int const _hasHorses + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + if (_hasHorses != FALSE) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, (int)((int)(_playerID))); - - } - - else { - - BVar1 - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, - DAT_TribesState::ptr)(_tribeID); - - if (BVar1 == FALSE) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( - _tribeID, (int)((int)(_playerID))); - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, (int)((int)(_playerID))); - } + _tribeID, playerID); + } else { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( + _tribeID, playerID); } } - - __playerID = __playerID + 1; - - _counter = _counter + 1; - - } while (_counter < _groupCount); + } } - - local_8 = local_8 + 2; - - } while ((int)local_8 < 0xb42a2c); + } } - - return; } - } } diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp index 69cfc4111..eaaa3fd90 100644 --- a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -15,89 +15,55 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CE830 - void AICState ::moveAttackTribesToLocations(int playerID) - + void AICState::moveAttackTribesToLocations(int playerID) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; - int iVar1; - - int iVar2; - - int psVar3; - - int tribeID; - - int iVar4; - - int iVar5; - - int* local_c; - - psVar3 = playerID; - - if (DAT_GameState::instance.playerDataArray[(int)playerID].aiType != OpenSHC::AI::AIT_NULL) { - - iVar4 = 0; + int _destIndex = 0; - local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + for (int _index = 0; _index < 11; _index++) { + int* _mappingPtr + = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[_index] + 1; - do { + int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr + -1))[0]; + int _tribeIndex = 0; + int const _maxTribeCount = *_mappingPtr; - iVar1 = *local_c; + if (0 < _maxTribeCount) { + short* _tribeIDPtr = &DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart]; - iVar2 = (*(int (*)[2])(local_c + -1))[0]; + do { + int const _tribeID = (int)*_tribeIDPtr; - iVar5 = 0; + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { - if (0 < iVar1) { + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - short* __playerID = DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeIDs + iVar2; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(_tribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] + .xOffset)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] + .yOffset)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - do { + _destIndex = _destIndex + 1; + } - tribeID = (int)*__playerID; + _tribeIDPtr = _tribeIDPtr + 1; + _tribeIndex = _tribeIndex + 1; - if ((tribeID != 0) - && (DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[(int)psVar3].aiTribeUIDs[iVar5 + iVar2])) { - - DAT_TribesState::instance.tribes[tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - - /* - fixme: array too small? - */ - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(tribeID, - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[(int)psVar3 * 5][iVar4] - .xOffset)), - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[(int)psVar3 * 5][iVar4] - .yOffset)), - 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - - iVar4 = iVar4 + 1; - } - - __playerID = __playerID + 1; - - iVar5 = iVar5 + 1; - - } while (iVar5 < iVar1); - } - - local_c = local_c + 2; - - } while ((int)local_c < 0xb42a2c); + } while (_tribeIndex < _maxTribeCount); + } } - - return; } } diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index 50779533e..4c4593028 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -4,7 +4,6 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_PathFindingState.hpp" @@ -14,153 +13,88 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CE5F0 - void AICState ::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, int playerID2) - + void AICState::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, int playerID2) { + uint _p1_campfireX = DAT_GameState::instance.playerDataArray[playerID1].campground.xEntry; + uint _p1_campfireY = DAT_GameState::instance.playerDataArray[playerID1].campground.yEntry; - BOOLEnum BVar1; - - dword _gatehouseTile; - - int _tribeID; - - int _counter; - - int* local_10; - - uint _ghY; + int const _canNavigate = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID1, playerID2); uint _ghX; + uint _ghY; - int _maxTribeCount; - - int _p1_keepCampfireX; - - int _aiTribeBehaviourTypeOffset; - - uint _p1_keepCampfireY; - - int _playerID2; - - _playerID2 = playerID2; - - _p1_keepCampfireY = DAT_GameState::instance.playerDataArray[playerID1].campground.yEntry; - - _p1_keepCampfireX = DAT_GameState::instance.playerDataArray[playerID1].campground.xEntry; - - BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID1, (int)((int)(playerID2))); - - if (BVar1 == FALSE) { - - _gatehouseTile = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findOwnedGatehouse, - DAT_PathFindingState::ptr)((int)playerID2, (uint)((int)(_p1_keepCampfireX)), _p1_keepCampfireY); - + if (_canNavigate == FALSE) { + dword const _gatehouseTile + = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findOwnedGatehouse, + DAT_PathFindingState::ptr)(playerID2, _p1_campfireX, _p1_campfireY); if (_gatehouseTile == 0) { - DAT_GameState::instance.playerDataArray[playerID1].requestStateUnk = 0; - return; } - _ghY = (uint)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_gatehouseTile]; - _ghX = _gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[_ghY].addXgetTile; } - local_10 = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + int* _mappingPtr = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; do { - - _maxTribeCount = *local_10; - - _aiTribeBehaviourTypeOffset = (*(int (*)[2])(local_10 + -1))[0]; - - _counter = 0; + int const _maxTribeCount = *_mappingPtr; + int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr - 1))[0]; + int _tribeIndex = 0; if (0 < _maxTribeCount) { - - /* - fixme: reused parameter */ - - short* __playerID2 - = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _aiTribeBehaviourTypeOffset; + short* _tribeIDPtr = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _tribeTypeStart; do { - - _tribeID = (int)*__playerID2; + int const _tribeID = (int)*_tribeIDPtr; if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID1] - .aiTribeUIDs[_counter + _aiTribeBehaviourTypeOffset])) { + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID1, (int)((int)(_playerID2))); - - if (BVar1 == FALSE) { - - /* - send to enemy gate house */ + int const _canNav2 + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID1, playerID2); + if (_canNav2 != FALSE) { + if (_tribeTypeStart == 0xbe) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID2); + } else { + int const _hasHorses + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + if (_hasHorses != FALSE) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID2); + } else { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( + _tribeID, playerID2); + } + } + } else { MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( _tribeID, _ghX, _ghY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - - } - - else if (_aiTribeBehaviourTypeOffset == 0xbe) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, (int)((int)(_playerID2))); - - } - - else { - - BVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, - DAT_TribesState::ptr)(_tribeID); - - if (BVar1 == FALSE) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( - _tribeID, (int)((int)(_playerID2))); - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, (int)((int)(_playerID2))); - } } } - __playerID2 = __playerID2 + 1; - - _counter = _counter + 1; - - } while (_counter < _maxTribeCount); + _tribeIDPtr = _tribeIDPtr + 1; + _tribeIndex = _tribeIndex + 1; + } while (_tribeIndex < _maxTribeCount); } - local_10 = local_10 + 2; - - } while ((int)local_10 < 0xb42a2c); - - return; + _mappingPtr = _mappingPtr + 2; + } while ((int)_mappingPtr < 0xb42a2c); } - } } From 8e9929f05bae69270644ef0fcc7eaa604874a103 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 11:22:09 +0200 Subject: [PATCH 038/242] field name updates --- .../addUnitToSmallestBehaviourTypeTribe.cpp | 2 +- .../aiChoiceAttForceRallyPercentage.cpp | 2 +- .../AI/AICState/aiCreateSiegeUnits.cpp | 267 +++++++++++++----- .../AI/AICState/aiGiveRaidInstructions.cpp | 69 +++-- src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 3 +- src/OpenSHC/AI/AICState/buyRequiredGoods.cpp | 2 +- ...mBuildingIDFromPlayersArrayOfBuildings.cpp | 13 +- .../AI/AICState/clearOutdatedAITribes.cpp | 6 +- .../clearRallyFlagOnAllAIAttackTribes.cpp | 3 +- ...ndAttackTribePositionAndPathToDefenses.cpp | 8 +- .../generateSiegeCreationInformation.cpp | 2 +- .../getTargetableBuildingForPlayerID.cpp | 2 +- .../giveMoveCommandToAttackTribes.cpp | 3 +- ...eUnitsGoDefensiveAndBackToSomeLocation.cpp | 2 +- .../AICState/moveAttackTribesToLocations.cpp | 3 +- ...rcentageNonMovingTribesGTEAICSpecified.cpp | 2 +- .../processAttForceRallyPercentage.cpp | 6 +- .../randomlySelectAttackUnitTypeToRecruit.cpp | 29 +- ...selectBuildingFromAListOfBuildingTypes.cpp | 2 +- src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 2 +- ...oAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp | 2 +- ...gedUnitTribesToAIVSlotsOrKeepIfNervous.cpp | 3 +- .../sendUnitsToAttackBreachedCastle.cpp | 3 +- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 2 +- ...sendWallPatrolUnitTribesToAIVLocations.cpp | 2 +- .../AI/AICState/smallestTribeOfUnitType.cpp | 2 +- .../AI/AICState/someChatMessageSelection.cpp | 12 +- .../AI/AICState/unitIDIsRangedOrArmored.cpp | 4 +- ...12_toPlaceSiegeTentsAndAssignEngineers.cpp | 12 +- 29 files changed, 307 insertions(+), 163 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp index 402f0e208..c26db36f6 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp @@ -19,7 +19,7 @@ namespace AI { return 0; } int _tribeTypeOffset - = DAT_SkirmishDefinedData::instance.DAT_AIUnitBehaviourTypeMapping[(int)aiUnitBehaviourType + -10]; + = DAT_SkirmishDefinedData::instance.AIUnitBehaviourTypeMapping[(int)aiUnitBehaviourType + -10]; int _smallestTribe = 0; int _smallestTribeOffset = 0; short _smallestTribeSize = 1000; diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp index 46b561d3c..165cf2937 100644 --- a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -45,7 +45,7 @@ namespace AI { local_10 = 0; - local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index 704837eaf..c5e339c24 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -58,8 +58,11 @@ namespace AI { int* _pDelay; do { - UnitType _unitType = *(UnitType*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].unitType + _mappingOffset); - int _tribeSize = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + _mappingOffset)]; + UnitType _unitType + = *(UnitType*)((int)&DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[0].unitType + + _mappingOffset); + int _tribeSize = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*( + int*)((int)&DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[0].slot + _mappingOffset)]; int _slotIndex = 0; int _nextSlotIndex; @@ -69,14 +72,22 @@ namespace AI { if (0 < _tribeSize) { do { _nextSlotIndex = _slotIndex + 1; - int _location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].slot + _mappingOffset)][_slotIndex]; + int _location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[*( + int*)((int)&DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[0].slot + + _mappingOffset)][_slotIndex]; if (0 < _location) { int _existingBuildingID = (int)(short)DAT_TileMapState::instance.BuildingLayer[_location]; int _engineIndex = _incrementsBy5 + _slotIndex; - int _unitID = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID; - int _uid = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid; - int _tile = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID; + int _unitID = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID; + int _uid = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid; + int _tile = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID; if ((_unitID == 0) || (DAT_UnitsState::instance.units[_unitID].uid == _uid)) { if ((_tile == 0) || (DAT_BuildingsState::instance.buildings[_tile].uid == _uid)) { @@ -87,52 +98,124 @@ namespace AI { if (0x1f < _mappingOffset) _doPlace = true; } else if ((_mappingOffset < 0x20)) { - BuildingTypeShort _existingBuildingType = DAT_BuildingsState::instance.buildings[_existingBuildingID].buildingType; - if (_existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER4 || _existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER5) + BuildingTypeShort _existingBuildingType + = DAT_BuildingsState::instance.buildings[_existingBuildingID] + .buildingType; + if (_existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER4 + || _existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER5) _doPlace = true; } else { _doPlace = true; } if (_doPlace) { - int _requiredGold = DAT_BuildingsState::instance.buildingCosts[*(int*)((int)&DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[0].buildingType + _mappingOffset)].requiredGold; + int _requiredGold + = DAT_BuildingsState::instance + .buildingCosts[*(int*)((int)&DAT_SkirmishDefinedData::instance + .SiegeEngineMetaInfoArray[0] + .buildingType + + _mappingOffset)] + .requiredGold; int _aicOffset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - _pDelay = &DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay; + _pDelay = &DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay; *_pDelay = *_pDelay + 1; - if ((_requiredGold <= DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] + *(int*)((int)this + _aicOffset + 0x118)) - && (*(int*)((int)this + _aicOffset + 0x11c) <= DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay)) { - int _y = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_location]; - int _placeTile = _location - DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; + if ((_requiredGold <= DAT_GameState::instance.playerDataArray[playerID] + .currentResources[0xf] + + *(int*)((int)this + _aicOffset + 0x118)) + && (*(int*)((int)this + _aicOffset + 0x11c) + <= DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay)) { + int _y = (int)DAT_ViewportRenderState::instance + .DAT_TileTranslationMatrix_YComponent[_location]; + int _placeTile = _location + - DAT_ViewportRenderState::instance.translationMatrix[_y] + .addXgetTile; if (_siegeInfoIndex < 2) { - int _spawnedUnit = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::spawnUnit, DAT_UnitsState::ptr)(playerID, playerID, _placeTile * 8 + 4, _y * 8 + 4, (int)((int)(DAT_BuildingsState::instance.buildings[_existingBuildingID].terrainHeightUnk)), _unitType); - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].unitID = _spawnedUnit; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].uid = DAT_UnitsState::instance.units[_spawnedUnit].uid; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].buildingID = 0; - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processPlacementResourceLossForBuildingType, DAT_BuildingsState::ptr)(playerID, (BuildingType)((int)(DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex].buildingType)), 0); + int _spawnedUnit = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::spawnUnit, + DAT_UnitsState::ptr)(playerID, playerID, _placeTile * 8 + 4, + _y * 8 + 4, + (int)((int)(DAT_BuildingsState::instance + .buildings[_existingBuildingID] + .terrainHeightUnk)), + _unitType); + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .unitID = _spawnedUnit; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .uid = DAT_UnitsState::instance.units[_spawnedUnit].uid; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .buildingID = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: + processPlacementResourceLossForBuildingType, + DAT_BuildingsState::ptr)(playerID, + (BuildingType)((int)(DAT_SkirmishDefinedData::instance + .SiegeEngineMetaInfoArray[_siegeInfoIndex] + .buildingType)), + 0); } else { - MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID, _placeTile, _y, (CommandBuildingType)((int)((uint)(ushort)(short)DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeInfoIndex].commandBuildingType)), 3, 0xf); + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, + DAT_TileMapState::ptr)(playerID, _placeTile, _y, + (CommandBuildingType)(( + int)((uint)(ushort)(short)DAT_SkirmishDefinedData::instance + .SiegeEngineMetaInfoArray[_siegeInfoIndex] + .commandBuildingType)), + 3, 0xf); if (DAT_TileMapState::instance.buildingPlacementFail == FALSE) { - int* _pGold = DAT_GameState::instance.playerDataArray[playerID].currentResources + 0xf; + int* _pGold = DAT_GameState::instance.playerDataArray[playerID] + .currentResources + + 0xf; *_pGold = *_pGold - _requiredGold; - int _newBuildingID = DAT_TileMapState::instance.DAT_PlacedBuildingID; - int _newUID = DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.DAT_PlacedBuildingID].uid; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].unitID = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].uid = _newUID; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex].buildingID = _newBuildingID; + int _newBuildingID + = DAT_TileMapState::instance.DAT_PlacedBuildingID; + int _newUID = DAT_BuildingsState::instance + .buildings[DAT_TileMapState::instance + .DAT_PlacedBuildingID] + .uid; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .unitID = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .uid = _newUID; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] + .buildingID = _newBuildingID; } } - *(undefined4*)(playerID * 0x39f4 + 0x115f48c + _slotIndex * 20 + _siegeInfoIndex * 100) = 0; + *(undefined4*)(playerID * 0x39f4 + 0x115f48c + _slotIndex * 20 + + _siegeInfoIndex * 100) = 0; return; } } } else { - int _requiredEngineerCount = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, DAT_BuildingsState::ptr)(_tile); - if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount != _requiredEngineerCount) { - if (_requiredEngineerCount <= DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { - int _engineersTribe = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _requiredEngineerCount); - DAT_TribesState::instance.tribes[_engineersTribe].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; - DAT_TribesState::instance.tribes[_engineersTribe].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(_engineersTribe, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); + int _requiredEngineerCount + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: + getRequiredEngineerCountForSiegeBuilding, + DAT_BuildingsState::ptr)(_tile); + if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount + != _requiredEngineerCount) { + if (_requiredEngineerCount + <= DAT_GameState::instance.playerDataArray[playerID] + .engineerCountRelated) { + int _engineersTribe = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, + this)(playerID, _requiredEngineerCount); + DAT_TribesState::instance.tribes[_engineersTribe].tribeType + = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_engineersTribe].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, + DAT_TribesState::ptr)(_engineersTribe, + OpenSHC::Map::Units:: + UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, + _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); return; } DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; @@ -140,33 +223,71 @@ namespace AI { } } else { if (_tile != 0) { - int _requiredEngineerCount2 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, DAT_BuildingsState::ptr)(_tile); - if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount != _requiredEngineerCount2) { - if (_requiredEngineerCount2 <= DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { - int _engineersTribe2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _requiredEngineerCount2); - DAT_TribesState::instance.tribes[_engineersTribe2].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; - DAT_TribesState::instance.tribes[_engineersTribe2].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(_engineersTribe2, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); + int _requiredEngineerCount2 + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: + getRequiredEngineerCountForSiegeBuilding, + DAT_BuildingsState::ptr)(_tile); + if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount + != _requiredEngineerCount2) { + if (_requiredEngineerCount2 + <= DAT_GameState::instance.playerDataArray[playerID] + .engineerCountRelated) { + int _engineersTribe2 = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, + this)(playerID, _requiredEngineerCount2); + DAT_TribesState::instance.tribes[_engineersTribe2].tribeType + = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_engineersTribe2].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, + DAT_TribesState::ptr)(_engineersTribe2, + OpenSHC::Map::Units:: + UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, + _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); return; } DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; } } else { - int _remainingRequiredEngineers = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, DAT_UnitsState::ptr)(_unitID); + int _remainingRequiredEngineers = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, + DAT_UnitsState::ptr)(_unitID); if (0 < _remainingRequiredEngineers) { - if (DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated < _remainingRequiredEngineers) { - DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; + if (DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated + < _remainingRequiredEngineers) { + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired + = TRUE; } else { - int _tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)(playerID, _remainingRequiredEngineers); - int _targetUnitID = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; + int _tribeID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, + this)(playerID, _remainingRequiredEngineers); + int _targetUnitID = (int)DAT_TribesState::instance.tribes[_tribeID] + .selectionTargetUnitID; if ((_targetUnitID != 0) - && (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)(playerID, - (dword)((int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[_unitID].tile])), - (dword)((int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[_targetUnitID].tile])), - 0) != 0)) { - DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; - DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x41c; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(_tribeID, OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, _unitID, DAT_UnitsState::instance.units[_unitID].uid, 0); + && (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func:: + calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance + .units[_unitID] + .tile])), + (dword)((int)((int)(short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance + .units[_targetUnitID] + .tile])), + 0) + != 0)) { + DAT_TribesState::instance.tribes[_tribeID].tribeType + = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x41c; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, + DAT_UnitsState::ptr)(_tribeID, + OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, _unitID, + DAT_UnitsState::instance.units[_unitID].uid, 0); return; } } @@ -174,18 +295,38 @@ namespace AI { } } } else { - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unknown = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unknown = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID = 0; } } else { - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unitID = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].uid = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].delay = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].unknown = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[0][_engineIndex].buildingID = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unitID = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .uid = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .delay = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .unknown = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[0][_engineIndex] + .buildingID = 0; } } diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp index 32b7b3685..f1a374dc6 100644 --- a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -45,21 +45,24 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = iVar4 + -1; } - // Helper: do the movement command given a tile - // (was shared LAB_004d2d8d block) - #define DO_MOVE_TO_TILE(_tile, _tribeID3) \ - do { \ - if ((_tile) != 0) { \ - short sVar2_ = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[(_tile)]; \ - int iVar4_ = DAT_ViewportRenderState::instance.translationMatrix[sVar2_].addXgetTile; \ - BOOLEnum BVar5_ = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)((_tribeID3), (_tile)); \ - if (BVar5_ == FALSE) { \ - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)((_tribeID3), playerID); \ - } else { \ - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)((_tribeID3), (uint)((int)((_tile) - iVar4_)), (uint)((int)((int)sVar2_)), 0); \ - } \ - } \ - } while(0) +// Helper: do the movement command given a tile +// (was shared LAB_004d2d8d block) +#define DO_MOVE_TO_TILE(_tile, _tribeID3) \ + do { \ + if ((_tile) != 0) { \ + short sVar2_ = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[(_tile)]; \ + int iVar4_ = DAT_ViewportRenderState::instance.translationMatrix[sVar2_].addXgetTile; \ + BOOLEnum BVar5_ = MACRO_CALL_MEMBER( \ + OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)((_tribeID3), (_tile)); \ + if (BVar5_ == FALSE) { \ + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)((_tribeID3), playerID); \ + } else { \ + MACRO_CALL_MEMBER( \ + OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( \ + (_tribeID3), (uint)((int)((_tile) - iVar4_)), (uint)((int)((int)sVar2_)), 0); \ + } \ + } \ + } while (0) short* _ptrTribeID3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xb4; @@ -77,7 +80,8 @@ namespace AI { if ((DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2) && (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) != 0)) { + DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) + != 0)) { if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) { _buildingID_2 = MACRO_CALL_MEMBER( @@ -105,7 +109,8 @@ namespace AI { } } - } else if ((DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown == 0) + } else if ((DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + == 0) && (iVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(_aiType + -1, playerID), DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk < iVar4)) { @@ -130,7 +135,8 @@ namespace AI { _buildingID_2 = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); if (_buildingID_2 != 0) { - _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + _buildingTile + = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX + DAT_ViewportRenderState::instance .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] .buildingEntryY] @@ -140,8 +146,8 @@ namespace AI { } } - } else if ((DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb6) - || (DAT_SkirmishDefinedData::instance.DAT_TribeTypeID[_indexTo6] == 0xb5)) { + } else if ((DAT_SkirmishDefinedData::instance.TribeTypeID[_indexTo6] == 0xb6) + || (DAT_SkirmishDefinedData::instance.TribeTypeID[_indexTo6] == 0xb5)) { if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( @@ -155,8 +161,8 @@ namespace AI { if (_buildingID == 0) { _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, - this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); } if (_buildingID != 0) { @@ -170,8 +176,8 @@ namespace AI { } } else { - BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, FALSE); + BVar5 + = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID3, _indexTo6, FALSE); if (BVar5 == FALSE) { iVar4 = (int)DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID; if ((((iVar4 == 0) @@ -182,11 +188,12 @@ namespace AI { _tribeID3, _indexTo6, TRUE), BVar5 == FALSE)) { iVar4 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, - this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); if (iVar4 == 0) { DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + = 0; } else { MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(_tribeID3, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, iVar4, @@ -194,12 +201,14 @@ namespace AI { int iVar3 = DAT_BuildingsState::instance.buildings[iVar4].uid; DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = (short)iVar4; DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID = iVar3; - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 100; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + = 100; } } else { if (DAT_GameState::instance.mapAndTime.yearChanged != 0) DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 100; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown + = 100; } } } @@ -209,7 +218,7 @@ namespace AI { _indexTo6 = _indexTo6 + TRUE; } while ((int)_indexTo6 < 6); - #undef DO_MOVE_TO_TILE +#undef DO_MOVE_TO_TILE } } } diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp index ba171bf29..810c29fce 100644 --- a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -21,8 +21,7 @@ namespace AI { return; for (int _index1 = 0; _index1 < 11; _index1++) { - int* _mappingPtr - = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[_index1] + 1; + int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index1] + 1; int const _maxTribeCount = *_mappingPtr; int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr - 1))[0]; int _tribeIndex = 0; diff --git a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp index 9a0ea9e4e..900f0e7ad 100644 --- a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp +++ b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp @@ -48,7 +48,7 @@ namespace AI { do { - resourceType = DAT_SkirmishDefinedData::instance.DAT_ResourceAcqusitionPreferenceOrder[param_1]; + resourceType = DAT_SkirmishDefinedData::instance.ResourceAcquisitionPreferenceOrder[param_1]; if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0) || (0xb < param_1)) { diff --git a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp index b180166d0..73e758d0c 100644 --- a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp +++ b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp @@ -38,19 +38,22 @@ namespace AI { if (0 < _chosenBuildingTypeIndex) { - BuildingTypeInt _buildingType = - (BuildingTypeInt)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType; + BuildingTypeInt _buildingType + = (BuildingTypeInt)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType; do { BuildingTypeInt _cmpType; if (_rng < 2) { - _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet3[_selectionIndex]; + _cmpType + = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet3[_selectionIndex]; } else if (_rng < 4) { - _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet2[_selectionIndex]; + _cmpType + = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet2[_selectionIndex]; } else { - _cmpType = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_selectionIndex]; + _cmpType + = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1[_selectionIndex]; } if (_buildingType == _cmpType) { diff --git a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp index 91ef8a70c..86ca327e0 100644 --- a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp +++ b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp @@ -23,11 +23,9 @@ namespace AI { if (_index != 8) { - int _groupCount - = DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[_index][1]; + int _groupCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index][1]; - int _tribeType - = DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[_index][0]; + int _tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index][0]; int _offset = 0; diff --git a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp index 548106804..2cdeef7f8 100644 --- a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp @@ -33,8 +33,7 @@ namespace AI { if (DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) { - _ptrTribeCount - = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + _ptrTribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp index 2420b23f2..7059f8a9f 100644 --- a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -16,20 +16,20 @@ namespace AI { { uint local_8 = 0; uint local_4 = 0; - int* local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + int* local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; bool _found = false; do { int iVar2 = 0; if (0 < *local_c) { - short* psVar3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs - + (*(int (*)[2])(local_c + -1))[0]; + short* psVar3 + = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + (*(int (*)[2])(local_c + -1))[0]; do { int iVar1 = (int)*psVar3; if ((iVar1 != 0) && (DAT_TribesState::instance.tribes[iVar1].uid == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[iVar2 + (*(int (*)[2])(local_c + -1))[0]])) { + .aiTribeUIDs[iVar2 + (*(int (*)[2])(local_c + -1))[0]])) { iVar2 = (int)DAT_TribesState::instance.tribes[iVar1].selectionTargetUnitID; local_8 = (uint)DAT_UnitsState::instance.units[iVar2].x; local_4 = (uint)DAT_UnitsState::instance.units[iVar2].y; diff --git a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp index bc11333dd..1fddcaf46 100644 --- a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp +++ b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp @@ -55,7 +55,7 @@ namespace AI { _siegeIndex = 3; } - iVar2 = DAT_SkirmishDefinedData::instance.DAT_SiegeEngineMetaInfoArray[_siegeIndex].slot; + iVar2 = DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[_siegeIndex].slot; _goal = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[iVar2]; diff --git a/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp index 5cb3f087a..cd9b3b5e1 100644 --- a/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp +++ b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp @@ -81,7 +81,7 @@ namespace AI { if (_candidateBuilding != 0) { - _pTargets = DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1; + _pTargets = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1; do { diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp index b9bce3061..4e463ac1d 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp @@ -42,8 +42,7 @@ namespace AI { _counter = 0; - _ptrGroupCount - = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + _ptrGroupCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { diff --git a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp index 4c1c47ab2..7d2f22ddc 100644 --- a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp +++ b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp @@ -42,7 +42,7 @@ namespace AI { if ((DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) && (DAT_GameState::instance.playerDataArray[param_1].someTile != 0)) { - local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp index eaaa3fd90..4e4a6a0e2 100644 --- a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -24,8 +24,7 @@ namespace AI { int _destIndex = 0; for (int _index = 0; _index < 11; _index++) { - int* _mappingPtr - = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[_index] + 1; + int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index] + 1; int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr + -1))[0]; int _tribeIndex = 0; diff --git a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp index 8d942cd2a..e98776b56 100644 --- a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp +++ b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp @@ -47,7 +47,7 @@ namespace AI { _movingFewerThan20Percent = 0; - _ptrSize = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + _ptrSize = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { diff --git a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp index a6a3f9d47..2ecd26042 100644 --- a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp @@ -29,7 +29,7 @@ namespace AI { int _tribeTotal = 0; int _notReallyMoving = 0; - int* local_c = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + int* local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { int iVar2 = (*(int (*)[2])(local_c + -1))[0]; @@ -68,8 +68,8 @@ namespace AI { } while ((int)local_c < 0xb42a2c); if (0 < _tribeTotal) { - return (BOOLEnum)((_notReallyMoving * 100) / _tribeTotal - >= *(int*)((int)this + _aiTypeMinus1 * 0x2a4 + 0x200)); + return ( + BOOLEnum)((_notReallyMoving * 100) / _tribeTotal >= *(int*)((int)this + _aiTypeMinus1 * 0x2a4 + 0x200)); } return FALSE; diff --git a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp index c9ffdb38b..24deba5fb 100644 --- a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp +++ b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp @@ -72,7 +72,7 @@ namespace AI { /* clear out flags */ - piVar1 = DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[0] + 1; + piVar1 = DAT_SkirmishDefinedData::instance.attackUnitRequired[0] + 1; do { @@ -97,7 +97,7 @@ namespace AI { _index = 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[0][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[0][1] = 1; } _maxDiggingUnits = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttDiggingUnitMax; @@ -108,7 +108,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[1][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[1][1] = 1; } _maxAssassins = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxAssassins; @@ -118,7 +118,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[2][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[2][1] = 1; } _maxUnit2 = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnit2Max; @@ -127,7 +127,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[3][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[3][1] = 1; } _maxLaddermen = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxLaddermen; @@ -137,7 +137,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[4][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[4][1] = 1; } _maxTunnelers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxTunnelers; @@ -147,7 +147,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[5][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[5][1] = 1; } _maxUnitPatrol = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitPatrolMax; @@ -157,7 +157,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[6][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[6][1] = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitBackupMax; @@ -167,7 +167,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[7][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[7][1] = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitEngageMax; @@ -177,7 +177,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[8][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[8][1] = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitSiegeDefMax; @@ -187,7 +187,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[9][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[9][1] = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxDefault; @@ -197,7 +197,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[10][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[10][1] = 1; } if (_index != 0) { @@ -210,12 +210,11 @@ namespace AI { do { - if (DAT_SkirmishDefinedData::instance.DAT_AIBehaviourTypeUnitRequired[_index2][1] != 0) { + if (DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2][1] != 0) { if (_rng == 0) { - return (AIUnitBehaviourType)(DAT_SkirmishDefinedData::instance - .DAT_AIBehaviourTypeUnitRequired[_index2][0]); + return (AIUnitBehaviourType)(DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2][0]); } _rng = _rng + -1; diff --git a/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp index 1b1c2239a..75b65a9ec 100644 --- a/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp +++ b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp @@ -46,7 +46,7 @@ namespace AI { do { if ((int)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType - == DAT_SkirmishDefinedData::instance.buildingTargetPrioritySet1[_loopCounter]) { + == DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1[_loopCounter]) { /* fancy break statement? */ diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp index f4283f86e..f0ef6d940 100644 --- a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -27,7 +27,7 @@ namespace AI { return; int iVar3 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - AIResourceTradeCategoryInt* local_18 = &DAT_SkirmishDefinedData::instance.DAT_AIResourceTradeAICMapping[0].aic; + AIResourceTradeCategoryInt* local_18 = &DAT_SkirmishDefinedData::instance.AIResourceTradeAICMapping[0].aic; do { ResourceType resourceType diff --git a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp index 83b899711..7b01dc9c3 100644 --- a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp +++ b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp @@ -42,7 +42,7 @@ namespace AI { _enclosed = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)( playerID); - _ptr = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_GroundUnits[0].aivUnitType; + _ptr = &DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[0].aivUnitType; do { diff --git a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp index 429bb500b..5e202cb21 100644 --- a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp +++ b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp @@ -21,8 +21,7 @@ namespace AI { { - AIVUnitTypeInt* _ptr - = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_RangedUnits[0].aivUnitType; + AIVUnitTypeInt* _ptr = &DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[0].aivUnitType; do { diff --git a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp index 6870e8369..66d46dc78 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp @@ -67,8 +67,7 @@ namespace AI { _defendingLordIndex = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID); - _ptrGroupCount - = (int (*)[2])(DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping[0] + 1); + _ptrGroupCount = (int (*)[2])(DAT_SkirmishDefinedData::instance.MaxBreachTribes[0] + 1); do { diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index 4c4593028..3413b2634 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -40,7 +40,7 @@ namespace AI { _ghX = _gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[_ghY].addXgetTile; } - int* _mappingPtr = DAT_SkirmishDefinedData::instance.DAT_AttackTribes_AITribeType_MaxTribeCount_Mapping[0] + 1; + int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; do { int const _maxTribeCount = *_mappingPtr; diff --git a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp index b5d4cdd8e..6683a5696 100644 --- a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp +++ b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp @@ -61,7 +61,7 @@ namespace AI { /* defWallPatrolGroups */ - _ptr = &DAT_SkirmishDefinedData::instance.AIVUnitTypeMaxLocationPairArray_PatrolUnits[0].aivUnitType; + _ptr = &DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[0].aivUnitType; do { diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp index 086bf9485..02619dda4 100644 --- a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -25,7 +25,7 @@ namespace AI { if ((iVar3 < iVar6) && (((unitType == 0x8 || (unitType == 0xa)) || (unitType == 0x11)))) { iVar6 = iVar3; } - iVar3 = DAT_SkirmishDefinedData::instance.DAT_AiTribeIDOffsetForUnitType[(int)unitType]; + iVar3 = DAT_SkirmishDefinedData::instance.AITribeIDOffsetForUnitType[(int)unitType]; if (0 < iVar6) { short* _aiTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar3; do { diff --git a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp index 7a9a56b30..43f52c12f 100644 --- a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp +++ b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp @@ -133,8 +133,8 @@ namespace AI { do { iVar3 = iVar3 - + DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping - [DAT_GameState::instance.playerDataArray[aiStack_24[iVar4]].aiType + + DAT_SkirmishDefinedData::instance + .MaxBreachTribes[DAT_GameState::instance.playerDataArray[aiStack_24[iVar4]].aiType + OpenSHC::AI::AIT_FREDERICK][0]; iVar4 = iVar4 + 1; @@ -156,15 +156,15 @@ namespace AI { iVar3 = aiStack_24[iVar4]; iVar5 = iVar5 - - DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping - [DAT_GameState::instance.playerDataArray[iVar3].aiType + - DAT_SkirmishDefinedData::instance + .MaxBreachTribes[DAT_GameState::instance.playerDataArray[iVar3].aiType + OpenSHC::AI::AIT_FREDERICK][0]; if (iVar5 < 0) { DAT_GameSynchronyState::instance.DAT_ChatTauntOrMessage = -2 - - DAT_SkirmishDefinedData::instance.DAT_BreachTribeTypes_TribeGroupCount_Mapping - [DAT_GameState::instance.playerDataArray[iVar3].aiType + - DAT_SkirmishDefinedData::instance + .MaxBreachTribes[DAT_GameState::instance.playerDataArray[iVar3].aiType + OpenSHC::AI::AIT_FREDERICK][1]; DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[1] = 1; diff --git a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp index eda86856b..ff18d5cb7 100644 --- a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp +++ b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp @@ -18,10 +18,10 @@ namespace AI { SkirmishDefinedData* pSVar1 = DAT_SkirmishDefinedData::ptr; do { - if (pSVar1->DAT_UnitTypes_RangedAndArmored[0] == _unitType) + if (pSVar1->RangedAndArmoredUnits[0] == _unitType) return (undefined4)(1); - pSVar1 = (SkirmishDefinedData*)(pSVar1->DAT_UnitTypes_RangedAndArmored + 1); + pSVar1 = (SkirmishDefinedData*)(pSVar1->RangedAndArmoredUnits + 1); } while ((int)pSVar1 < 0xb3eb50); diff --git a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp index 8011403c9..b5ec39df2 100644 --- a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp +++ b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp @@ -92,10 +92,10 @@ namespace AI { do { - if (*piVar4 == DAT_SkirmishDefinedData::instance.DAT_SiegeEngineUnitType[iVar2]) { + if (*piVar4 == DAT_SkirmishDefinedData::instance.SiegeEngineUnitType[iVar2]) { _requiredEngineers - = DAT_SkirmishDefinedData::instance.DAT_SiegeEngineTypeRequiredEngineers[iVar2]; + = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[iVar2]; break; } @@ -146,13 +146,13 @@ namespace AI { do { if (*_siegeEngineUnitType - == DAT_SkirmishDefinedData::instance.DAT_SiegeEngineUnitType[_counterTill6]) { + == DAT_SkirmishDefinedData::instance.SiegeEngineUnitType[_counterTill6]) { - _requiredEngineers = DAT_SkirmishDefinedData::instance - .DAT_SiegeEngineTypeRequiredEngineers[_counterTill6]; + _requiredEngineers + = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[_counterTill6]; _siegeEngineType = (CommandBuildingType)DAT_SkirmishDefinedData::instance - .DAT_SiegeEngineCommandBuildingTypes[_counterTill6]; + .SiegeEngineCommandBuildingTypes[_counterTill6]; break; } From bf7676ceef1956f7037d1032ead9ed5e247e4ff1 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 12:12:34 +0200 Subject: [PATCH 039/242] improve readability and fit --- .../AICState/aiCommandSiegeEngineTribes.cpp | 2 +- .../AI/AICState/aiCreateSiegeUnits.cpp | 2 +- .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 2 +- .../AI/AICState/aiGiveRaidInstructions.cpp | 2 +- src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 57 +++++++------- .../AICState/computeEnemyKeepApproachTile.cpp | 6 +- .../AICState/decideOnTribeAttackLocation.cpp | 34 +++++---- ...ndAttackTribePositionAndPathToDefenses.cpp | 2 +- .../AICState/moveAttackTribesToLocations.cpp | 52 ++++++------- .../AICState/sendTribeToAIVLocationSlot.cpp | 6 +- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 75 +++++++++---------- 11 files changed, 112 insertions(+), 128 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp index f4a02fbcf..4d458992a 100644 --- a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp @@ -175,7 +175,7 @@ namespace AI { if (0 < _tile) { - y1 = (uint)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + y1 = (uint)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; x1 = _tile - DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index c5e339c24..fb783db4b 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -129,7 +129,7 @@ namespace AI { .aiSiegeCreationInformation[0][_engineIndex] .delay)) { int _y = (int)DAT_ViewportRenderState::instance - .DAT_TileTranslationMatrix_YComponent[_location]; + .tileTranslationMatrix_YComponent[_location]; int _placeTile = _location - DAT_ViewportRenderState::instance.translationMatrix[_y] .addXgetTile; diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp index a48ad6d5f..90ab12ecd 100644 --- a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -70,7 +70,7 @@ namespace AI { .addXgetTile; } if (_hasTarget && _tile != 0) { - sVar2 = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + sVar2 = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; iVar3 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; _canNavigate = MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( _tribeID, _tile); diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp index f1a374dc6..eaf785544 100644 --- a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -50,7 +50,7 @@ namespace AI { #define DO_MOVE_TO_TILE(_tile, _tribeID3) \ do { \ if ((_tile) != 0) { \ - short sVar2_ = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[(_tile)]; \ + short sVar2_ = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[(_tile)]; \ int iVar4_ = DAT_ViewportRenderState::instance.translationMatrix[sVar2_].addXgetTile; \ BOOLEnum BVar5_ = MACRO_CALL_MEMBER( \ OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)((_tribeID3), (_tile)); \ diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp index 810c29fce..a80d00659 100644 --- a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -21,42 +21,35 @@ namespace AI { return; for (int _index1 = 0; _index1 < 11; _index1++) { - int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index1] + 1; - int const _maxTribeCount = *_mappingPtr; - int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr - 1))[0]; + int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index1].tribeType; int _tribeIndex = 0; - - if (0 < _maxTribeCount) { - - for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { - int const _tribeID - = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - if (_tribeTypeStart == 0xbe) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, playerID); - } else if (_tribeTypeStart == 0xd) { + int const _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index1].tribeCount; + + for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { + int const _tribeID + = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart + _tribeIndex]; + + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_tribeTypeStart + _tribeIndex])) { + + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + if (_tribeTypeStart == 0xbe) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); + } else if (_tribeTypeStart == 0xd) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); + } else { + int const _hasHorses + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + if (_hasHorses != FALSE) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( _tribeID, playerID); } else { - int const _hasHorses - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, - DAT_TribesState::ptr)(_tribeID); - if (_hasHorses != FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, playerID); - } else { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( - _tribeID, playerID); - } + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); } } } diff --git a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp index 3143812d5..e833529d0 100644 --- a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp +++ b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp @@ -76,9 +76,9 @@ namespace AI { _tile - DAT_ViewportRenderState::instance .translationMatrix[DAT_ViewportRenderState::instance - .DAT_TileTranslationMatrix_YComponent[_tile]] + .tileTranslationMatrix_YComponent[_tile]] .addXgetTile, - (int)((int)(DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]))); + (int)((int)(DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]))); /* avoiding unit death areas */ @@ -126,7 +126,7 @@ namespace AI { if (0 < _shortestDistanceTile) { - _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_shortestDistanceTile]; + _y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_shortestDistanceTile]; DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY = (int)_y; diff --git a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp index 5e71e48dc..5d078d371 100644 --- a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp +++ b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp @@ -54,11 +54,12 @@ namespace AI { int _unitID = MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::getUnitIDForIndexInTribe, DAT_TribesState::ptr)(_tribeID, 0); if ((_unitID != 0) - && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, + && MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[_tribeID].owner, _targetPlayer, (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), - (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), (byte*)&tribeID_OR_moatWasHit, - &_x, &_y)) { + (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), (byte*)&tribeID_OR_moatWasHit, &_x, + &_y)) { if ((char)tribeID_OR_moatWasHit != '\0') { MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( _tribeID, ((UnitInstructionType)0x23), @@ -91,8 +92,9 @@ namespace AI { return; } - int _buildingID = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, - DAT_GameState::ptr)(_targetPlayer); + int _buildingID + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + DAT_GameState::ptr)(_targetPlayer); if (_buildingID != 0) { MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( _tribeID, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, _buildingID, @@ -116,8 +118,9 @@ namespace AI { return; } - int _buildingID_2 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, - DAT_GameState::ptr)(_targetPlayer); + int _buildingID_2 + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + DAT_GameState::ptr)(_targetPlayer); int _destinationTile; int _destinationX2; @@ -125,8 +128,8 @@ namespace AI { if (_buildingID_2 == 0) { int iVar5 = DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] - .addXgetTile; + .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] + .addXgetTile; _destinationTile = iVar5 + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; } else { int iVar5 = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; @@ -145,16 +148,19 @@ namespace AI { if (DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper == 0) { // was LAB_004d1d11 int iVar5b = DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] - .addXgetTile; - _destinationTile = iVar5b + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; + .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer] + .campground.yEntry] + .addXgetTile; + _destinationTile + = iVar5b + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; } } } if (_destinationTile != 0) { - _destinationY2 = (int)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_destinationTile]; - _destinationX2 = _destinationTile - DAT_ViewportRenderState::instance.translationMatrix[_destinationY2].addXgetTile; + _destinationY2 = (int)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_destinationTile]; + _destinationX2 + = _destinationTile - DAT_ViewportRenderState::instance.translationMatrix[_destinationY2].addXgetTile; BOOLEnum BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( _tribeID, _destinationTile); if (BVar4 != FALSE) { diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp index 7059f8a9f..d8525fab9 100644 --- a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -55,7 +55,7 @@ namespace AI { OpenSHC::Map::Navigation::PathFindingState_Func::tracePathToFriendlyDefensesAndReturnTileUnk, DAT_PathFindingState::ptr)(playerID, local_8, local_4); if (0 < _tile) { - short _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + short _y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; DAT_GameState::instance.playerDataArray[playerID].someTile = _tile; int iVar2 = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; DAT_GameState::instance.playerDataArray[playerID].someY = (int)_y; diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp index 4e4a6a0e2..6de76caf0 100644 --- a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -24,43 +24,35 @@ namespace AI { int _destIndex = 0; for (int _index = 0; _index < 11; _index++) { - int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index] + 1; - - int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr + -1))[0]; + int const _tribeTypeStart = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; int _tribeIndex = 0; - int const _maxTribeCount = *_mappingPtr; - - if (0 < _maxTribeCount) { - short* _tribeIDPtr = &DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart]; - - do { - int const _tribeID = (int)*_tribeIDPtr; + int const _maxTribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { + for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + int const _tribeID + = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(_tribeID, - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] - .xOffset)), - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] - .yOffset)), - 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { - _destIndex = _destIndex + 1; - } + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - _tribeIDPtr = _tribeIDPtr + 1; - _tribeIndex = _tribeIndex + 1; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] + .xOffset)), + (uint)((int)(DAT_GameState::instance.mapAndTime + .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] + .yOffset)), + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - } while (_tribeIndex < _maxTribeCount); + _destIndex = _destIndex + 1; + } } } } diff --git a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp index 73e501ba0..2d8aad2b4 100644 --- a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp @@ -32,11 +32,11 @@ namespace AI { if (_slotIndex <= 9) _tile = DAT_GameState::instance.playerDataArray[_owner].aivUnitLocationSlots[aivUnitType][_slotIndex]; - short _y = DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_tile]; + short _y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; int _x = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; - BOOLEnum _canNavigate = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, _tile); + BOOLEnum _canNavigate + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, _tile); if (_canNavigate == FALSE) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, _owner); diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index 3413b2634..4ad45f3f1 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -36,65 +36,58 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID1].requestStateUnk = 0; return; } - _ghY = (uint)DAT_ViewportRenderState::instance.DAT_TileTranslationMatrix_YComponent[_gatehouseTile]; + _ghY = (uint)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_gatehouseTile]; _ghX = _gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[_ghY].addXgetTile; } - int* _mappingPtr = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + int* _mappingPtr = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; - do { - int const _maxTribeCount = *_mappingPtr; - int const _tribeTypeStart = (*(int (*)[2])(_mappingPtr - 1))[0]; + for (int _index = 0; _index < 11; _index++) { + int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; int _tribeIndex = 0; + int const _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - if (0 < _maxTribeCount) { - short* _tribeIDPtr = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs + _tribeTypeStart; + for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { - do { - int const _tribeID = (int)*_tribeIDPtr; + int const _tribeID + = (int)DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID1] - .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID1] + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + DAT_TribesState::instance.tribes[_tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - int const _canNav2 - = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID1, playerID2); + int const _canNav2 + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID1, playerID2); - if (_canNav2 != FALSE) { - if (_tribeTypeStart == 0xbe) { + if (_canNav2 != FALSE) { + if (_tribeTypeStart == 0xbe) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( + _tribeID, playerID2); + } else { + int const _hasHorses + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(_tribeID); + if (_hasHorses != FALSE) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( _tribeID, playerID2); } else { - int const _hasHorses - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, - DAT_TribesState::ptr)(_tribeID); - if (_hasHorses != FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, playerID2); - } else { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( - _tribeID, playerID2); - } + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( + _tribeID, playerID2); } - } else { - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - _tribeID, _ghX, _ghY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); } + } else { + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + _tribeID, _ghX, _ghY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); } - - _tribeIDPtr = _tribeIDPtr + 1; - _tribeIndex = _tribeIndex + 1; - } while (_tribeIndex < _maxTribeCount); + } } - - _mappingPtr = _mappingPtr + 2; - } while ((int)_mappingPtr < 0xb42a2c); + } } } } From bbed0b43773cd7f3c76caaffc8b10e3b69bd92e6 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 12:41:00 +0200 Subject: [PATCH 040/242] as best as we can --- .../AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index 4ad45f3f1..00653f14a 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -16,6 +16,11 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; + /** + * I seem unable to make this match better than 75.42% even though this function flow is dumb: _ghX and _ghY are + * only specified if not navigatable, which is checked twice for some reason. + */ + // FUNCTION: STRONGHOLDCRUSADER 0x004CE5F0 void AICState::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, int playerID2) { @@ -40,8 +45,6 @@ namespace AI { _ghX = _gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[_ghY].addXgetTile; } - int* _mappingPtr = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; - for (int _index = 0; _index < 11; _index++) { int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; int _tribeIndex = 0; From 10f33361763442b0ef563828cd31564f40a14a80 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 13:21:15 +0200 Subject: [PATCH 041/242] improve rally percentage --- .../aiChoiceAttForceRallyPercentage.cpp | 73 ++++++------------- 1 file changed, 23 insertions(+), 50 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp index 165cf2937..61e3f3977 100644 --- a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -20,70 +20,43 @@ namespace AI { { - AITypeInt AVar1; + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[param_1].aiType; - int iVar2; - - int iVar3; - - short* psVar4; - - int local_14; - - int local_10; - - int* local_c; - - AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) { + if (_aiType == OpenSHC::AI::AIT_NULL) { return 0; } - local_14 = 0; - - local_10 = 0; - - local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + int _nonMoving = 0; + int _activeTribes = 0; + int _index = 0; + int _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - do { + for (; _index < 11; _index++) { - iVar3 = 0; + int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; + int _tribeIndex = 0; + _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - if (0 < *local_c) { + for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { - psVar4 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + (*(int (*)[2])(local_c + -1))[0]; + int const _tribeID + = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - do { + if (((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid + == DAT_GameState::instance.playerDataArray[param_1] + .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) + && (_activeTribes += 1, DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0x14)) { - iVar2 = (int)*psVar4; - - if (((iVar2 != 0) - && (DAT_TribesState::instance.tribes[iVar2].uid - == DAT_GameState::instance.playerDataArray[param_1] - .aiTribeUIDs[iVar3 + (*(int (*)[2])(local_c + -1))[0]])) - && (local_14 = local_14 + 1, - DAT_TribesState::instance.tribes[iVar2].percentageMovingUnk < 0x14)) { - - local_10 = local_10 + 1; - } - - iVar3 = iVar3 + 1; - - psVar4 = psVar4 + 1; - - } while (iVar3 < *local_c); + _nonMoving += 1; + } } + } - local_c = local_c + 2; - - } while ((int)local_c < 0xb42a2c); - - if (0 < local_14) { + if (0 < _activeTribes) { - return (uint)(*(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x200) - <= (local_10 * 100) / local_14); + return (uint)(((int)this->aics[_aiType - 1].AttForceRallyPercentage) <= (_nonMoving * 100) / _activeTribes); } return 0; From 42c8433fd4784c8ba800e0e99181a0272b192934 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 29 Jul 2026 13:26:25 +0200 Subject: [PATCH 042/242] OpenSHC::AI::AICState::aiChoiceAttForceRallyPercentage 100% --- .../aiChoiceAttForceRallyPercentage.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp index 61e3f3977..1e64d7c93 100644 --- a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -27,18 +27,17 @@ namespace AI { return 0; } - int _nonMoving = 0; + int const _aiIndex = _aiType - 1; int _activeTribes = 0; - int _index = 0; - int _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; + int _nonMoving = 0; - for (; _index < 11; _index++) { + for (int _index = 0; _index < 11; _index++) { int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; - int _tribeIndex = 0; - _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { + int const _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; + + for (int _tribeIndex = 0; _tribeIndex < _maxTribeCount; _tribeIndex++) { int const _tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[_tribeTypeStart + _tribeIndex]; @@ -54,12 +53,12 @@ namespace AI { } } - if (0 < _activeTribes) { + if (_activeTribes <= 0) { - return (uint)(((int)this->aics[_aiType - 1].AttForceRallyPercentage) <= (_nonMoving * 100) / _activeTribes); + return 0; } - return 0; + return (uint)((_nonMoving * 100) / _activeTribes >= (int)this->aics[_aiIndex].AttForceRallyPercentage); } } From 303af5656bac44398aea88eecadd4067b3351be6 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Thu, 30 Jul 2026 00:31:21 +0200 Subject: [PATCH 043/242] slow improvement --- .../AICState/aiCommandSiegeEngineTribes.cpp | 202 +++++------------- 1 file changed, 59 insertions(+), 143 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp index 4d458992a..cee33b455 100644 --- a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp @@ -14,194 +14,110 @@ #include "OpenSHC/Globals/DAT_TroopValueState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" - namespace OpenSHC { namespace AI { - using OpenSHC::Map::Units::SomeTribeBehaviorType; using OpenSHC::Map::Units::Unit; using OpenSHC::Map::Units::UnitLogicState; using OpenSHC::Map::Units::UnitType; using OpenSHC::Map::Units::UnitTypeShort; using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CFCD0 void AICState ::aiCommandSiegeEngineTribes(int playerID) - { - - UnitTypeShort UVar1; - - int iVar2; - - uint x1; - - int _sectionID2; - - int iVar3; - - int iVar4; - - uint y1; - - Unit* local_14; - - int local_c[3]; - - int _tile; - - short _sectionID; - - short _targetUnitID; - - iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xba]; - - iVar4 = 0; - - iVar3 = 0; - - local_c[0] = 0; - - local_c[1] = 0; - - local_c[2] = 0; - - if ((iVar2 != 0) - && (DAT_TribesState::instance.tribes[iVar2].uid + int _targetTribeIDs[3]; + _targetTribeIDs[0] = 0; + _targetTribeIDs[1] = 0; + _targetTribeIDs[2] = 0; + int _validCount = 0; + int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xba]; + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xba])) { - - local_c[0] = iVar2; - - iVar3 = 1; + _targetTribeIDs[0] = _tribeID; + _validCount = 1; } - - iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbb]; - - if ((iVar2 != 0) - && (DAT_TribesState::instance.tribes[iVar2].uid + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbb]; + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbb])) { - - local_c[iVar3] = iVar2; - - iVar3 = iVar3 + 1; + _targetTribeIDs[_validCount] = _tribeID; + _validCount += 1; } - - iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbc]; - - if ((iVar2 != 0) - && (DAT_TribesState::instance.tribes[iVar2].uid + _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbc]; + if ((_tribeID != 0) + && (DAT_TribesState::instance.tribes[_tribeID].uid == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbc])) { - - local_c[iVar3] = iVar2; + _targetTribeIDs[_validCount] = _tribeID; } - - local_14 = &DAT_UnitsState::instance.units[1]; - - do { - - if ((local_14->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) - && ((((UVar1 = local_14->unitType, - UVar1 == OpenSHC::Map::Units::UT_S_TOWER || (UVar1 == OpenSHC::Map::Units::UT_S_BATTERINGRAM)) - || (UVar1 == OpenSHC::Map::Units::UT_S_SHIELD)) - && ((local_14->unknownSiegeTentRelated02 == 3 && (local_14->aiUnitBehaviourType != 0x15)))))) { - - if (UVar1 == OpenSHC::Map::Units::UT_S_TOWER) { - - if ((local_14->tribeID != 0) + int _shieldCount = 0; + for (int _unitID = 1; _unitID < 2500; _unitID++) { + UnitTypeShort _unitType; + if ((DAT_UnitsState::instance.units[_unitID].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) + && ((((_unitType = DAT_UnitsState::instance.units[_unitID].unitType, + _unitType == OpenSHC::Map::Units::UT_S_TOWER + || (_unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM)) + || (_unitType == OpenSHC::Map::Units::UT_S_SHIELD)) + && ((DAT_UnitsState::instance.units[_unitID].unknownSiegeTentRelated02 == 3 + && (DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType != 0x15)))))) { + if (_unitType == OpenSHC::Map::Units::UT_S_TOWER) { + int _engineTribeID = (int)DAT_UnitsState::instance.units[_unitID].tribeID; + if ((_engineTribeID != 0) && (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc + -4) != 0)) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, - DAT_TribesState::ptr)((int)local_14->tribeID, OpenSHC::Map::Units::STBT_0x414); + DAT_TribesState::ptr)(_engineTribeID, OpenSHC::Map::Units::STBT_0x414); } - - } - - else if (UVar1 == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { - - iVar3 = (int)local_14->tribeID; - - if (iVar3 != 0) { - + } else if (_unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { + int _engineTribeID = (int)DAT_UnitsState::instance.units[_unitID].tribeID; + if (_engineTribeID != 0) { if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.gateValuesArray + playerID * 0x177bc + -4) - == 0) { - + != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, + DAT_TribesState::ptr)(_engineTribeID, OpenSHC::Map::Units::STBT_0x3f6); + } else { if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc + -4) != 0) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, - DAT_TribesState::ptr)(iVar3, OpenSHC::Map::Units::STBT_0x413); + DAT_TribesState::ptr)(_engineTribeID, OpenSHC::Map::Units::STBT_0x413); } - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, - DAT_TribesState::ptr)(iVar3, OpenSHC::Map::Units::STBT_0x3f6); } } - - } - - else if (UVar1 == OpenSHC::Map::Units::UT_S_SHIELD) { - - _sectionID = local_14->tribeID; - - _sectionID2 = (int)_sectionID; - - if ((_sectionID2 != 0) && (iVar4 < 3)) { - - iVar3 = local_c[iVar4]; - - DAT_TribesState::instance.tribes[_sectionID2].field56_0x1f2 = (short)iVar3; - - DAT_TribesState::instance.tribes[_sectionID2].uid2 - = DAT_TribesState::instance.tribes[iVar3].uid; - - _targetUnitID = DAT_TribesState::instance.tribes[iVar3].selectionTargetUnitID; - - DAT_TribesState::instance.tribes[iVar3].tribeID = _sectionID; - - _tile = DAT_UnitsState::instance.units[_targetUnitID].tile; - - iVar4 = iVar4 + 1; - - if (0 < _tile) { - - y1 = (uint)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; - - x1 = _tile - DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; - + } else if (_unitType == OpenSHC::Map::Units::UT_S_SHIELD) { + int _shieldTribeID = (int)DAT_UnitsState::instance.units[_unitID].tribeID; + if ((_shieldTribeID != 0) && (_shieldCount < 3)) { + int _targetTribeID = _targetTribeIDs[_shieldCount]; + DAT_TribesState::instance.tribes[_shieldTribeID].field56_0x1f2 = (short)_targetTribeID; + DAT_TribesState::instance.tribes[_shieldTribeID].uid2 + = DAT_TribesState::instance.tribes[_targetTribeID].uid; + int _targetUnitID = (int)DAT_TribesState::instance.tribes[_targetTribeID].selectionTargetUnitID; + DAT_TribesState::instance.tribes[_targetTribeID].tribeID = (short)_shieldTribeID; + int _targetTile = DAT_UnitsState::instance.units[_targetUnitID].tile; + _shieldCount = _shieldCount + 1; + if (0 < _targetTile) { + uint y1 + = (uint)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_targetTile]; + uint x1 = _targetTile - DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - _sectionID2, x1, y1, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - + _shieldTribeID, x1, y1, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: calculatePreferredRelativeOrientation, DAT_DirectionAlgorithmState::ptr)((int)DAT_UnitsState::instance.units[_targetUnitID].x, (int)((int)(DAT_UnitsState::instance.units[_targetUnitID].y)), (int)((int)(x1)), (int)((int)(y1))); - - DAT_TribesState::instance.tribes[_sectionID2].orientation + DAT_TribesState::instance.tribes[_shieldTribeID].orientation = (short)DAT_DirectionAlgorithmState::instance.orientation; } } } } - - local_14 = local_14 + 0x248; - - } while ((int)local_14 < 0x165141a); - - return; + } } - } } From e2924593bed780ca775db20317a7928d8821404c Mon Sep 17 00:00:00 2001 From: sourcehold Date: Thu, 30 Jul 2026 01:13:11 +0200 Subject: [PATCH 044/242] slow improvement --- .../aiCommandTribe11StandGroundToGate.cpp | 40 +++++--- .../aiCommandTribe12AggressiveApproach.cpp | 98 ++++++++++--------- .../aiCommandTribe13DefensiveWave.cpp | 34 ++++--- 3 files changed, 100 insertions(+), 72 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp index 7001fe9cf..ffd86e8ba 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp @@ -13,20 +13,32 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF470 void AICState::aiCommandTribe11StandGroundToGate(int playerID) { - int iVar1; - int iVar2; - if ((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) - && (iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], iVar2 != 0)) - && (DAT_TribesState::instance.tribes[iVar2].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb])) - && (DAT_TribesState::instance.tribes[iVar2].selectionTargetUnitID != 0)) { - DAT_TribesState::instance.tribes[iVar2].unitStance = Map::Units::Behavior::USE_STAND_GROUND; - iVar1 = MACRO_CALL_MEMBER( - Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)(iVar2); - if (iVar1 == 0) { - MACRO_CALL_MEMBER( - Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)(iVar2); - } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return; + } + + int const iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb]; + + if (iVar2 == 0) { + return; + } + + if (DAT_TribesState::instance.tribes[iVar2].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb]) { + return; + } + + if (DAT_TribesState::instance.tribes[iVar2].selectionTargetUnitID == 0) { + return; + } + + DAT_TribesState::instance.tribes[iVar2].unitStance = Map::Units::Behavior::USE_STAND_GROUND; + + if (MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)( + iVar2) + == 0) { + MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)( + iVar2); } } } diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp index e4b5a1359..8dd97308d 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp @@ -23,55 +23,59 @@ namespace AI { decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CF2E0 - void AICState ::aiCommandTribe12AggressiveApproach(int param_1) - + void AICState ::aiCommandTribe12AggressiveApproach(int playerID) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) { + return; + } + + int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xc]; + + if (tribeID == 0) { + return; + } + + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xc]) { + return; + } + + int targetUnitID = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + + if (targetUnitID == 0) { + return; + } - int iVar1; - - BOOLEnum BVar2; - - int tribeID; - - if ((((DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) - && (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xc], tribeID != 0)) - && (DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xc])) - && (iVar1 = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID, iVar1 != 0)) { - - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, - DAT_PathFindingState::ptr)((int)DAT_UnitsState::instance.units[iVar1].x, - (uint)((int)((int)DAT_UnitsState::instance.units[iVar1].y)), -1, -1, 10000, FALSE); - - iVar1 = DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID; - - DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - BVar2 = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)(iVar1, 200); - - if (((BVar2 != FALSE) - || (BVar2 = MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)( - DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, (int)((int)(150))), - BVar2 != FALSE)) - || ((BVar2 - = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)( - DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, 100), - BVar2 != FALSE - || (BVar2 = MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)( - DAT_GameState::instance.playerDataArray[param_1].attackedPlayerID, (int)((int)(50))), - BVar2 != FALSE)))) { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(tribeID, (uint)((int)(DAT_PathFindingState::instance.ALG_ResultX)), - (uint)((int)(DAT_PathFindingState::instance.ALG_ResultY)), 0, 0, - OpenSHC::Map::Units::Instructions::UMSE_0); - } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + DAT_PathFindingState::ptr)((int)DAT_UnitsState::instance.units[targetUnitID].x, + (uint)((int)((int)DAT_UnitsState::instance.units[targetUnitID].y)), -1, -1, 10000, FALSE); + + int attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + // Try progressively smaller search costs; stop at the first one that finds a destination. + // The later probes deliberately re-read attackedPlayerID, as the calls may update it. + if ((MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)(attackedPlayerID, 200) + != FALSE) + || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 150) + != FALSE) + || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 100) + != FALSE) + || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 50) + != FALSE)) { + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, (uint)((int)(DAT_PathFindingState::instance.ALG_ResultX)), + (uint)((int)(DAT_PathFindingState::instance.ALG_ResultY)), 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); } return; diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp index c28d2776b..bf47a5dfa 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp @@ -11,19 +11,31 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF270 - void AICState::aiCommandTribe13DefensiveWave(int param_1) + void AICState::aiCommandTribe13DefensiveWave(int playerID) { - int tribeID; - if ((DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) - && (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xd], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0xd]) - && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { - DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( - tribeID, Map::Units::STBT_0x3f4); - } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return; } + + int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xd]; + + if (tribeID == 0) { + return; + } + + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xd]) { + return; + } + + if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) { + return; + } + + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f4); } } } From 0ce80ca9a98624cdcd93e38b1e6fe26ef332c2c1 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Tue, 4 Aug 2026 00:11:17 +0200 Subject: [PATCH 045/242] integrate main --- .../aiChoiceAttForceRallyPercentage.cpp | 2 +- .../AI/AICState/aiCreateSiegeUnits.cpp | 10 ++-- .../AI/AICState/clearOutdatedAITribes.cpp | 8 +-- .../clearRallyFlagOnAllAIAttackTribes.cpp | 15 ++--- .../AICState/computeAttackPossibilities.cpp | 2 +- .../AICState/computeEnemyKeepApproachTile.cpp | 2 +- .../AICState/destroyAnyBuildingInCategory.cpp | 16 ++--- .../AI/AICState/destroyBuildingIfNoWorker.cpp | 2 +- ...ndAttackTribePositionAndPathToDefenses.cpp | 2 +- .../giveMoveCommandToAttackTribes.cpp | 2 +- ...eUnitsGoDefensiveAndBackToSomeLocation.cpp | 2 +- ...erIsWoodCuttersHutWhileNoWoodAvailable.cpp | 17 ++++++ ...rcentageNonMovingTribesGTEAICSpecified.cpp | 2 +- .../processAttForceRallyPercentage.cpp | 2 +- .../randomlySelectAttackUnitTypeToRecruit.cpp | 31 +++++----- .../recomputeAIPathCostToAttackedKeep.cpp | 2 +- .../AI/AICState/recomputeAIZonerLayer.cpp | 2 +- .../AI/AICState/recomputeAttackAIZone.cpp | 2 +- .../recruitHarrassingSiegeEngines.cpp | 19 +++--- .../AI/AICState/renderDebugDataAiInfo.cpp | 4 +- .../sendUnitsToAttackBreachedCastle.cpp | 2 +- .../AICState/shouldDestroyWoodCutterUnk.cpp | 2 +- .../AICState/shouldNotBeBuildingArmoury.cpp | 6 +- .../AICState/shouldNotBeBuildingGranary.cpp | 6 +- .../AI/AICState/shouldNotBeBuildingHovel.cpp | 6 +- .../AI/AICState/shouldNotBuildKillingPits.cpp | 6 +- ...rketArmoryGranaryBarracksMercenarypost.cpp | 16 +++-- ...uldWaitWithBuildingAPositiveFearFactor.cpp | 60 +++++++++---------- ...ouldWaitWithBuildingNegativeFearFactor.cpp | 30 +++++----- .../AI/AICState/someChatMessageSelection.cpp | 9 ++- .../AI/AICState/updateAIPlayerState.cpp | 6 +- ...12_toPlaceSiegeTentsAndAssignEngineers.cpp | 13 ++-- .../useAITribe_0xe_toPlaceTunnels.cpp | 8 +-- src/OpenSHC/AI/AICState/wipeAICMemory.cpp | 2 +- .../woodCuttersHutWhileNoWoodAvailable.cpp | 17 ------ 35 files changed, 166 insertions(+), 167 deletions(-) create mode 100644 src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp delete mode 100644 src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp index 1e64d7c93..de707eebc 100644 --- a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -16,7 +16,7 @@ namespace AI { decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CEC80 - uint AICState ::aiChoiceAttForceRallyPercentage(int param_1) + BOOLEnum AICState ::aiChoiceAttForceRallyPercentage(int param_1) { diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index fb783db4b..886073a29 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -7,7 +7,7 @@ #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Map/Buildings/BuildingTypeShort.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" @@ -30,7 +30,7 @@ namespace AI { using OpenSHC::AI::AIType; using OpenSHC::AI::AITypeInt; using OpenSHC::AI::Tribes::AITribeType; - using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Commands::MappersEnum; using OpenSHC::Map::Buildings::BuildingType; using OpenSHC::Map::Buildings::BuildingTypeShort; using OpenSHC::Map::Units::SomeTribeBehaviorType; @@ -161,7 +161,7 @@ namespace AI { } else { MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID, _placeTile, _y, - (CommandBuildingType)(( + (MappersEnum)(( int)((uint)(ushort)(short)DAT_SkirmishDefinedData::instance .SiegeEngineMetaInfoArray[_siegeInfoIndex] .commandBuildingType)), @@ -172,10 +172,10 @@ namespace AI { + 0xf; *_pGold = *_pGold - _requiredGold; int _newBuildingID - = DAT_TileMapState::instance.DAT_PlacedBuildingID; + = DAT_TileMapState::instance.placedBuildingID; int _newUID = DAT_BuildingsState::instance .buildings[DAT_TileMapState::instance - .DAT_PlacedBuildingID] + .placedBuildingID] .uid; DAT_GameState::instance.playerDataArray[playerID] .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] diff --git a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp index 86ca327e0..913be6005 100644 --- a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp +++ b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp @@ -23,13 +23,13 @@ namespace AI { if (_index != 8) { - int _groupCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index][1]; + int _tribeCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index].tribeCount; - int _tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index][0]; + int _tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index].tribeType; int _offset = 0; - if (0 < _groupCount) { + if (0 < _tribeCount) { short* _ptrTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeType; @@ -49,7 +49,7 @@ namespace AI { _ptrTribeID = _ptrTribeID + 1; - } while (_offset < _groupCount); + } while (_offset < _tribeCount); } } diff --git a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp index 2cdeef7f8..e01808143 100644 --- a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp @@ -33,24 +33,21 @@ namespace AI { if (DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) { - _ptrTribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; - do { /* - first iteration: 3 */ + first iteration: 0 */ - _tribeCount = *_ptrTribeCount; + _counter = 0; - /* - first iteration: 186 */ + _tribeCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_counter].tribeCount; - _tribeType = (*(int (*)[2])(_ptrTribeCount + -1))[0]; + _tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_counter].tribeType; /* - first iteration: 0 */ + first iteration: 186 */ - _counter = 0; + // _tribeType = (*(int (*)[2])(_ptrTribeCount + -1))[0]; if (0 < _tribeCount) { diff --git a/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp index e73d9dff7..bb31d983e 100644 --- a/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp +++ b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp @@ -26,7 +26,7 @@ namespace AI { piVar1 = &DAT_GameState::instance.playerDataArray[playerID]; - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIInfoLayer))); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackPrimeInfo, this)(playerID, piVar1->attackedPlayerID); diff --git a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp index e833529d0..7f28e4267 100644 --- a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp +++ b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp @@ -56,7 +56,7 @@ namespace AI { this->aiBorderTilesIndex = 0; - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 8000, '\0', (void*)((int)(this->aiBorderTiles))); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); diff --git a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp index 42b5dde68..8f1d56ea7 100644 --- a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp +++ b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp @@ -38,12 +38,12 @@ namespace AI { || BVar1 == Map::Buildings::BT_APOTHECARY || BVar1 == Map::Buildings::BT_CHAPEL || BVar1 == Map::Buildings::BT_CHURCH || BVar1 == Map::Buildings::BT_CATHEDRAL); } else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) { - _matches = (BVar1 == Map::Buildings::BT_GATEHOUSELARGE || BVar1 == Map::Buildings::BT_GATEHOUSESMALL - || BVar1 == Map::Buildings::BT_DRAWBRIDGE || BVar1 == Map::Buildings::BT_TOWER1 - || BVar1 == Map::Buildings::BT_TOWER2 || BVar1 == Map::Buildings::BT_TOWER3 - || BVar1 == Map::Buildings::BT_TOWER4 || BVar1 == Map::Buildings::BT_TOWER5 - || BVar1 == Map::Buildings::BT_ENGINEERSGUILD || BVar1 == Map::Buildings::BT_TUNNELERSGUILD - || BVar1 == Map::Buildings::BT_OILSMELTER); + _matches = (BVar1 == Map::Buildings::BT_GATEHOUSELARGE + || BVar1 == Map::Buildings::BT_GATEHOUSESMALL || BVar1 == Map::Buildings::BT_DRAWBRIDGE + || BVar1 == Map::Buildings::BT_TOWER1 || BVar1 == Map::Buildings::BT_TOWER2 + || BVar1 == Map::Buildings::BT_TOWER3 || BVar1 == Map::Buildings::BT_TOWER4 + || BVar1 == Map::Buildings::BT_TOWER5 || BVar1 == Map::Buildings::BT_ENGINEERSGUILD + || BVar1 == Map::Buildings::BT_TUNNELERSGUILD || BVar1 == Map::Buildings::BT_OILSMELTER); } else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) { _matches = (BVar1 == Map::Buildings::BT_MERCENARYPOST || BVar1 == Map::Buildings::BT_BARRACKS || BVar1 == Map::Buildings::BT_STABLES); @@ -62,8 +62,8 @@ namespace AI { if (_matches) { MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( - _buildingID); + MACRO_CALL_MEMBER( + Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_buildingID); } } _buildingID = _buildingID + 1; diff --git a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp index 29895258e..3cff7bcbf 100644 --- a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp +++ b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp @@ -32,7 +32,7 @@ namespace AI { return 0; // old enough: destroy - MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + MACRO_CALL_MEMBER(AIVState_Func::resetCountdownInHeatMap, DAT_AIVState::ptr)( (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp index d8525fab9..e896ea9ea 100644 --- a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -16,7 +16,7 @@ namespace AI { { uint local_8 = 0; uint local_4 = 0; - int* local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + int* local_c = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; bool _found = false; do { diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp index 4e463ac1d..a224fd2ec 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp @@ -42,7 +42,7 @@ namespace AI { _counter = 0; - _ptrGroupCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + _ptrGroupCount = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; do { diff --git a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp index 7d2f22ddc..540b6cdd5 100644 --- a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp +++ b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp @@ -42,7 +42,7 @@ namespace AI { if ((DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) && (DAT_GameState::instance.playerDataArray[param_1].someTile != 0)) { - local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + local_c = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; do { diff --git a/src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp b/src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp new file mode 100644 index 000000000..09d8f6571 --- /dev/null +++ b/src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp @@ -0,0 +1,17 @@ +#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" + +#include "OpenSHC/Globals/DAT_AIVState.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004ECAB0 + BOOLEnum AICState::mapperIsWoodCuttersHutWhileNoWoodAvailable( + undefined4 playerID, Commands::MappersEnum commandBuildingType) + { + return ((commandBuildingType == Commands::M_MAPPER_WOODSMAN) + && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0)); + } +} +} diff --git a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp index e98776b56..dba68ea44 100644 --- a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp +++ b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp @@ -47,7 +47,7 @@ namespace AI { _movingFewerThan20Percent = 0; - _ptrSize = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + _ptrSize = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; do { diff --git a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp index 2ecd26042..b53a16f12 100644 --- a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp @@ -29,7 +29,7 @@ namespace AI { int _tribeTotal = 0; int _notReallyMoving = 0; - int* local_c = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0] + 1; + int* local_c = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; do { int iVar2 = (*(int (*)[2])(local_c + -1))[0]; diff --git a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp index 24deba5fb..0fc1d1750 100644 --- a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp +++ b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp @@ -72,7 +72,7 @@ namespace AI { /* clear out flags */ - piVar1 = DAT_SkirmishDefinedData::instance.attackUnitRequired[0] + 1; + piVar1 = &DAT_SkirmishDefinedData::instance.attackUnitRequired[0].required; do { @@ -97,18 +97,18 @@ namespace AI { _index = 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[0][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[0].required = 1; } _maxDiggingUnits = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttDiggingUnitMax; if (((_maxDiggingUnits != 0) && (DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops < (int)_maxDiggingUnits)) - && (5 < DAT_GameState::instance.playerDataArray[_attackedPlayerID].field992_0x396c)) { + && (5 < DAT_GameState::instance.playerDataArray[_attackedPlayerID].moatsOwned)) { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[1][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[1].required = 1; } _maxAssassins = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxAssassins; @@ -118,7 +118,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[2][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[2].required = 1; } _maxUnit2 = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnit2Max; @@ -127,7 +127,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[3][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[3].required = 1; } _maxLaddermen = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxLaddermen; @@ -137,7 +137,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[4][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[4].required = 1; } _maxTunnelers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxTunnelers; @@ -147,7 +147,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[5][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[5].required = 1; } _maxUnitPatrol = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitPatrolMax; @@ -157,7 +157,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[6][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[6].required = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitBackupMax; @@ -167,7 +167,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[7][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[7].required = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitEngageMax; @@ -177,7 +177,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[8][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[8].required = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitSiegeDefMax; @@ -187,7 +187,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[9][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[9].required = 1; } _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxDefault; @@ -197,7 +197,7 @@ namespace AI { _index = _index + 1; - DAT_SkirmishDefinedData::instance.attackUnitRequired[10][1] = 1; + DAT_SkirmishDefinedData::instance.attackUnitRequired[10].required = 1; } if (_index != 0) { @@ -210,11 +210,12 @@ namespace AI { do { - if (DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2][1] != 0) { + if (DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2].required != 0) { if (_rng == 0) { - return (AIUnitBehaviourType)(DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2][0]); + return (AIUnitBehaviourType)(DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2] + .unitBehaviourType); } _rng = _rng + -1; diff --git a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp index a25c39500..3964e3919 100644 --- a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp @@ -61,7 +61,7 @@ namespace AI { *(int*)((int)DAT_TroopValueState::instance.attackInfo.hackValuesArray + playerID * 0x177bc + -0x10) = _attackedPlayerID; - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, diff --git a/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp index 6213b44c7..199d93eca 100644 --- a/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp @@ -21,7 +21,7 @@ namespace AI { DAT_TroopValueState::instance.attackInfo.playerInfo[0].currentPlayerID_OR_attackedPlayerID_OR_one = 1; - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); MACRO_CALL_MEMBER( diff --git a/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp index 8ab398ad0..3396df9e5 100644 --- a/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp @@ -42,7 +42,7 @@ namespace AI { if ((_fullID != -1) || (DAT_GameSynchronyState::instance.currentAIArray[_playerID] != 0)) { - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, diff --git a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp index 21cd5785b..f497eabdc 100644 --- a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp +++ b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp @@ -4,7 +4,7 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Unit.hpp" @@ -24,7 +24,7 @@ namespace OpenSHC { namespace AI { using OpenSHC::AI::Tribes::AITribeType; - using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Commands::MappersEnum; using OpenSHC::Map::Buildings::BuildingType; using OpenSHC::Map::Units::SomeTribeBehaviorType; using OpenSHC::Map::Units::Unit; @@ -65,7 +65,7 @@ namespace AI { int _aicEnginesArrayIndex; - CommandBuildingType _siegeEngineToBuild; + MappersEnum _siegeEngineToBuild; _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; @@ -171,8 +171,7 @@ namespace AI { _aicEnginesArrayIndex = DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex; - _siegeEngineToBuild - = *(CommandBuildingType*)((int)this + (iVar1 + _aicEnginesArrayIndex) * 4 + 0x1cc); + _siegeEngineToBuild = *(MappersEnum*)((int)this + (iVar1 + _aicEnginesArrayIndex) * 4 + 0x1cc); DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = _aicEnginesArrayIndex + 1; @@ -185,9 +184,9 @@ namespace AI { return; } - iVar1 = DAT_AIVState::instance.DAT_BuildingAppropriateGridYPosition * 5; + iVar1 = DAT_AIVState::instance.buildingAppropriateGridYPosition * 5; - _aicEnginesArrayIndex = DAT_AIVState::instance.DAT_BuildingApproriateGridXPosition * 5; + _aicEnginesArrayIndex = DAT_AIVState::instance.buildingAppropriateGridYPosition * 5; DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; @@ -200,15 +199,15 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)( playerID, _aicEnginesArrayIndex, iVar1, _siegeEngineToBuild, 3, 0xf); - _buildingID = DAT_TileMapState::instance.DAT_PlacedBuildingID; + _buildingID = DAT_TileMapState::instance.placedBuildingID; if (DAT_TileMapState::instance.buildingPlacementFail != FALSE) { return; } - DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.DAT_PlacedBuildingID] - .attackWave = 0; + DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.placedBuildingID].attackWave + = 0; DAT_BuildingsState::instance.buildings[_buildingID].unknownSiegeTentRelated01 = 2; diff --git a/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp index 6367b31c8..46687d253 100644 --- a/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp +++ b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp @@ -143,7 +143,7 @@ namespace AI { if (_playerData->aiType == OpenSHC::AI::AIT_NULL) { - iVar1 = DAT_AIVState::instance.SEC_AIVS[_playerData->aivID].castleID; + iVar1 = DAT_AIVState::instance.aivs[_playerData->aivID].castleID; pcVar2 = "AIV:n/a"; @@ -151,7 +151,7 @@ namespace AI { else { - iVar1 = DAT_AIVState::instance.SEC_AIVS[_playerData->aivID].castleID; + iVar1 = DAT_AIVState::instance.aivs[_playerData->aivID].castleID; pcVar2 = "AIV: %d"; } diff --git a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp index 66d46dc78..54406b440 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp @@ -67,7 +67,7 @@ namespace AI { _defendingLordIndex = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID); - _ptrGroupCount = (int (*)[2])(DAT_SkirmishDefinedData::instance.MaxBreachTribes[0] + 1); + _ptrGroupCount = (int (*)[2])(&DAT_SkirmishDefinedData::instance.MaxBreachTribes[0].tribeCount); do { diff --git a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp index c0e9f4f2a..7b9edebb0 100644 --- a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp +++ b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp @@ -34,7 +34,7 @@ namespace AI { if (_hut == 0) return FALSE; - MACRO_CALL_MEMBER(AIVState_Func::set0x13ValueTo10InHeatMap, DAT_AIVState::ptr)( + MACRO_CALL_MEMBER(AIVState_Func::resetCountdownInHeatMap, DAT_AIVState::ptr)( (int)(short)DAT_BuildingsState::instance.buildings[_hut].x, (int)(short)DAT_BuildingsState::instance.buildings[_hut].y); MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp index cff5e2904..51ca93934 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingArmoury.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -7,9 +7,9 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004ECA60 - BOOLEnum AICState::shouldNotBeBuildingArmoury(PlayerID playerID, Commands::CommandBuildingType commandBuildingType) + BOOLEnum AICState::shouldNotBeBuildingArmoury(PlayerID playerID, Commands::MappersEnum commandBuildingType) { - if (commandBuildingType != Commands::CBT_ARMORY) { + if (commandBuildingType != Commands::M_MAPPER_ARMOURY) { return FALSE; } return DAT_GameState::instance.playerDataArray[playerID].isArmouryAlmostFilledUp == 0; diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp index 93ea91df5..5ef58f276 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingGranary.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -7,9 +7,9 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004ECA30 - BOOLEnum AICState::shouldNotBeBuildingGranary(int playerID, Commands::CommandBuildingType commandBuildingType) + BOOLEnum AICState::shouldNotBeBuildingGranary(int playerID, Commands::MappersEnum commandBuildingType) { - if (commandBuildingType != Commands::CBT_GRANARY) { + if (commandBuildingType != Commands::M_MAPPER_GRANARY) { return FALSE; } return DAT_GameState::instance.playerDataArray[playerID].granaryIsAlmostFilledUp == FALSE; diff --git a/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp index 4ba346293..d14e60a15 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBeBuildingHovel.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -7,9 +7,9 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB5B0 - BOOLEnum AICState::shouldNotBeBuildingHovel(PlayerID playerID, Commands::CommandBuildingType param_2) + BOOLEnum AICState::shouldNotBeBuildingHovel(PlayerID playerID, Commands::MappersEnum param_2) { - if (param_2 != Commands::CBT_HOVEL) { + if (param_2 != Commands::M_MAPPER_HOVEL) { return FALSE; } diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp index e16bf1b27..6c80452e9 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_AIVState.hpp" @@ -7,9 +7,9 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004ECA90 - BOOLEnum AICState::shouldNotBuildKillingPits(int playerID, Commands::CommandBuildingType commandBuildingType) + BOOLEnum AICState::shouldNotBuildKillingPits(int playerID, Commands::MappersEnum commandBuildingType) { - if (commandBuildingType == Commands::CBT_KILLINGPIT) { + if (commandBuildingType == Commands::M_MAPPER_KILLING_PIT) { return (BOOLEnum)(DAT_AIVState::instance.mapExtraInfo.playerTotalKillingPits[playerID] >= 100); } return FALSE; diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp index 544c8e381..c1ac9a6b1 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBuildMarketArmoryGranaryBarracksMercenarypost.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -8,21 +8,19 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB9F0 BOOLEnum AICState::shouldNotBuildMarketArmoryGranaryBarracksMercenarypost( - int playerID, Commands::CommandBuildingType param_2) + int playerID, Commands::MappersEnum param_2) { if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { // nervous: reject market/mercenarypost/barracks/armory types - if (param_2 != Commands::CBT_MARKETPLACE - && param_2 != Commands::CBT_MERCENARYPOST - && param_2 != Commands::CBT_BARRACKS - && param_2 != Commands::CBT_ARMORY) { - return param_2 != Commands::CBT_GRANARY; + if (param_2 != Commands::M_MAPPER_TRADEPOST && param_2 != Commands::M_MAPPER_BARRACKS_ARAB + && param_2 != Commands::M_MAPPER_BARRACKS_EURO && param_2 != Commands::M_MAPPER_ARMOURY) { + return param_2 != Commands::M_MAPPER_GRANARY; } } else { // not nervous: only reject if destroy tracker > 0 and not marketplace if (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker > 0 - && param_2 != Commands::CBT_MARKETPLACE) { - return param_2 != Commands::CBT_GRANARY; + && param_2 != Commands::M_MAPPER_TRADEPOST) { + return param_2 != Commands::M_MAPPER_GRANARY; } } return FALSE; diff --git a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp index d2a7df33b..83caadc1e 100644 --- a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp +++ b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingAPositiveFearFactor.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -7,37 +7,37 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB700 - BOOLEnum AICState::shouldWaitWithBuildingAPositiveFearFactor(int playerID, Commands::CommandBuildingType param_2) + BOOLEnum AICState::shouldWaitWithBuildingAPositiveFearFactor(int playerID, Commands::MappersEnum param_2) { switch (param_2) { - case Commands::CBT_COMMUNAL_GARDEN1: - case Commands::CBT_COMMUNAL_GARDEN2: - case Commands::CBT_COMMUNAL_GARDEN3: - case Commands::CBT_COMMUNAL_GARDEN4: - case Commands::CBT_COMMUNAL_GARDEN5: - case Commands::CBT_SHRUB_GARDEN6: - case Commands::CBT_COMMUNAL_GARDEN7: - case Commands::CBT_COMMUNAL_GARDEN8: - case Commands::CBT_COMMUNAL_GARDEN9: - case Commands::CBT_TOWN_GARDEN10: - case Commands::CBT_TOWN_GARDEN11: - case Commands::CBT_TOWN_GARDEN12: - case Commands::CBT_MAYPOLE: - case Commands::CBT_STATUE1: - case Commands::CBT_STATUE2: - case Commands::CBT_STATUE3: - case Commands::CBT_STATUE4: - case Commands::CBT_STATUE5: - case Commands::CBT_SHRINE1: - case Commands::CBT_SHRINE2: - case Commands::CBT_SHRINE3: - case Commands::CBT_SHRINE4: - case Commands::CBT_SHRINE5: - case Commands::CBT_DANCINGBEAR: - case Commands::CBT_POND_1: - case Commands::CBT_SMALL_POND_3: - case Commands::CBT_LARGE_POND_3: - case Commands::CBT_LARGE_POND_4: + case Commands::M_MAPPER_GARDEN1: + case Commands::M_MAPPER_GARDEN2: + case Commands::M_MAPPER_GARDEN3: + case Commands::M_MAPPER_GARDEN4: + case Commands::M_MAPPER_GARDEN5: + case Commands::M_MAPPER_GARDEN6: + case Commands::M_MAPPER_GARDEN7: + case Commands::M_MAPPER_GARDEN8: + case Commands::M_MAPPER_GARDEN9: + case Commands::M_MAPPER_GARDEN10: + case Commands::M_MAPPER_GARDEN11: + case Commands::M_MAPPER_GARDEN12: + case Commands::M_MAPPER_MAYPOLE: + case Commands::M_MAPPER_STATUE1: + case Commands::M_MAPPER_STATUE2: + case Commands::M_MAPPER_STATUE3: + case Commands::M_MAPPER_STATUE4: + case Commands::M_MAPPER_STATUE5: + case Commands::M_MAPPER_SHRINE1: + case Commands::M_MAPPER_SHRINE2: + case Commands::M_MAPPER_SHRINE3: + case Commands::M_MAPPER_SHRINE4: + case Commands::M_MAPPER_SHRINE5: + case Commands::M_MAPPER_DANCING_BEAR: + case Commands::M_MAPPER_POND1: + case Commands::M_MAPPER_POND2_SMALL: + case Commands::M_MAPPER_POND3_LARGE1: + case Commands::M_MAPPER_POND4_LARGE2: DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay += 1; if (DAT_GameState::instance.playerDataArray[playerID].aivPositiveFearFactorDelay < 200) { return TRUE; diff --git a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp index 36ab16d6f..db2fd86bb 100644 --- a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp +++ b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp @@ -1,5 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -7,23 +7,23 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB610 - BOOLEnum AICState::shouldWaitWithBuildingNegativeFearFactor(int param_1, Commands::CommandBuildingType param_2) + BOOLEnum AICState::shouldWaitWithBuildingNegativeFearFactor(int param_1, Commands::MappersEnum param_2) { int* piVar1; switch (param_2) { - case Commands::CBT_GALLOWS: - case Commands::CBT_STOCKS: - case Commands::CBT_CESSPIT1: - case Commands::CBT_CESSPIT2: - case Commands::CBT_CESSPIT3: - case Commands::CBT_CESSPIT4: - case Commands::CBT_BURNINGSTAKE: - case Commands::CBT_GIBBET: - case Commands::CBT_DUNGEON: - case Commands::CBT_STRETCHINGRACK: - case Commands::CBT_RACKFLOGGING: - case Commands::CBT_CHOPPINGBLOCK: - case Commands::CBT_DUNKINGSTOOL: + case Commands::M_MAPPER_GALLOWS: + case Commands::M_MAPPER_STOCKS: + case Commands::M_MAPPER_CESS_PIT1: + case Commands::M_MAPPER_CESS_PIT2: + case Commands::M_MAPPER_CESS_PIT3: + case Commands::M_MAPPER_CESS_PIT4: + case Commands::M_MAPPER_BURNING_STAKE: + case Commands::M_MAPPER_GIBBET: + case Commands::M_MAPPER_DUNGEON: + case Commands::M_MAPPER_RACK_STRETCHING: + case Commands::M_MAPPER_RACK_FLOGGING: + case Commands::M_MAPPER_CHOPPING_BLOCK: + case Commands::M_MAPPER_DUNKING_STOOL: if ((DAT_GameState::instance.playerDataArray[param_1].popularity < 5000) || (piVar1 = &DAT_GameState::instance.playerDataArray[param_1].aivNegativeFearFactorDelay, *piVar1 = *piVar1 + 1, diff --git a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp index 43f52c12f..a92dbbe88 100644 --- a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp +++ b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp @@ -135,7 +135,8 @@ namespace AI { iVar3 = iVar3 + DAT_SkirmishDefinedData::instance .MaxBreachTribes[DAT_GameState::instance.playerDataArray[aiStack_24[iVar4]].aiType - + OpenSHC::AI::AIT_FREDERICK][0]; + + OpenSHC::AI::AIT_FREDERICK] + .tribeType; iVar4 = iVar4 + 1; @@ -158,14 +159,16 @@ namespace AI { iVar5 = iVar5 - DAT_SkirmishDefinedData::instance .MaxBreachTribes[DAT_GameState::instance.playerDataArray[iVar3].aiType - + OpenSHC::AI::AIT_FREDERICK][0]; + + OpenSHC::AI::AIT_FREDERICK] + .tribeType; if (iVar5 < 0) { DAT_GameSynchronyState::instance.DAT_ChatTauntOrMessage = -2 - DAT_SkirmishDefinedData::instance .MaxBreachTribes[DAT_GameState::instance.playerDataArray[iVar3].aiType - + OpenSHC::AI::AIT_FREDERICK][1]; + + OpenSHC::AI::AIT_FREDERICK] + .tribeCount; DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[1] = 1; diff --git a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp index 607b9a752..c0bee72c5 100644 --- a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp @@ -43,7 +43,7 @@ namespace AI { iVar5 != 0)) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToPlayerIDsKeepIfPossible, this)( - playerID, (short*)((int)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk))); + playerID, ((int)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk))); return; } @@ -53,7 +53,7 @@ namespace AI { BOOLEnum _shouldAttack = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::aiShouldAttackOrWaitForTeamCoordination, this)(playerID); if (_shouldAttack == FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRetreatUnits, this)((short*)playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRetreatUnits, this)(playerID); return; } DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; @@ -111,7 +111,7 @@ namespace AI { DAT_BuildingsState::ptr)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeEnemyKeepApproachTile, this)(playerID); if (0 < DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackTribesToLocations, this)((short*)playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackTribesToLocations, this)(playerID); return; } // state 1 with no path: reset to 0 diff --git a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp index b5ec39df2..2b4bb4481 100644 --- a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp +++ b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp @@ -4,7 +4,7 @@ #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/UnitInstructionType.hpp" @@ -19,7 +19,7 @@ namespace AI { using OpenSHC::AI::AIType; using OpenSHC::AI::AITypeInt; using OpenSHC::AI::Tribes::AITribeType; - using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Commands::MappersEnum; using OpenSHC::Map::Units::SomeTribeBehaviorType; using OpenSHC::Map::Units::UnitInstructionType; @@ -43,7 +43,7 @@ namespace AI { int* piVar4; - CommandBuildingType _siegeEngineType; + MappersEnum _siegeEngineType; int iVar5; @@ -132,7 +132,7 @@ namespace AI { /* fixme: parameter reuse */ - _siegeEngineType = (CommandBuildingType)playerID; + _siegeEngineType = (MappersEnum)playerID; do { @@ -151,8 +151,9 @@ namespace AI { _requiredEngineers = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[_counterTill6]; - _siegeEngineType = (CommandBuildingType)DAT_SkirmishDefinedData::instance - .SiegeEngineCommandBuildingTypes[_counterTill6]; + _siegeEngineType + = (MappersEnum) + DAT_SkirmishDefinedData::instance.SiegeEngineMappersEnums[_counterTill6]; break; } diff --git a/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp index ff4f4d85b..3f47b3277 100644 --- a/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp +++ b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp @@ -3,7 +3,7 @@ #include "OpenSHC/Map/Units/TroopValueState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" +#include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/UnitInstructionType.hpp" @@ -16,7 +16,7 @@ namespace AI { using OpenSHC::AI::AIType; using OpenSHC::AI::Tribes::AITribeType; - using OpenSHC::Commands::CommandBuildingType; + using OpenSHC::Commands::MappersEnum; using OpenSHC::Map::Units::SomeTribeBehaviorType; using OpenSHC::Map::Units::UnitInstructionType; @@ -66,8 +66,8 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func:: placeSiegeTentOrTunnelAtSuitableLocationAndAssignEngineers, - DAT_TroopValueState::ptr)(_tribeID, OpenSHC::Commands::CBT_TUNNEL_ENTRANCE, (uint)((int)(50)), - (UnitInstructionType)((int)(21))); + DAT_TroopValueState::ptr)(_tribeID, OpenSHC::Commands::M_MAPPER_TUNNEL_CONSTRUCTION, + (uint)((int)(50)), (UnitInstructionType)((int)(21))); _size = DAT_TribesState::instance.tribes[_aiTribeID].size; } diff --git a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp index 2a2e2abcc..ed4a02035 100644 --- a/src/OpenSHC/AI/AICState/wipeAICMemory.cpp +++ b/src/OpenSHC/AI/AICState/wipeAICMemory.cpp @@ -10,7 +10,7 @@ namespace AI { void AICState::wipeAICMemory() { for (int i = 0; i < 20; i++) { - MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemoryWithByteValue, DAT_LowLevelMemory::ptr)( + MACRO_CALL_MEMBER(IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( 676, '\0', &this->aics[i]); } } diff --git a/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp b/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp deleted file mode 100644 index 975bfa838..000000000 --- a/src/OpenSHC/AI/AICState/woodCuttersHutWhileNoWoodAvailable.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Commands/CommandBuildingType.hpp" - -#include "OpenSHC/Globals/DAT_AIVState.hpp" - -namespace OpenSHC { -namespace AI { - - // FUNCTION: STRONGHOLDCRUSADER 0x004ECAB0 - BOOLEnum AICState::woodCuttersHutWhileNoWoodAvailable( - undefined4 playerID, Commands::CommandBuildingType commandBuildingType) - { - return ((commandBuildingType == Commands::CBT_WOODCUTTERSHUT) - && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0)); - } -} -} From 25382f3183c28d8dcb5753bd40eac8c8b2196a6c Mon Sep 17 00:00:00 2001 From: sourcehold Date: Tue, 4 Aug 2026 12:22:43 +0200 Subject: [PATCH 046/242] sellExcessGoods 61.18% --- src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 118 ++++++++++---------- 1 file changed, 56 insertions(+), 62 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp index f0ef6d940..643d56427 100644 --- a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -14,6 +14,7 @@ namespace AI { using OpenSHC::AI::AIType; using OpenSHC::AI::AITypeInt; + using OpenSHC::AI::AIC::AICSpecification; using OpenSHC::AI::Trading::AIResourceTradeCategory; using OpenSHC::AI::Trading::AIResourceTradeCategoryInt; using OpenSHC::AI::Trading::ResourceAICResourceMappingEntry; @@ -22,90 +23,83 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D1D60 void AICState ::sellExcessGoods(int param_1) { - AITypeInt AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; - if (AVar1 == OpenSHC::AI::AIT_NULL) + AITypeInt aiType = DAT_GameState::instance.playerDataArray[param_1].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) return; - int iVar3 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - AIResourceTradeCategoryInt* local_18 = &DAT_SkirmishDefinedData::instance.AIResourceTradeAICMapping[0].aic; + int aicIndex = aiType - 1; + AICSpecification& aic = this->aics[aicIndex]; + int nervousActions = DAT_GameState::instance.playerDataArray[param_1].aiNervousActionsTracker; + int& goldResource = DAT_GameState::instance.playerDataArray[param_1].currentResources[0xf]; + int& popularity = DAT_GameState::instance.playerDataArray[param_1].popularity; - do { - ResourceType resourceType - = (OpenSHC::Game::Resources::ResourceType)((ResourceAICResourceMappingEntry*)(local_18 + -1))->game; - AIResourceTradeCategoryInt AVar2 = *local_18; + for (int entryIndex = 0; entryIndex < 20; entryIndex = entryIndex + 1) { + ResourceType resourceType = (OpenSHC::Game::Resources::ResourceType)DAT_SkirmishDefinedData::instance + .AIResourceTradeAICMapping[entryIndex] + .game; + AIResourceTradeCategoryInt category + = DAT_SkirmishDefinedData::instance.AIResourceTradeAICMapping[entryIndex].aic; + int variance = aic.maxResourceVariance; + int& currentResource = DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType]; - int iVar6 = *(int*)((int)this + iVar3 + 0xc0); - int iVar5; - if (AVar2 == OpenSHC::AI::Trading::AIRTC_WOOD) { - iVar5 = *(int*)((int)this + iVar3 + 0xac); - } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { - iVar5 = *(int*)((int)this + iVar3 + 0x80); - } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_STONE) { - iVar5 = *(int*)((int)this + iVar3 + 0xb0); - } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_WEAPONS) { - iVar5 = *(int*)((int)this + iVar3 + 0xb8); - } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_ALE) { - iVar5 = *(int*)((int)this + iVar3 + 0xbc); + int amount; + if (category == OpenSHC::AI::Trading::AIRTC_WOOD) { + amount = aic.maxWood; + } else if (category == OpenSHC::AI::Trading::AIRTC_FOOD) { + amount = aic.maxFood; + } else if (category == OpenSHC::AI::Trading::AIRTC_STONE) { + amount = aic.maxStone; + } else if (category == OpenSHC::AI::Trading::AIRTC_WEAPONS) { + amount = aic.maxEquipment; + } else if (category == OpenSHC::AI::Trading::AIRTC_ALE) { + amount = aic.maxBeer; } else { - iVar5 = *(int*)((int)this + iVar3 + 0xb4); + amount = aic.maxResourceOther; } - uint uVar4 = iVar5 + iVar6; + amount = amount + variance; - if ((DAT_GameState::instance.playerDataArray[param_1].aiNervousActionsTracker <= 0) - || (DAT_GameState::instance.playerDataArray[param_1].currentResources[0xf] >= 0x1f4)) { + if ((nervousActions > 0) && (goldResource < 0x1f4)) { - if (DAT_GameState::instance.playerDataArray[param_1].popularity < *(int*)((int)this + iVar3 + 0x18)) { - if (AVar2 != OpenSHC::AI::Trading::AIRTC_FOOD) { - if (AVar2 == OpenSHC::AI::Trading::AIRTC_WEAPONS) { - uVar4 = 0; - iVar6 = 0; + if (category == OpenSHC::AI::Trading::AIRTC_FOOD) { + amount = amount / 4; + } else { + amount = ((category != OpenSHC::AI::Trading::AIRTC_WEAPONS) - 1) & 10000; + } + variance = 0; + + } else { + if (popularity < aic.criticalPopularity) { + if (category != OpenSHC::AI::Trading::AIRTC_FOOD) { + if (category == OpenSHC::AI::Trading::AIRTC_WEAPONS) { + amount = 0; } else { - uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; - iVar6 = 0; + amount = amount / 4; } - } else { - iVar6 = 0; } + variance = 0; } else { - uVar4 = uVar4 + amount = amount + DAT_GameState::instance.playerDataArray[param_1].resourcesToAcquireArray[resourceType]; } - - } else if (AVar2 == OpenSHC::AI::Trading::AIRTC_FOOD) { - uVar4 = (int)(uVar4 + ((int)uVar4 >> 0x1f & 3U)) >> 2; - iVar6 = 0; - } else { - uVar4 = (AVar2 != OpenSHC::AI::Trading::AIRTC_WEAPONS) - 1 & 10000; - iVar6 = 0; } - // Check no-sell list (was LAB_004d1e81) - { - int iVar5_2 = 0; - ResourceType* pRVar7 = (ResourceType*)((int)this + iVar3 + 0xd4); - do { - if (resourceType == *pRVar7) { - uVar4 = 0; - iVar6 = 0; - break; - } - iVar5_2 = iVar5_2 + 1; - pRVar7 = pRVar7 + 1; - } while (iVar5_2 < 0xf); + int* sellResourceList = &aic.sellResource01; + for (int sellResourceIndex = 0; sellResourceIndex < 0xf; sellResourceIndex = sellResourceIndex + 1) { + if (resourceType == sellResourceList[sellResourceIndex]) { + amount = 0; + variance = 0; + break; + } } - if ((int)uVar4 < DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType]) { + if (currentResource > amount) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellGoods, this)(param_1, resourceType, - (DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType] - uVar4) + iVar6); + (DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType] - amount) + + variance); return; } - - local_18 = local_18 + 2; - if (0xb4252b < (int)local_18) - return; - - } while (true); + } } } } From 4f4f4d4528f1562ed76c6f19e68f0bcdad15d53e Mon Sep 17 00:00:00 2001 From: sourcehold Date: Wed, 5 Aug 2026 00:52:02 +0200 Subject: [PATCH 047/242] fix typo --- .../useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp index 2b4bb4481..f3e1e0afa 100644 --- a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp +++ b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp @@ -151,9 +151,8 @@ namespace AI { _requiredEngineers = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[_counterTill6]; - _siegeEngineType - = (MappersEnum) - DAT_SkirmishDefinedData::instance.SiegeEngineMappersEnums[_counterTill6]; + _siegeEngineType = (MappersEnum)DAT_SkirmishDefinedData::instance + .SiegeEngineCommandBuildingTypes[_counterTill6]; break; } From df31b368cf995f4c70fd73eaed356851cdb617d4 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sun, 16 Aug 2026 23:14:43 +0200 Subject: [PATCH 048/242] improve setAICParameters_01 --- src/OpenSHC/AI/AICState/setAICParameters_01.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_01.cpp b/src/OpenSHC/AI/AICState/setAICParameters_01.cpp index 3cb13057a..d085d91ae 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_01.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_01.cpp @@ -13,16 +13,15 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004C6D60 void AICState::setAICParameters_01(int aicID) { - this->aics[aicID].populationPerFarm = 6; - this->aics[aicID].minimumCheese = 0xffffffff; - this->aics[aicID].minimumBread = 0xffffffff; - this->aics[aicID].minimumWheat = 0xffffffff; - this->aics[aicID].minimumHop = 0xffffffff; + this->aics[aicID].minimumCheese = -1; + this->aics[aicID].minimumBread = -1; + this->aics[aicID].minimumWheat = -1; + this->aics[aicID].minimumHop = -1; this->aics[aicID].aiRequestDelay = 0x12; this->aics[aicID].populationPerQuarry = 0x12; + this->aics[aicID].populationPerFarm = 6; this->aics[aicID].maxWoodcutters = 6; this->aics[aicID].maxFarms = 6; - this->aics[aicID].sellResource09 = 0x12; this->aics[aicID].flagType = 0xc; this->aics[aicID].unknown002 = 0; this->aics[aicID].unknown001 = 0; @@ -30,8 +29,8 @@ namespace AI { this->aics[aicID].unknown004 = 0; this->aics[aicID].unknown005 = 0; this->aics[aicID].criticalPopularity = 4000; - this->aics[aicID].lowestPopularity = 0x157c; - this->aics[aicID].highestPopularity = 0x1d4c; + this->aics[aicID].lowestPopularity = 5500; + this->aics[aicID].highestPopularity = 7500; this->aics[aicID].taxesMin = 3; this->aics[aicID].taxesMax = 10; this->aics[aicID].farm1 = 0x20; @@ -66,6 +65,7 @@ namespace AI { this->aics[aicID].sellResource05 = 9; this->aics[aicID].sellResource06 = 0xe; this->aics[aicID].sellResource07 = 0x10; + this->aics[aicID].sellResource09 = 0x12; this->aics[aicID].sellResource11 = 0x14; this->aics[aicID].sellResource12 = 0x15; this->aics[aicID].sellResource13 = 0x16; From 0643abfc5baf78f1cd99d11ae14bb06e17dd25ce Mon Sep 17 00:00:00 2001 From: sourcehold Date: Mon, 17 Aug 2026 00:09:16 +0200 Subject: [PATCH 049/242] improve setAICParameters --- .../AI/AICState/setAICParameters_03.cpp | 14 +- .../AI/AICState/setAICParameters_04.cpp | 10 +- .../AI/AICState/setAICParameters_05.cpp | 20 +-- .../AI/AICState/setAICParameters_06.cpp | 32 ++-- .../AI/AICState/setAICParameters_07.cpp | 8 +- .../AI/AICState/setAICParameters_08.cpp | 144 +---------------- .../AI/AICState/setAICParameters_09.cpp | 141 +--------------- .../AI/AICState/setAICParameters_10.cpp | 140 +--------------- .../AI/AICState/setAICParameters_11.cpp | 152 ++---------------- .../AI/AICState/setAICParameters_12.cpp | 138 +--------------- .../AI/AICState/setAICParameters_13.cpp | 141 +--------------- .../AI/AICState/setAICParameters_14.cpp | 12 +- .../AI/AICState/setAICParameters_15.cpp | 135 +--------------- .../AI/AICState/setAICParameters_16.cpp | 138 +--------------- 14 files changed, 76 insertions(+), 1149 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_03.cpp b/src/OpenSHC/AI/AICState/setAICParameters_03.cpp index 2305891ed..7f8f963a3 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_03.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_03.cpp @@ -13,8 +13,8 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004C7520 void AICState::setAICParameters_03(int param_1) { - this->aics[param_1].minimumWheat = 0xffffffff; - this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].minimumWheat = -1; + this->aics[param_1].minimumHop = -1; this->aics[param_1].flagType = 0xc; this->aics[param_1].unknown002 = 0; this->aics[param_1].unknown001 = 0; @@ -84,8 +84,10 @@ namespace AI { this->aics[param_1].RecruitInterval = 1; this->aics[param_1].RecruitIntervalStrong = 4; this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].OuterPatrolRallyDelay = 0x14; this->aics[param_1].SortieUnitMeleeMin = 5; + this->aics[param_1].SortieUnitRanged = 0x17; + this->aics[param_1].SortieUnitMelee = 0x1a; + this->aics[param_1].OuterPatrolRallyDelay = 0x14; this->aics[param_1].RaidUnitsRandom = 5; this->aics[param_1].recruitProbRaidStrong = 0; this->aics[param_1].recruitProbAttackWeak = 0; @@ -103,14 +105,12 @@ namespace AI { this->aics[param_1].RaidRetargetDelay = 3; this->aics[param_1].AttForceBase = 10; this->aics[param_1].AttForceRandom = 10; - this->aics[param_1].SortieUnitRanged = 0x17; + this->aics[param_1].AttForceSupportAllyThreshold = 10; + this->aics[param_1].AttForceRallyPercentage = 0x3c; this->aics[param_1].DefUnit1 = 0x17; this->aics[param_1].DefUnit2 = 0x17; this->aics[param_1].DefUnit3 = 0x17; - this->aics[param_1].SortieUnitMelee = 0x1a; this->aics[param_1].RaidUnit1 = 0x1a; - this->aics[param_1].AttForceSupportAllyThreshold = 10; - this->aics[param_1].AttForceRallyPercentage = 0x3c; this->aics[param_1].AttMovingTribesThreshold = 100; this->aics[param_1].AttAssaultDelay = 5; this->aics[param_1].AttUnitPatrolRecommandDelay = 0xf; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_04.cpp b/src/OpenSHC/AI/AICState/setAICParameters_04.cpp index e81e060e1..913127402 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_04.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_04.cpp @@ -17,8 +17,8 @@ namespace AI { this->aics[param_1].unknown005 = 1; this->aics[param_1].farm2 = 0x20; this->aics[param_1].farm4 = 0x20; - this->aics[param_1].minimumWheat = 0xffffffff; - this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].minimumWheat = -1; + this->aics[param_1].minimumHop = -1; this->aics[param_1].flagType = 0xd; this->aics[param_1].unknown002 = 0; this->aics[param_1].unknown001 = 0; @@ -91,7 +91,9 @@ namespace AI { this->aics[param_1].SortieUnitRangedMin = 8; this->aics[param_1].SortieUnitRanged = 0x46; this->aics[param_1].SortieUnitMeleeMin = 6; + this->aics[param_1].SortieUnitMelee = 0x19; this->aics[param_1].DefDiggingUnitMax = 8; + this->aics[param_1].DefDiggingUnit = 0x19; this->aics[param_1].DefWalls = 0x50; this->aics[param_1].DefTotal = 100; this->aics[param_1].OuterPatrolGroupsMove = 1; @@ -104,11 +106,9 @@ namespace AI { this->aics[param_1].RaidUnit2 = 0x4a; this->aics[param_1].HarassingSiegeEngine1 = 0xbe; this->aics[param_1].RaidRetargetDelay = 5; + this->aics[param_1].AttForceBase = 0x28; this->aics[param_1].AttForceRandom = 0xf; this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; - this->aics[param_1].SortieUnitMelee = 0x19; - this->aics[param_1].DefDiggingUnit = 0x19; - this->aics[param_1].AttForceBase = 0x28; this->aics[param_1].AttForceRallyPercentage = 0x50; this->aics[param_1].AttMovingTribesThreshold = 100; this->aics[param_1].AttAssaultDelay = 0xc; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_05.cpp b/src/OpenSHC/AI/AICState/setAICParameters_05.cpp index b3958aa09..ad9eb85f1 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_05.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_05.cpp @@ -78,39 +78,39 @@ namespace AI { this->aics[param_1].recruitProbDefStrong = 0x19; this->aics[param_1].RaidUnitsRandom = 5; this->aics[param_1].HarassingSiegeEnginesMax = 5; + this->aics[param_1].HarassingSiegeEngine1 = 0xbe; this->aics[param_1].RecruitIntervalWeak = 1; this->aics[param_1].RecruitInterval = 1; this->aics[param_1].RecruitIntervalStrong = 1; this->aics[param_1].SortieUnitRangedMin = 10; + this->aics[param_1].SortieUnitMeleeMin = 7; + this->aics[param_1].SortieUnitMelee = 0x4b; + this->aics[param_1].SortieUnitRanged = 0x46; this->aics[param_1].OuterPatrolGroupsMove = 1; this->aics[param_1].OuterPatrolRallyDelay = 10; this->aics[param_1].RaidUnitsBase = 10; this->aics[param_1].AttForceRandom = 10; + this->aics[param_1].AttForceBase = 0x32; + this->aics[param_1].AttForceSupportAllyThreshold = 8; + this->aics[param_1].AttForceRallyPercentage = 0x50; this->aics[param_1].recruitProbRaidWeak = 0; this->aics[param_1].recruitProbRaidStrong = 0x19; this->aics[param_1].recruitProbAttackWeak = 0; this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].SortieUnitMeleeMin = 7; - this->aics[param_1].SortieUnitMelee = 0x4b; this->aics[param_1].DefDiggingUnitMax = 4; this->aics[param_1].DefDiggingUnit = 0x47; this->aics[param_1].DefWalls = 0x32; this->aics[param_1].OuterPatrolGroupsCount = 2; this->aics[param_1].DefUnit1 = 0x4b; + this->aics[param_1].DefUnit2 = 0x46; + this->aics[param_1].DefUnit3 = 0x46; + this->aics[param_1].DefUnit4 = 0x46; this->aics[param_1].DefUnit5 = 0x4c; this->aics[param_1].RaidUnit1 = 0x4a; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; this->aics[param_1].RaidRetargetDelay = 3; - this->aics[param_1].AttForceBase = 0x32; this->aics[param_1].recruitProbRaidDefault = 0x21; this->aics[param_1].recruitProbAttackDefault = 0x21; - this->aics[param_1].SortieUnitRanged = 0x46; this->aics[param_1].DefTotal = 0x46; - this->aics[param_1].DefUnit2 = 0x46; - this->aics[param_1].DefUnit3 = 0x46; - this->aics[param_1].DefUnit4 = 0x46; - this->aics[param_1].AttForceSupportAllyThreshold = 8; - this->aics[param_1].AttForceRallyPercentage = 0x50; this->aics[param_1].AttMovingTribesThreshold = 100; this->aics[param_1].AttAssaultDelay = 4; this->aics[param_1].AttUnitPatrolRecommandDelay = 1; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_06.cpp b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp index 2a28425db..b80d16350 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_06.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp @@ -14,13 +14,13 @@ namespace AI { { - this->aics[param_1].minimumCheese = 0xffffffff; + this->aics[param_1].minimumCheese = -1; - this->aics[param_1].minimumBread = 0xffffffff; + this->aics[param_1].minimumBread = -1; - this->aics[param_1].minimumWheat = 0xffffffff; + this->aics[param_1].minimumWheat = -1; - this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].minimumHop = -1; this->aics[param_1].taxesMax = 0xc; @@ -142,8 +142,6 @@ namespace AI { this->aics[param_1].unknown072 = 100; - this->aics[param_1].SortieUnitRangedMin = 7; - this->aics[param_1].unknown073 = 0x14; this->aics[param_1].recruitProbRaidWeak = 0x14; @@ -156,8 +154,14 @@ namespace AI { this->aics[param_1].RecruitIntervalStrong = 0; + this->aics[param_1].SortieUnitRangedMin = 7; + this->aics[param_1].SortieUnitMeleeMin = 5; + this->aics[param_1].SortieUnitRanged = 0x46; + + this->aics[param_1].SortieUnitMelee = 0x4b; + this->aics[param_1].OuterPatrolGroupsCount = 2; this->aics[param_1].HarassingSiegeEnginesMax = 2; @@ -176,8 +180,6 @@ namespace AI { this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].SortieUnitMelee = 0x4b; - this->aics[param_1].DefDiggingUnitMax = 4; this->aics[param_1].DefDiggingUnit = 0x47; @@ -192,20 +194,18 @@ namespace AI { this->aics[param_1].DefUnit1 = 0x4c; - this->aics[param_1].RaidUnitsBase = 0x1e; - - this->aics[param_1].RaidUnitsRandom = 0x1e; - - this->aics[param_1].RaidUnit1 = 0x47; - - this->aics[param_1].SortieUnitRanged = 0x46; - this->aics[param_1].DefUnit2 = 0x46; this->aics[param_1].DefUnit3 = 0x46; this->aics[param_1].DefUnit4 = 0x46; + this->aics[param_1].RaidUnitsBase = 0x1e; + + this->aics[param_1].RaidUnitsRandom = 0x1e; + + this->aics[param_1].RaidUnit1 = 0x47; + this->aics[param_1].HarassingSiegeEngine1 = 0x166; this->aics[param_1].HarassingSiegeEngine2 = 0xbe; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp index 84fc2c94a..9e00fc0d3 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp @@ -14,13 +14,13 @@ namespace AI { { - this->aics[param_1].minimumCheese = 0xffffffff; + this->aics[param_1].minimumCheese = -1; - this->aics[param_1].minimumBread = 0xffffffff; + this->aics[param_1].minimumBread = -1; - this->aics[param_1].minimumWheat = 0xffffffff; + this->aics[param_1].minimumWheat = -1; - this->aics[param_1].minimumHop = 0xffffffff; + this->aics[param_1].minimumHop = -1; this->aics[param_1].maxEquipment = 5; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_08.cpp b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp index fbc4839a2..038ccf902 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_08.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp @@ -8,282 +8,144 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C8920 void AICState ::setAICParameters_08(int param_1) - { - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].farm3 = 0x20; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].minimumApples = 5; - this->aics[param_1].minimumCheese = 5; - - this->aics[param_1].minimumBread = 0xffffffff; - - this->aics[param_1].minimumWheat = 0xffffffff; - - this->aics[param_1].minimumHop = 0xffffffff; - + this->aics[param_1].minimumBread = -1; + this->aics[param_1].minimumWheat = -1; + this->aics[param_1].minimumHop = -1; this->aics[param_1].tradeAmountFood = 5; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown005 = 0; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMin = 3; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].farm1 = 0x21; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 0xc; - this->aics[param_1].maxFood = 200; - this->aics[param_1].tradeAmountEquipment = 2; - this->aics[param_1].aiRequestDelay = 0x16; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxWood = 0x32; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 10; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 10; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 3; - this->aics[param_1].maxIronmines = 4; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxFarms = 0xf; - this->aics[param_1].buildInterval = 4; - this->aics[param_1].resourceRebuildDelay = 0x14; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x14; - this->aics[param_1].sellResource02 = 3; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource06 = 0xe; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].defWallPatrolRallyTime = 8; - this->aics[param_1].defWallPatrolGroups = 4; - this->aics[param_1].defSiegeEngineGoldThreshold = 200; - this->aics[param_1].defSiegeEngineBuildDelay = 2; - this->aics[param_1].unknown072 = 100; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x5a; - this->aics[param_1].recruitProbDefDefault = 0x1e; - this->aics[param_1].recruitProbDefStrong = 10; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].RaidUnitsBase = 10; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbRaidDefault = 0; - this->aics[param_1].recruitProbRaidStrong = 0; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].DefDiggingUnitMax = 0; - this->aics[param_1].DefWalls = 0x14; - this->aics[param_1].OuterPatrolGroupsCount = 2; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].DefUnit2 = 0x16; - this->aics[param_1].RaidUnitsRandom = 4; - this->aics[param_1].RaidUnit1 = 0x16; - this->aics[param_1].HarassingSiegeEnginesMax = 2; - this->aics[param_1].AttForceBase = 0x14; - this->aics[param_1].recruitProbAttackDefault = 0x46; - this->aics[param_1].recruitProbAttackStrong = 0x5a; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].SortieUnitRangedMin = 6; - this->aics[param_1].SortieUnitMeleeMin = 6; - this->aics[param_1].SortieUnitMelee = 0x19; - this->aics[param_1].DefDiggingUnit = 0x19; - this->aics[param_1].DefTotal = 0x28; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 5; - this->aics[param_1].DefUnit3 = 0x19; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RaidRetargetDelay = 5; - this->aics[param_1].AttForceRandom = 5; - this->aics[param_1].AttForceSupportAllyThreshold = 10; - this->aics[param_1].AttForceRallyPercentage = 10; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0x14; - this->aics[param_1].AttUnitPatrolRecommandDelay = 2; - this->aics[param_1].AttCoordinationPreference = 10; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].SiegeEngine2 = 0x27; - this->aics[param_1].SiegeEngine3 = 0x27; - this->aics[param_1].SiegeEngine4 = 0x3b; - this->aics[param_1].SiegeEngine5 = 0x28; - this->aics[param_1].SiegeEngine6 = 0x28; - this->aics[param_1].AttMaxEngineers = 0x10; - this->aics[param_1].AttDiggingUnit = 0x19; - this->aics[param_1].AttDiggingUnitMax = 6; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 3; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x14; - this->aics[param_1].AttUnitBackupGroupsCount = 2; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0x1b; - this->aics[param_1].AttUnitSiegeDefMax = 4; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 2; - this->aics[param_1].AttUnitMain1 = 0x1b; - this->aics[param_1].AttUnitMain2 = 0x19; - this->aics[param_1].AttUnitMain3 = 0x19; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 3; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_09.cpp b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp index 28bd5aac5..1000c8508 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_09.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp @@ -8,276 +8,141 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C8D20 void AICState ::setAICParameters_09(int param_1) - { - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].minimumApples = 5; - this->aics[param_1].minimumCheese = 5; - - this->aics[param_1].minimumBread = 0xffffffff; - - this->aics[param_1].minimumWheat = 0xffffffff; - - this->aics[param_1].minimumHop = 0xffffffff; - + this->aics[param_1].minimumBread = -1; + this->aics[param_1].minimumWheat = -1; + this->aics[param_1].minimumHop = -1; this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 0x157c; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 3; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].farm1 = 0x21; - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].farm3 = 0x1f; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 0xc; - this->aics[param_1].maxFood = 200; - this->aics[param_1].tradeAmountFood = 10; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0x16; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxResourceOther = 0xf; - this->aics[param_1].maxEquipment = 0x14; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 0xc; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 4; - this->aics[param_1].maxIronmines = 5; - this->aics[param_1].maxWoodcutters = 0xc; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 0xc; - this->aics[param_1].buildInterval = 4; - this->aics[param_1].resourceRebuildDelay = 0x1e; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = -999; - this->aics[param_1].poleturnerSetting = 0x14; - this->aics[param_1].sellResource04 = 7; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].defWallPatrolRallyTime = 8; - this->aics[param_1].defWallPatrolGroups = 2; - this->aics[param_1].defSiegeEngineGoldThreshold = 200; - this->aics[param_1].defSiegeEngineBuildDelay = 2; - this->aics[param_1].unknown072 = 100; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 100; - this->aics[param_1].recruitProbDefDefault = 0x32; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].AttForceSupportAllyThreshold = 0x14; - this->aics[param_1].RecruitInterval = 4; - this->aics[param_1].RecruitIntervalStrong = 4; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].SortieUnitMeleeMin = 4; - this->aics[param_1].DefDiggingUnitMax = 10; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].OuterPatrolRallyDelay = 10; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].DefUnit2 = 0x16; - this->aics[param_1].RaidUnitsBase = 4; - this->aics[param_1].AttForceRandom = 4; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackWeak = 0; - this->aics[param_1].recruitProbAttackDefault = 0x1e; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].SortieUnitRangedMin = 0xc; - this->aics[param_1].SortieUnitMelee = 0x1b; - this->aics[param_1].DefWalls = 0x32; - this->aics[param_1].DefTotal = 0x50; - this->aics[param_1].OuterPatrolGroupsCount = 2; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].DefUnit3 = 0x17; - this->aics[param_1].RaidUnitsRandom = 0; - this->aics[param_1].RaidUnit1 = 0x1c; - this->aics[param_1].HarassingSiegeEnginesMax = 2; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RaidRetargetDelay = 6; - this->aics[param_1].AttForceBase = 0x1e; - this->aics[param_1].AttForceRallyPercentage = 0x32; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0x14; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x32; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x28; - this->aics[param_1].SiegeEngine2 = 0x28; - this->aics[param_1].SiegeEngine3 = 0x28; - this->aics[param_1].SiegeEngine4 = 0x28; - this->aics[param_1].SiegeEngine5 = 0x28; - this->aics[param_1].SiegeEngine6 = 0x28; - this->aics[param_1].AttMaxEngineers = 0x12; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0x17; - this->aics[param_1].AttUnitPatrolMax = 0x14; - this->aics[param_1].AttUnitPatrolGroupsCount = 1; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x1e; - this->aics[param_1].AttUnitBackupGroupsCount = 2; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0x17; - this->aics[param_1].AttUnitSiegeDefMax = 10; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; - this->aics[param_1].AttUnitMain1 = 0x1b; - this->aics[param_1].AttUnitMain2 = 0x1b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 4; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp index 0d6b6afba..8b1e50bce 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp @@ -1,6 +1,5 @@ #include "OpenSHC/AI/AICState.func.hpp" #include "OpenSHC/AI/AIC/AITargetChoice.hpp" - namespace OpenSHC { namespace AI { @@ -8,276 +7,141 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C9120 void AICState ::setAICParameters_10(int param_1) - { - this->aics[param_1].taxesMin = 2; - this->aics[param_1].farm1 = 0x20; - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].tradeAmountEquipment = 2; - - this->aics[param_1].minimumWheat = 0xffffffff; - - this->aics[param_1].minimumHop = 0xffffffff; - + this->aics[param_1].minimumWheat = -1; + this->aics[param_1].minimumHop = -1; this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].resourceRebuildDelay = 0x3c; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].populationPerFarm = 5; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumCheese = 10; - this->aics[param_1].minimumBread = 10; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x32; - this->aics[param_1].maxResourceOther = 0xf; - this->aics[param_1].maxEquipment = 6; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 0; - this->aics[param_1].populationPerIronmine = 7; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 1; - this->aics[param_1].maxIronmines = 3; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 8; - this->aics[param_1].buildInterval = 4; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource02 = 3; - this->aics[param_1].sellResource04 = 7; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource06 = 0xe; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x46; - this->aics[param_1].recruitProbDefDefault = 0x28; - this->aics[param_1].RecruitIntervalWeak = 4; - this->aics[param_1].RecruitInterval = 4; - this->aics[param_1].RecruitIntervalStrong = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].DefWalls = 4; - this->aics[param_1].OuterPatrolGroupsCount = 4; - this->aics[param_1].RaidUnitsBase = 4; - this->aics[param_1].RaidUnitsRandom = 4; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x14; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].recruitProbAttackDefault = 0x14; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].SortieUnitMeleeMin = 0x14; - this->aics[param_1].DefTotal = 0x14; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].DefUnit2 = 0x16; - this->aics[param_1].DefUnit3 = 0x16; - this->aics[param_1].DefUnit4 = 0x16; - this->aics[param_1].DefUnit5 = 0x16; - this->aics[param_1].DefUnit6 = 0x16; - this->aics[param_1].HarassingSiegeEnginesMax = 1; - this->aics[param_1].recruitProbRaidDefault = 0x28; - this->aics[param_1].recruitProbAttackStrong = 0x3c; - this->aics[param_1].SortieUnitRangedMin = 2; - this->aics[param_1].SortieUnitMelee = 0x18; - this->aics[param_1].DefDiggingUnit = 0x18; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x1c; - this->aics[param_1].RaidUnit1 = 0x1c; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].AttForceBase = 10; - this->aics[param_1].AttForceRandom = 0x14; - this->aics[param_1].AttForceSupportAllyThreshold = 0x28; - this->aics[param_1].AttForceRallyPercentage = 0x28; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x46; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0; - this->aics[param_1].AttMaxEngineers = 0; - this->aics[param_1].AttDiggingUnit = 0x18; - this->aics[param_1].AttDiggingUnitMax = 0x3c; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0x18; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0; - this->aics[param_1].AttUnitBackupMax = 0; - this->aics[param_1].AttUnitBackupGroupsCount = 0; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x18; - this->aics[param_1].AttUnitMain2 = 0x18; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_11.cpp b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp index 9f6a82e8a..2296787e0 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_11.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp @@ -8,274 +8,140 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C94F0 void AICState ::setAICParameters_11(int param_1) - { - this->aics[param_1].taxesMin = 2; - - this->aics[param_1].minimumApples = 0xffffffff; - - this->aics[param_1].minimumCheese = 0xffffffff; - - this->aics[param_1].minimumBread = 0xffffffff; - + this->aics[param_1].minimumApples = -1; + this->aics[param_1].minimumCheese = -1; + this->aics[param_1].minimumBread = -1; this->aics[param_1].minimumWheat = 2; - - this->aics[param_1].minimumHop = 0xffffffff; - + this->aics[param_1].minimumHop = -1; this->aics[param_1].flagType = 10; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm1 = 0x1e; - this->aics[param_1].populationPerFarm = 5; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0x16; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x1e; - this->aics[param_1].doubleRationsFoodThreshold = 0x32; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x28; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 100; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 6; - this->aics[param_1].populationPerIronmine = 0xc; - this->aics[param_1].populationPerPitchrig = 6; - this->aics[param_1].maxQuarries = 3; - this->aics[param_1].maxIronmines = 1; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 4; - this->aics[param_1].maxFarms = 8; - this->aics[param_1].buildInterval = 3; - this->aics[param_1].resourceRebuildDelay = 0x32; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource02 = 3; - this->aics[param_1].sellResource03 = 6; - this->aics[param_1].sellResource06 = 0xe; - this->aics[param_1].sellResource08 = 0x11; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x46; - this->aics[param_1].recruitProbDefDefault = 0x1e; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x14; - this->aics[param_1].recruitProbAttackWeak = 0x1e; - this->aics[param_1].DefDiggingUnitMax = 4; - + this->aics[param_1].DefDiggingUnit = 0x47; this->aics[param_1].RaidUnitsBase = 0x1e; - this->aics[param_1].HarassingSiegeEnginesMax = 4; - + this->aics[param_1].HarassingSiegeEngine1 = 0x166; this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].SortieUnitMeleeMin = 10; - + this->aics[param_1].SortieUnitRangedMin = 6; + this->aics[param_1].SortieUnitMelee = 0x4b; + this->aics[param_1].SortieUnitRanged = 0x4a; this->aics[param_1].RaidUnitsRandom = 10; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbAttackDefault = 0x32; - this->aics[param_1].recruitProbAttackStrong = 0x3c; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 1; - - this->aics[param_1].SortieUnitRangedMin = 6; - - this->aics[param_1].SortieUnitMelee = 0x4b; - - this->aics[param_1].DefDiggingUnit = 0x47; - this->aics[param_1].DefWalls = 0x28; - this->aics[param_1].DefTotal = 0x28; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x46; - this->aics[param_1].DefUnit2 = 0x4c; - - this->aics[param_1].HarassingSiegeEngine1 = 0x166; - this->aics[param_1].AttForceBase = 0x28; - this->aics[param_1].AttForceRandom = 5; - - this->aics[param_1].SortieUnitRanged = 0x4a; - this->aics[param_1].RaidUnit1 = 0x4a; - this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; - this->aics[param_1].AttForceRallyPercentage = 0x50; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 4; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x5a; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x28; - this->aics[param_1].SiegeEngine2 = 0x4d; - this->aics[param_1].SiegeEngine3 = 0x4d; - this->aics[param_1].SiegeEngine4 = 0x4d; - this->aics[param_1].AttMaxEngineers = 9; - this->aics[param_1].AttDiggingUnit = 0x47; - this->aics[param_1].AttDiggingUnitMax = 0xf; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x4a; - this->aics[param_1].AttUnitBackupMax = 0x50; - this->aics[param_1].AttUnitBackupGroupsCount = 1; - this->aics[param_1].AttUnitEngageMax = 10; - this->aics[param_1].AttUnitEngage = 0x4c; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x4b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp index a09be5a21..d2c250af1 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp @@ -8,274 +8,140 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C9900 void AICState ::setAICParameters_12(int param_1) - { - this->aics[param_1].farm1 = 0x1e; - this->aics[param_1].farm3 = 0x1e; - - this->aics[param_1].minimumCheese = 0xffffffff; - - this->aics[param_1].minimumBread = 0xffffffff; - + this->aics[param_1].minimumCheese = -1; + this->aics[param_1].minimumBread = -1; this->aics[param_1].flagType = 10; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].farm4 = 0x1f; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 0x50; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumWheat = 2; - this->aics[param_1].minimumHop = 2; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 6; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 4; - this->aics[param_1].maxIronmines = 3; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 0x10; - this->aics[param_1].buildInterval = 2; - this->aics[param_1].resourceRebuildDelay = 0x28; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x50; - this->aics[param_1].recruitProbDefDefault = 0x28; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 10; - this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].SortieUnitMeleeMin = 0x14; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].RaidUnitsRandom = 10; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackDefault = 0x28; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitInterval = 0; - this->aics[param_1].RecruitIntervalStrong = 0; - this->aics[param_1].SortieUnitRanged = 0x46; - this->aics[param_1].SortieUnitMelee = 0x4b; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].DefWalls = 0x32; - this->aics[param_1].DefTotal = 0x32; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].DefUnit2 = 0x46; - this->aics[param_1].RaidUnitsBase = 0x1e; - this->aics[param_1].RaidUnit1 = 0x4b; - this->aics[param_1].HarassingSiegeEnginesMax = 3; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].HarassingSiegeEngine2 = 0xbe; - this->aics[param_1].HarassingSiegeEngine3 = 0x166; - this->aics[param_1].AttForceBase = 0x1e; - this->aics[param_1].AttForceRandom = 10; - this->aics[param_1].AttForceSupportAllyThreshold = 0x14; - this->aics[param_1].AttForceRallyPercentage = 0x50; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x50; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].SiegeEngine2 = 0x27; - this->aics[param_1].SiegeEngine3 = 0x3d; - this->aics[param_1].AttMaxEngineers = 6; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 0xf; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x4a; - this->aics[param_1].AttUnitBackupMax = 0x50; - this->aics[param_1].AttUnitBackupGroupsCount = 1; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x4b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_13.cpp b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp index be05cbf93..1bfe3d4ef 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_13.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp @@ -8,268 +8,137 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C9CF0 void AICState ::setAICParameters_13(int param_1) - { - - this->aics[param_1].minimumCheese = 0xffffffff; - - this->aics[param_1].minimumBread = 0xffffffff; - + this->aics[param_1].minimumCheese = -1; + this->aics[param_1].minimumBread = -1; this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumWheat = 5; - this->aics[param_1].minimumHop = 5; - this->aics[param_1].recruitGoldThreshold = 100; - this->aics[param_1].flagType = 10; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm1 = 0x1e; - this->aics[param_1].farm2 = 0x1e; - this->aics[param_1].farm3 = 0x1e; - this->aics[param_1].farm4 = 0x1f; - this->aics[param_1].populationPerFarm = 3; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].tradeAmountFood = 10; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x1e; - this->aics[param_1].doubleRationsFoodThreshold = 0x1e; - this->aics[param_1].maxWood = 0x32; - this->aics[param_1].maxStone = 0x28; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 0x14; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0xf; - this->aics[param_1].maxQuarries = 1; - this->aics[param_1].maxIronmines = 2; - this->aics[param_1].maxWoodcutters = 0xc; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 0x10; - this->aics[param_1].buildInterval = 1; - this->aics[param_1].resourceRebuildDelay = 0x14; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource03 = 6; - this->aics[param_1].sellResource08 = 0x11; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x50; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackDefault = 0x1e; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].RecruitInterval = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].recruitProbDefDefault = 0x32; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbAttackWeak = 0x14; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitIntervalWeak = 8; - this->aics[param_1].SortieUnitRanged = 0x46; - + this->aics[param_1].SortieUnitRangedMin = 5; this->aics[param_1].SortieUnitMeleeMin = 0xf; - this->aics[param_1].SortieUnitMelee = 0x46; - this->aics[param_1].DefDiggingUnitMax = 0x3c; - this->aics[param_1].DefDiggingUnit = 0x47; - this->aics[param_1].DefWalls = 0x50; - this->aics[param_1].DefTotal = 0x50; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x46; - this->aics[param_1].HarassingSiegeEnginesMax = 0; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].AttForceBase = 0x28; - this->aics[param_1].AttForceRandom = 0; - - this->aics[param_1].SortieUnitRangedMin = 5; - + this->aics[param_1].AttForceSupportAllyThreshold = 10; + this->aics[param_1].AttForceRallyPercentage = 0x32; this->aics[param_1].RaidUnitsBase = 5; - this->aics[param_1].RaidUnitsRandom = 5; - this->aics[param_1].RaidUnit1 = 0x49; - - this->aics[param_1].AttForceSupportAllyThreshold = 10; - - this->aics[param_1].AttForceRallyPercentage = 0x32; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x32; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].AttMaxEngineers = 0; - this->aics[param_1].AttDiggingUnit = 0x47; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 0x28; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x4a; - this->aics[param_1].AttUnitBackupMax = 0; - this->aics[param_1].AttUnitBackupGroupsCount = 0; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x49; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 4; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp index c5590667e..91bb5efe5 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp @@ -150,6 +150,8 @@ namespace AI { this->aics[param_1].DefDiggingUnitMax = 4; + this->aics[param_1].DefDiggingUnit = 0x1a; + this->aics[param_1].RaidUnitsRandom = 4; this->aics[param_1].RaidRetargetDelay = 4; @@ -164,6 +166,10 @@ namespace AI { this->aics[param_1].SortieUnitMeleeMin = 10; + this->aics[param_1].SortieUnitRanged = 0x17; + + this->aics[param_1].SortieUnitMelee = 0x1a; + this->aics[param_1].DefTotal = 0x32; this->aics[param_1].RaidUnitsBase = 10; @@ -174,8 +180,6 @@ namespace AI { this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].SortieUnitRanged = 0x17; - this->aics[param_1].DefWalls = 0x28; this->aics[param_1].OuterPatrolGroupsCount = 1; @@ -200,10 +204,6 @@ namespace AI { this->aics[param_1].HarassingSiegeEngine2 = 0x166; - this->aics[param_1].SortieUnitMelee = 0x1a; - - this->aics[param_1].DefDiggingUnit = 0x1a; - this->aics[param_1].RaidUnit1 = 0x1a; this->aics[param_1].AttForceBase = 0x32; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_15.cpp b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp index db36e5ca0..f05d8235b 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_15.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp @@ -8,268 +8,137 @@ namespace AI { /* decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CA4D0 void AICState ::setAICParameters_15(int param_1) - { - this->aics[param_1].farm1 = 0x21; - this->aics[param_1].farm3 = 0x21; - this->aics[param_1].farm4 = 0x21; - this->aics[param_1].populationPerFarm = 5; - this->aics[param_1].minimumHop = 5; - - this->aics[param_1].minimumBread = 0xffffffff; - - this->aics[param_1].minimumWheat = 0xffffffff; - + this->aics[param_1].minimumBread = -1; + this->aics[param_1].minimumWheat = -1; this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 7; - this->aics[param_1].populationPerIronmine = 7; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].maxResourceOther = 0xc; - this->aics[param_1].maxIronmines = 3; - this->aics[param_1].buildInterval = 3; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].farm2 = 0x1f; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumCheese = 10; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0; - this->aics[param_1].doubleRationsFoodThreshold = 0x50; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x32; - this->aics[param_1].maxEquipment = 10; - this->aics[param_1].maxBeer = 6; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 1; - this->aics[param_1].maxWoodcutters = 8; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 9; - this->aics[param_1].resourceRebuildDelay = 0x28; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource04 = 7; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].RecruitIntervalStrong = 4; - this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].SortieUnitMeleeMin = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].RaidUnitsRandom = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].recruitProbRaidWeak = 0x28; - this->aics[param_1].recruitProbRaidDefault = 0x28; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].DefTotal = 0x28; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].AttForceBase = 10; - this->aics[param_1].AttForceSupportAllyThreshold = 10; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x32; - this->aics[param_1].recruitProbDefDefault = 0x1e; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackDefault = 0x1e; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].SortieUnitMelee = 0x1c; - this->aics[param_1].DefWalls = 0x1e; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].RaidUnitsBase = 0x10; - this->aics[param_1].RaidUnit1 = 0x1c; - this->aics[param_1].HarassingSiegeEnginesMax = 1; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].AttForceRandom = 0x14; - this->aics[param_1].AttForceRallyPercentage = 0x32; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x46; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x28; - this->aics[param_1].SiegeEngine2 = 0x28; - this->aics[param_1].AttMaxEngineers = 6; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x1e; - this->aics[param_1].AttUnitBackupGroupsCount = 3; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x1b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; - return; } - } } diff --git a/src/OpenSHC/AI/AICState/setAICParameters_16.cpp b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp index 98b8a0d26..d7e7a4390 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_16.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp @@ -6,272 +6,138 @@ namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CA8A0 void AICState ::setAICParameters_16(int param_1) - { - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm2 = 0x1e; - this->aics[param_1].farm3 = 0x1e; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].maxFarms = 0xc; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].farm1 = 0x1f; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumApples = 10; - - this->aics[param_1].minimumCheese = 0xffffffff; - - this->aics[param_1].minimumBread = 0xffffffff; - + this->aics[param_1].minimumCheese = -1; + this->aics[param_1].minimumBread = -1; this->aics[param_1].minimumWheat = 2; - this->aics[param_1].minimumHop = 2; - this->aics[param_1].tradeAmountFood = 5; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x28; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 5; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 0x32; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 6; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 4; - this->aics[param_1].maxIronmines = 2; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 0; - this->aics[param_1].buildInterval = 2; - this->aics[param_1].resourceRebuildDelay = 0x28; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource03 = 6; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x50; - this->aics[param_1].recruitProbDefDefault = 0x28; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 10; - this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].recruitProbAttackDefault = 0x28; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].SortieUnitMeleeMin = 0x14; - this->aics[param_1].SortieUnitMelee = 0x25; - this->aics[param_1].DefWalls = 0x1e; - this->aics[param_1].DefTotal = 0x1e; - this->aics[param_1].RaidUnitsBase = 0x1e; - this->aics[param_1].RaidUnitsRandom = 10; - this->aics[param_1].RaidUnit1 = 0x25; - this->aics[param_1].HarassingSiegeEnginesMax = 5; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].AttForceBase = 0x32; - this->aics[param_1].AttForceRandom = 10; - this->aics[param_1].AttForceSupportAllyThreshold = 0x28; - this->aics[param_1].AttForceRallyPercentage = 0x50; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x50; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].SiegeEngine2 = 0x27; - this->aics[param_1].SiegeEngine3 = 0x27; - this->aics[param_1].SiegeEngine4 = 0x27; - this->aics[param_1].AttMaxEngineers = 8; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 10; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x28; - this->aics[param_1].AttUnitBackupGroupsCount = 1; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x25; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; - return; } - } } From 84f90bfad9c9650e5f1335095a6d97b4fe072561 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Mon, 17 Aug 2026 21:08:23 +0200 Subject: [PATCH 050/242] improve setAICParameters --- src/OpenSHC/AI/AICState/setAICParameters_07.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp index 9e00fc0d3..589ad5bd9 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp @@ -22,10 +22,6 @@ namespace AI { this->aics[param_1].minimumHop = -1; - this->aics[param_1].maxEquipment = 5; - - this->aics[param_1].maxResourceVariance = 5; - this->aics[param_1].flagType = 10; this->aics[param_1].unknown002 = 0; @@ -74,8 +70,12 @@ namespace AI { this->aics[param_1].maxResourceOther = 10; + this->aics[param_1].maxEquipment = 5; + this->aics[param_1].maxBeer = 0x14; + this->aics[param_1].maxResourceVariance = 5; + this->aics[param_1].recruitGoldThreshold = 200; this->aics[param_1].populationPerWoodcutter = 2; From 46e45fcc5ce221e4c940175dc137cc863bd944ba Mon Sep 17 00:00:00 2001 From: Gynt Date: Thu, 17 Sep 2026 10:31:38 +0200 Subject: [PATCH 051/242] progress --- .../useAITribe_0xe_toPlaceTunnels.cpp | 71 ++++++++----------- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp index 3f47b3277..7e6f75cc3 100644 --- a/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp +++ b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/TroopValueState.func.hpp" #include "OpenSHC/AI/AIType.hpp" @@ -20,60 +21,44 @@ namespace AI { using OpenSHC::Map::Units::SomeTribeBehaviorType; using OpenSHC::Map::Units::UnitInstructionType; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CF180 - void AICState ::useAITribe_0xe_toPlaceTunnels(int playerID) - + void AICState::useAITribe_0xe_toPlaceTunnels(int playerID) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; + int _aiTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xe]; + if (_aiTribeID == 0) + return; + if (DAT_TribesState::instance.tribes[_aiTribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xe]) + return; + short _size = DAT_TribesState::instance.tribes[_aiTribeID].size; - int _aiTribeID; - - uint _unitID; + for (int _countdown = _size; (_size != 0 && (0 < _countdown)); _countdown--) { - int _tribeID; + int _unitID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::popUnitFromTribe, DAT_TribesState::ptr)(_aiTribeID); - int _countdown; + int _tribeID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - short _size; - - if (((DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) - && (_aiTribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xe], - _aiTribeID != 0)) - && (DAT_TribesState::instance.tribes[_aiTribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xe])) { - - _size = DAT_TribesState::instance.tribes[_aiTribeID].size; + DAT_TribesState::instance.tribes[_tribeID].attackWave + = DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; - for (_countdown = (int)_size; (_size != 0 && (0 < _countdown)); _countdown = _countdown + -1) { + DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_TUNNELERS; - _unitID = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::popUnitFromTribe, DAT_TribesState::ptr)(_aiTribeID); + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x415; - _tribeID = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + _unitID, _tribeID); - DAT_TribesState::instance.tribes[_tribeID].attackWave - = (short)DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TroopValueState_Func::placeSiegeTentOrTunnelAtSuitableLocationAndAssignEngineers, + DAT_TroopValueState::ptr)( + _tribeID, OpenSHC::Commands::M_MAPPER_TUNNEL_CONSTRUCTION, 50, (UnitInstructionType)21); - DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_TUNNELERS; - - DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x415; - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( - _unitID, _tribeID); - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func:: - placeSiegeTentOrTunnelAtSuitableLocationAndAssignEngineers, - DAT_TroopValueState::ptr)(_tribeID, OpenSHC::Commands::M_MAPPER_TUNNEL_CONSTRUCTION, - (uint)((int)(50)), (UnitInstructionType)((int)(21))); - - _size = DAT_TribesState::instance.tribes[_aiTribeID].size; - } + _size = DAT_TribesState::instance.tribes[_aiTribeID].size; } - - return; } } From 8de227d390e23bb2abf561e7fe8b68afd81e4406 Mon Sep 17 00:00:00 2001 From: Gynt Date: Thu, 17 Sep 2026 10:37:19 +0200 Subject: [PATCH 052/242] reimplement: SHC_3BB0A8C1_0x004CF180 100% --- .../AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp | 10 ++++++---- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp index 7e6f75cc3..f9a3597ee 100644 --- a/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp +++ b/src/OpenSHC/AI/AICState/useAITribe_0xe_toPlaceTunnels.cpp @@ -32,12 +32,16 @@ namespace AI { if (DAT_TribesState::instance.tribes[_aiTribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xe]) return; - short _size = DAT_TribesState::instance.tribes[_aiTribeID].size; + int _countdown = DAT_TribesState::instance.tribes[_aiTribeID].size; - for (int _countdown = _size; (_size != 0 && (0 < _countdown)); _countdown--) { + while (DAT_TribesState::instance.tribes[_aiTribeID].size != 0) { + if (_countdown <= 0) + break; int _unitID = MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::popUnitFromTribe, DAT_TribesState::ptr)(_aiTribeID); + // Yes this line has to be right here for the code to match. + _countdown--; int _tribeID = MACRO_CALL_MEMBER( OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); @@ -56,8 +60,6 @@ namespace AI { OpenSHC::Map::Units::TroopValueState_Func::placeSiegeTentOrTunnelAtSuitableLocationAndAssignEngineers, DAT_TroopValueState::ptr)( _tribeID, OpenSHC::Commands::M_MAPPER_TUNNEL_CONSTRUCTION, 50, (UnitInstructionType)21); - - _size = DAT_TribesState::instance.tribes[_aiTribeID].size; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b80b8635f..64fd1bd3a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35351,7 +35351,7 @@ SHC_3BB0A8C1_0x004CEFD0 | 0.0% | Pending SHC_3BB0A8C1_0x004CF060 | 0.0% | Pending -SHC_3BB0A8C1_0x004CF180 | 0.0% | Pending +SHC_3BB0A8C1_0x004CF180 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CF270 | 0.0% | Pending From fbe8032176199695f62e8f3fef22401535111137 Mon Sep 17 00:00:00 2001 From: Gynt Date: Thu, 17 Sep 2026 10:47:04 +0200 Subject: [PATCH 053/242] reimplement: SHC_3BB0A8C1_0x004CEFD0 100% --- ...12_toPlaceSiegeTentsAndAssignEngineers.cpp | 235 +++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 68 insertions(+), 169 deletions(-) diff --git a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp index f3e1e0afa..7bc2f8ea6 100644 --- a/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp +++ b/src/OpenSHC/AI/AICState/useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers.cpp @@ -23,183 +23,82 @@ namespace AI { using OpenSHC::Map::Units::SomeTribeBehaviorType; using OpenSHC::Map::Units::UnitInstructionType; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CEFD0 - void AICState ::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers(int playerID) - + void AICState::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers(int playerID) { - - AITypeInt AVar1; - - int iVar2; - - int _counterTill6; - - int _selectionID2; - - int iVar3; - - int* piVar4; - - MappersEnum _siegeEngineType; - - int iVar5; - - int _counterTill8; - - int _aiTribeID; - - int* _siegeEngineUnitType; - - int local_18; - + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (_aiType == OpenSHC::AI::AIT_NULL) + return; + int _aicIndex = _aiType - 1; + int _aiTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; + if (_aiTribeID == 0) + return; + if (DAT_TribesState::instance.tribes[_aiTribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12]) + return; + + int _availableEngineers = DAT_TribesState::instance.tribes[_aiTribeID].size; int _requiredEngineers; + int _totalRequiredEngineers = 0; + + for (int i = 0; i < 8; i++) { + if ((&this->aics[_aicIndex].SiegeEngine1)[i] <= 0) + break; + for (int j = 0; j < 6; j++) { + if ((&this->aics[_aicIndex].SiegeEngine1)[i] + == DAT_SkirmishDefinedData::instance.SiegeEngineUnitType[j]) { + _requiredEngineers = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[j]; + break; + } + } + if (_totalRequiredEngineers + _requiredEngineers > _availableEngineers) + break; + _totalRequiredEngineers += _requiredEngineers; + } - short _currentAttackWave; - - short _size; - - AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar1 != OpenSHC::AI::AIT_NULL) { - - _aiTribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; - - if ((_aiTribeID != 0) - && (DAT_TribesState::instance.tribes[_aiTribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { - - _size = DAT_TribesState::instance.tribes[_aiTribeID].size; - - local_18 = (int)_size; - - iVar3 = 0; - - _siegeEngineUnitType = (int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x214); - - piVar4 = _siegeEngineUnitType; - - iVar5 = 0; - - do { - - if (*piVar4 < 1) - break; - - iVar2 = 0; - - do { - - if (*piVar4 == DAT_SkirmishDefinedData::instance.SiegeEngineUnitType[iVar2]) { - - _requiredEngineers - = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[iVar2]; - - break; - } - - iVar2 = iVar2 + 1; - - } while (iVar2 < 6); - - iVar2 = _requiredEngineers + iVar5; - - if (local_18 < iVar2) - break; - - iVar3 = iVar3 + 1; - - piVar4 = piVar4 + 1; - - iVar5 = iVar2; - - } while (iVar3 < 8); - - if (0 < iVar5) { - - for (; (_size != 0 && (0 < iVar5)); iVar5 = iVar5 + -1) { - - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::popUnitFromTribe, DAT_TribesState::ptr)(_aiTribeID); - - _size = DAT_TribesState::instance.tribes[_aiTribeID].size; - } - - _counterTill8 = 0; - - /* - fixme: parameter reuse */ - - _siegeEngineType = (MappersEnum)playerID; - - do { - - if (*_siegeEngineUnitType < 1) { - - return; - } - - _counterTill6 = 0; - - do { - - if (*_siegeEngineUnitType - == DAT_SkirmishDefinedData::instance.SiegeEngineUnitType[_counterTill6]) { - - _requiredEngineers - = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[_counterTill6]; - - _siegeEngineType = (MappersEnum)DAT_SkirmishDefinedData::instance - .SiegeEngineCommandBuildingTypes[_counterTill6]; - - break; - } - - _counterTill6 = _counterTill6 + 1; - - } while (_counterTill6 < 6); - - if (local_18 < _requiredEngineers) { - - return; - } - - local_18 = local_18 - _requiredEngineers; - - _selectionID2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToSelection, this)( - playerID, _requiredEngineers); - - if (_selectionID2 == 0) { - - return; - } - - _currentAttackWave = (short)DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; - - DAT_TribesState::instance.tribes[_selectionID2].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; - - DAT_TribesState::instance.tribes[_selectionID2].tribeBehaviorType - = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - - DAT_TribesState::instance.tribes[_selectionID2].attackWave = _currentAttackWave; - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func:: - placeSiegeTentOrTunnelAtSuitableLocationAndAssignEngineers, - DAT_TroopValueState::ptr)( - _selectionID2, _siegeEngineType, (uint)((int)(60)), (UnitInstructionType)((int)(15))); - - _counterTill8 = _counterTill8 + 1; + if (_totalRequiredEngineers <= 0) + return; - _siegeEngineUnitType = _siegeEngineUnitType + 1; + for (; DAT_TribesState::instance.tribes[_aiTribeID].size != 0; _totalRequiredEngineers--) { + if (_totalRequiredEngineers <= 0) + break; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::popUnitFromTribe, DAT_TribesState::ptr)( + _aiTribeID); + } - } while (_counterTill8 < 8); + MappersEnum _siegeEngineType; + for (int i = 0; i < 8; i++) { + if ((&this->aics[_aicIndex].SiegeEngine1)[i] <= 0) + return; + for (int j = 0; j < 6; j++) { + if ((&this->aics[_aicIndex].SiegeEngine1)[i] + == DAT_SkirmishDefinedData::instance.SiegeEngineUnitType[j]) { + _requiredEngineers = DAT_SkirmishDefinedData::instance.SiegeEngineTypeRequiredEngineers[j]; + _siegeEngineType + = (MappersEnum)DAT_SkirmishDefinedData::instance.SiegeEngineCommandBuildingTypes[j]; + break; } } + if (_requiredEngineers > _availableEngineers) + return; + _availableEngineers -= _requiredEngineers; + + int _tribeID + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToSelection, this)( + playerID, _requiredEngineers); + if (_tribeID == 0) + return; + + DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + DAT_TribesState::instance.tribes[_tribeID].attackWave + = DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; + + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TroopValueState_Func::placeSiegeTentOrTunnelAtSuitableLocationAndAssignEngineers, + DAT_TroopValueState::ptr)(_tribeID, _siegeEngineType, 60, (UnitInstructionType)15); } - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 64fd1bd3a..45e76320c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35347,7 +35347,7 @@ SHC_3BB0A8C1_0x004CED90 | 0.0% | Pending SHC_3BB0A8C1_0x004CEEA0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CEFD0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CEFD0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CF060 | 0.0% | Pending From fae9941086433c58103c44b39f2495ea05978965 Mon Sep 17 00:00:00 2001 From: Gynt Date: Thu, 17 Sep 2026 10:51:05 +0200 Subject: [PATCH 054/242] reimplement: SHC_3BB0A8C1_0x004D4940 100% --- .../AI/AICState/updateTribeLocations.cpp | 54 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 25 insertions(+), 31 deletions(-) diff --git a/src/OpenSHC/AI/AICState/updateTribeLocations.cpp b/src/OpenSHC/AI/AICState/updateTribeLocations.cpp index d84f52f91..b8f7db9a6 100644 --- a/src/OpenSHC/AI/AICState/updateTribeLocations.cpp +++ b/src/OpenSHC/AI/AICState/updateTribeLocations.cpp @@ -12,51 +12,45 @@ namespace AI { using OpenSHC::AI::AITypeInt; // FUNCTION: STRONGHOLDCRUSADER 0x004D4940 - void AICState ::updateTribeLocations(int playerID) - + void AICState::updateTribeLocations(int playerID) { + AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - AITypeInt AVar2; - - AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar2 != OpenSHC::AI::AIT_NULL) { - - DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter = - DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter + 1; + if (_aiType == OpenSHC::AI::AIT_NULL) { + return; + } - if (DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter - >= *(int*)((int)this + AVar2 * 0x2a4 - 0x194)) { + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter + = DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter + 1; - DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits = - DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits + 1; + if (DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter + >= this->aics[_aiType - 1].defWallPatrolRallyTime) { - DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter = 0; - } + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits + = DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits + 1; - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::ifHasTribe0SendUnitsToKeep, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeWaitCounter = 0; + } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeAtOffset1ToCampfire, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::ifHasTribe0SendUnitsToKeep, this)(playerID); - if (DAT_GameState::instance.mapAndTime.monthTicks == playerID) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeAtOffset1ToCampfire, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::digNearestMoat, this)(playerID); - } + if (DAT_GameState::instance.mapAndTime.monthTicks == playerID) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendRangedUnitTribesToAIVSlotsOrKeepIfNervous, this)( - playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::digNearestMoat, this)(playerID); + } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed, - this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendRangedUnitTribesToAIVSlotsOrKeepIfNervous, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendWallPatrolUnitTribesToAIVLocations, this)(playerID); + MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendOilMenForOilPickupOrToAIVLocations, this)(playerID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendWallPatrolUnitTribesToAIVLocations, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiGiveOuterPatrolCommand, this)(playerID); - } + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendOilMenForOilPickupOrToAIVLocations, this)(playerID); - return; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiGiveOuterPatrolCommand, this)(playerID); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 45e76320c..784bf9d20 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35557,7 +35557,7 @@ SHC_3BB0A8C1_0x004D4870 | 0.0% | Pending SHC_3BB0A8C1_0x004D48F0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D4940 | 0.0% | Pending +SHC_3BB0A8C1_0x004D4940 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D49E0 | 0.0% | Pending From 438ae4380a04031e9aea0af4cb7fb0e8a4be19ac Mon Sep 17 00:00:00 2001 From: Gynt Date: Thu, 17 Sep 2026 14:32:31 +0200 Subject: [PATCH 055/242] reimplement: SHC_3BB0A8C1_0x004D3320 87.69%, effectively 100% --- .../AI/AICState/updateAIStrengthState.cpp | 271 ++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 118 insertions(+), 155 deletions(-) diff --git a/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp index 8ff7b1851..ab8f7dd45 100644 --- a/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp @@ -24,13 +24,13 @@ namespace AI { using OpenSHC::WindowsHelper::Enums::BOOLEnum; // FUNCTION: STRONGHOLDCRUSADER 0x004D3320 - void AICState ::updateAIStrengthState(int playerID, int aiRecruitUnitChoicePreference) + void AICState::updateAIStrengthState(int playerID, int aiRecruitUnitChoicePreference) { int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (_aiType == 0) return; - if ((char)aiRecruitUnitChoicePreference == '\0') { + if ((char)aiRecruitUnitChoicePreference == 0) { if (DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) return; if (DAT_GameCore::instance.isSkirmishTrail != TRUE) @@ -39,212 +39,175 @@ namespace AI { return; } - int _aiTypeMin1 = _aiType + -1; + int _aicIndex = _aiType - 1; + int _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 0; - - if (_currentGold >= 200) - DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = (1999 < _currentGold) + 1; + if (_currentGold < 200) + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 0; + else if (_currentGold < 2000) + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 1; + else + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState = 2; int _currentPopulation = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; - if (15 < _currentPopulation) { - int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + if (_currentPopulation >= 15) { if (_currentPopulation < 40) - *piVar1 = *piVar1 + 1; + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState += 1; else - *piVar1 = *piVar1 + 2; + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState += 2; } int _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; - if (20 < _totalFood) { - int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + if (_totalFood >= 20) { if (_totalFood < 200) - *piVar1 = *piVar1 + 1; + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState += 1; else - *piVar1 = *piVar1 + 2; + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState += 2; } int _totalTroopCount = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk + DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; - if (7 < _totalTroopCount) { - int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; + if (_totalTroopCount >= 8) { if (_totalTroopCount < 40) - *piVar1 = *piVar1 + 2; + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState += 2; else - *piVar1 = *piVar1 + 4; + DAT_GameState::instance.playerDataArray[playerID].aiStrengthState += 4; } - int _aiStrengthState = DAT_GameState::instance.playerDataArray[playerID].aiStrengthState; - if (_aiStrengthState < 3) + if (DAT_GameState::instance.playerDataArray[playerID].aiStrengthState <= 2) DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; - else if (_aiStrengthState < 8) + else if (DAT_GameState::instance.playerDataArray[playerID].aiStrengthState <= 7) DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_DEFAULT; else DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_STRONG; - if ((DAT_GameState::instance.playerDataArray[playerID].aivCurrentPauseIndex == 1) - && (0 < DAT_GameState::instance.playerDataArray[playerID].aivPauses[1])) + // while the first AIV pause is still running, the AI always feels weak + if (DAT_GameState::instance.playerDataArray[playerID].aivCurrentPauseIndex == 1 + && DAT_GameState::instance.playerDataArray[playerID] + .aivPauses[DAT_GameState::instance.playerDataArray[playerID].aivCurrentPauseIndex] + > 0) DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; - int _aicOffset = DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + _aiTypeMin1 * 169; - int _recruitProbRaid = *(int*)((int)this + _aicOffset * 4 + 0x134); - int _recruitProbDefensive = *(int*)((int)this + _aicOffset * 4 + 0x128); - int _totalRecruitProb = *(int*)((int)this + _aicOffset * 4 + 0x140) + _recruitProbRaid + _recruitProbDefensive; - - int _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_ATTACKING; - bool bVar3 = false; - int _subtraction = 0; - bool _needsCheck = false; - - if (_totalRecruitProb == 0) { - _aiRecruitUnitChoiceState = aiRecruitUnitChoicePreference; - if (aiRecruitUnitChoicePreference == 1) { - int _raidUnitCount = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(_aiTypeMin1, playerID); - int _totalDefTroops = DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk; - bVar3 = (_totalDefTroops < _raidUnitCount); - _subtraction = _totalDefTroops - _raidUnitCount; - _needsCheck = true; - } else if (aiRecruitUnitChoicePreference == 0) { - int _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; - int _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); - bVar3 = (_totalRaidTroops < _defTotal); - _subtraction = _totalRaidTroops - _defTotal; - _needsCheck = true; - } - } else { - int _rng = (int)SEC_RNG::instance.currentNumber2; + // the three recruitProb* triples are laid out as Default, Weak, Strong, matching AIStrengthType + int _aiStrengthFeeling = DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling; + int _recruitProbDefensive = (&this->aics[_aicIndex].recruitProbDefDefault)[_aiStrengthFeeling]; + int _recruitProbAttack = (&this->aics[_aicIndex].recruitProbAttackDefault)[_aiStrengthFeeling]; + int _recruitProbRaid = (&this->aics[_aicIndex].recruitProbRaidDefault)[_aiStrengthFeeling]; + int _totalRecruitProb = _recruitProbAttack + _recruitProbRaid + _recruitProbDefensive; + + int _aiRecruitUnitChoice; + if (_totalRecruitProb != 0) { + int _random = SEC_RNG::instance.currentNumber2 % _totalRecruitProb; MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - if ((int)DAT_GameCore::instance.mapTimeInTicks < 4800) { - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - int _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; - int _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); - bVar3 = (_totalRaidTroops < _defTotal); - _subtraction = _totalRaidTroops - _defTotal; - _needsCheck = true; - } else if (_rng % _totalRecruitProb < _recruitProbDefensive) { - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - int _totalRaidTroops = DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk; - int _defTotal = *(int*)((int)this + _aiTypeMin1 * 676 + 0x170); - bVar3 = (_totalRaidTroops < _defTotal); - _subtraction = _totalRaidTroops - _defTotal; - _needsCheck = true; - } else if (_rng % _totalRecruitProb < _recruitProbRaid + _recruitProbDefensive) { - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_RAIDING; - int _raidUnitCount = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(_aiTypeMin1, playerID); - int _totalDefTroops = DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk; - bVar3 = (_totalDefTroops < _raidUnitCount); - _subtraction = _totalDefTroops - _raidUnitCount; - _needsCheck = true; - } + if ((int)DAT_GameCore::instance.mapTimeInTicks < 4800) + _aiRecruitUnitChoice = OpenSHC::AI::AIRUC_DEFENSIVE; + else if (_random < _recruitProbDefensive) + _aiRecruitUnitChoice = OpenSHC::AI::AIRUC_DEFENSIVE; + else if (_random < _recruitProbRaid + _recruitProbDefensive) + _aiRecruitUnitChoice = OpenSHC::AI::AIRUC_RAIDING; + else + _aiRecruitUnitChoice = OpenSHC::AI::AIRUC_ATTACKING; + } else { + _aiRecruitUnitChoice = aiRecruitUnitChoicePreference; } - if (!_needsCheck || !(bVar3 == (_subtraction < 0))) - _aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_ATTACKING; + if (_aiRecruitUnitChoice == OpenSHC::AI::AIRUC_RAIDING) { + if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk + >= MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( + _aicIndex, playerID)) + _aiRecruitUnitChoice = OpenSHC::AI::AIRUC_ATTACKING; + } else if (_aiRecruitUnitChoice == OpenSHC::AI::AIRUC_DEFENSIVE) { + if (DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk + >= this->aics[_aicIndex].DefTotal) + _aiRecruitUnitChoice = OpenSHC::AI::AIRUC_ATTACKING; + } - if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState != _aiRecruitUnitChoiceState) - DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = _aiRecruitUnitChoiceState; + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState != _aiRecruitUnitChoice) + DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = _aiRecruitUnitChoice; - if ((char)aiRecruitUnitChoicePreference == '\0') + if ((char)aiRecruitUnitChoicePreference == 0) return; - if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) { - BOOLEnum _teamWeak = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, TRUE); - if (_teamWeak == FALSE) { + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { + if (!MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, TRUE)) { DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = 0; return; } - int _currentGold_2 = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; + + int _gold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - if (_currentGold_2 < 500) { - int _aiNervAct = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; - if (_aiNervAct < 8) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); - } else if (!(5 < _aiNervAct)) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); - } - } else { - short* psVar2 = &DAT_GameState::instance.playerDataArray[playerID].aiStateCounter; - *psVar2 = *psVar2 + 1; - if ((2500 < _currentGold_2) - && ((DAT_GameState::instance.playerDataArray[playerID].aiStateCounter & 1U) != 0) - && (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 20)) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::shareGoldAmongTeamMembers, this)( - playerID, _currentGold_2 / 10); + if (_gold > 500) { + if (_gold > 2500) { + DAT_GameState::instance.playerDataArray[playerID].aiStateCounter++; + if ((DAT_GameState::instance.playerDataArray[playerID].aiStateCounter & 1) + && DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy + <= 20) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::shareGoldAmongTeamMembers, this)( + playerID, _gold / 10); + } } + } else if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 7) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); + } else if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 5) { + // unreachable in the original as well: anything <= 5 is already handled by the <= 7 branch + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); } - int _aiNervAct2 = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; - if (_aiNervAct2 < 2) - return; - DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = _aiNervAct2 + -1; + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 1) + DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker--; return; } - int _aiBuildDestroyTracker = DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; - - if (_aiBuildDestroyTracker < 1) { - BOOLEnum _teamWeak2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)(playerID, FALSE); - if (_teamWeak2 != FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playNervous2BikFromPlayer, this)(playerID); - DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = 8; - DAT_GameState::instance.playerDataArray[playerID].aiStateCounter = 0; + int _destroyChoice = DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker; + if (_destroyChoice > 0) { + if (!MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID)) { + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 0; return; } - BOOLEnum _outOfSupplies = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); - if (_outOfSupplies == FALSE) - return; - DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 8; - return; - } - BOOLEnum _outOfSupplies2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID); - if (_outOfSupplies2 == FALSE) { - DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 0; - return; - } + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] = 20; + DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; + DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; - DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] = 20; - DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling = OpenSHC::AI::AIST_WEAK; - DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState = OpenSHC::AI::AIRUC_DEFENSIVE; + if (_destroyChoice == 8) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS); + } else if (_destroyChoice == 7) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); + } else if (_destroyChoice == 6) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_GATEHOUSES_TOWERS_GUILDS); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_BARRACKS_MERCPOST_STABLES); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_WATER_BUILDINGS); + } else if (_destroyChoice == 5) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); + } else if (_destroyChoice == 4) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( + playerID, OpenSHC::AI::AINDBC_FARMS); + } - if (_aiBuildDestroyTracker == 8) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_FEAR_FACTOR_BUILDINGS); - } else if (_aiBuildDestroyTracker == 7) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS); DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; - return; - } else if (_aiBuildDestroyTracker == 6) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_GATEHOUSES_TOWERS_GUILDS); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_BARRACKS_MERCPOST_STABLES); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_WATER_BUILDINGS); - DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; - return; - } else if (_aiBuildDestroyTracker == 5) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_RESOURCE_BUILDINGS); - DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; - return; - } else if (_aiBuildDestroyTracker == 4) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::destroyAnyBuildingInCategory, this)( - playerID, OpenSHC::AI::AINDBC_FARMS); + } else if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::teamIsWeakRelativeToEnemy, this)( + playerID, FALSE)) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playNervous2BikFromPlayer, this)(playerID); + DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker = 8; + DAT_GameState::instance.playerDataArray[playerID].aiStateCounter = 0; + } else if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNotEnoughSupplies, this)(playerID)) { + DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker = 8; } - - DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker--; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 784bf9d20..938d239c4 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35511,7 +35511,7 @@ SHC_3BB0A8C1_0x004D2F80 | 0.0% | Pending SHC_3BB0A8C1_0x004D30E0 | 0.0% | Pending -SHC_3BB0A8C1_0x004D3320 | 0.0% | Pending +SHC_3BB0A8C1_0x004D3320 | 87.69% | Reimplemented, different register usage, effectively 100% SHC_3BB0A8C1_0x004D3780 | 0.0% | Pending From 0b8e107821fbe8915d929daaa9f046563abef0d4 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Thu, 17 Sep 2026 22:32:13 +0200 Subject: [PATCH 056/242] reimplement: SHC_3BB0A8C1_0x004D49E0 52.84% --- .../AI/AICState/updateAIPlayerState.cpp | 218 ++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 101 insertions(+), 119 deletions(-) diff --git a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp index c0bee72c5..0a242e001 100644 --- a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp @@ -4,7 +4,6 @@ #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" @@ -16,46 +15,36 @@ namespace OpenSHC { namespace AI { using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - // Helper shared by state 4 (canNavigate==FALSE) and state 6 (canUnitsNavigate==FALSE) - __forceinline static void recomputeAndReset(OpenSHC::AI::AICState* pThis, int playerID) - { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, pThis)(playerID, 0); - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, pThis)(playerID); - DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 = 0; - } - // FUNCTION: STRONGHOLDCRUSADER 0x004D49E0 - void AICState ::updateAIPlayerState(int playerID) + void AICState::updateAIPlayerState(int playerID) { - AITypeInt AVar4 = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (AVar4 == OpenSHC::AI::AIT_NULL) + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) return; + int _aicIndex = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; - int _aiType = AVar4 + ~OpenSHC::AI::AIT_NULL; - - int iVar5 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; - if (((iVar5 != 1) && (iVar5 == 2)) - && (iVar5 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk), - iVar5 != 0)) { + // an ally asked for help and is still alive: drop everything and go to their keep + if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk != 1 + && DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2 + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk)) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToPlayerIDsKeepIfPossible, this)( - playerID, ((int)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk))); + playerID, DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk); return; } int _aiPlayerState = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; - if (_aiPlayerState == 0) { - BOOLEnum _shouldAttack = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::aiShouldAttackOrWaitForTeamCoordination, this)(playerID); - if (_shouldAttack == FALSE) { + if (!MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiShouldAttackOrWaitForTeamCoordination, this)( + playerID)) { + // send own units back to keep or campfire MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRetreatUnits, this)(playerID); return; } + + // proceed with attack DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 1; DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue = 0; @@ -63,26 +52,24 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackCoordinationLevel, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackStrength, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackRaidParameter, this)(playerID); - int* piVar2 = (int*)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID * 0x39f4 + 0x115e9d4 - + playerID * 0x20); - *piVar2 = *piVar2 + 1; - } else { - BOOLEnum BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID); - if ((((BVar6 != FALSE) && (_aiPlayerState != 9)) - || ((0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker - && (_aiPlayerState < 6)))) - || (199 < DAT_GameState::instance.playerDataArray[playerID].attackTicker)) - DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 8; + // fixme: struct layout. This looks like an int[10][8] attack tracker starting at + // attackedByPlayerArrayUnk (0x2BDC) and ending where aivUnitLocationSlots begins (0x2D1C). + (&DAT_GameState::instance.playerDataArray[DAT_GameState::instance.playerDataArray[playerID] + .attackedPlayerID] + .attackedByPlayerArrayUnk)[playerID * 8]++; + } else if ((MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID) + && _aiPlayerState != 9) + || (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0 && _aiPlayerState <= 5) + || DAT_GameState::instance.playerDataArray[playerID].attackTicker >= 200) { + DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 8; } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearRallyFlagOnAllAIAttackTribes, this)(playerID); - int _attackedPlayerAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - - if (_attackedPlayerAlive == 0) { - iVar5 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; - if (iVar5 < 4) { + if (!MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) { + // attacked player is dead + if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState <= 3) { DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); MACRO_CALL_MEMBER( @@ -93,37 +80,36 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)( playerID); - } else if (iVar5 < 7) { + } else if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState < 7) { DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 7; } } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::clearOutdatedAITribes, this)(playerID); - int _aiPlayerState_2 = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; - BOOLEnum BVar6; - int* piVar2; + _aiPlayerState = DAT_GameState::instance.playerDataArray[playerID].aiPlayerState; - if (_aiPlayerState_2 == 1) { + if (_aiPlayerState == 1) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recreateEngineersTribe, this)(playerID); DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 2; MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::initializeGatePathfindingForOwner, DAT_BuildingsState::ptr)(playerID); + // computes the first siege location for units MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeEnemyKeepApproachTile, this)(playerID); - if (0 < DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile) { + if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile > 0) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackTribesToLocations, this)(playerID); return; } - // state 1 with no path: reset to 0 + // no approach tile found: back to idle DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; return; } - if (_aiPlayerState_2 == 2) { - uint _rallyReady - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID); - if (_rallyReady == 0) + if (_aiPlayerState == 2) { + // gathering: wait until enough of the attack force has rallied + if (!MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiChoiceAttForceRallyPercentage, this)(playerID)) return; + // send the attacking units to move closer DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 3; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::useAITribe_0x12_toPlaceSiegeTentsAndAssignEngineers, this)( playerID); @@ -138,14 +124,13 @@ namespace AI { return; } - if (_aiPlayerState_2 == 3) { - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - *piVar2 = *piVar2 + 1; + if (_aiPlayerState == 3) { + // send the attacking units closer to the castle + DAT_GameState::instance.playerDataArray[playerID].attackTicker++; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); - BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::processAttForceRallyPercentage, this)(playerID); - if (BVar6 == FALSE) + if (!MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::processAttForceRallyPercentage, this)(playerID)) return; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); @@ -155,29 +140,28 @@ namespace AI { return; } - if (_aiPlayerState_2 == 4) { - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - *piVar2 = *piVar2 + 1; + if (_aiPlayerState == 4) { + // siege: wait AttAssaultDelay (skipped without siege engines) before the assault + DAT_GameState::instance.playerDataArray[playerID].attackTicker++; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::moveAttackingUnitsToNextRallyPoint, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandSiegeEngineTribes, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAttack, this)(playerID); - iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::countSiegeEngineUnits, this)(playerID); - if (iVar5 < 1) + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::countSiegeEngineUnits, this)(playerID) <= 0) DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue = 100; - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue; - *piVar2 = *piVar2 + 1; + DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue++; if (DAT_GameState::instance.playerDataArray[playerID].attackAssaultDelayRelatedValue - <= ((int)this->aics[_aiType].AttAssaultDelay)) + <= this->aics[_aicIndex].AttAssaultDelay) return; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocationFullVolume, DAT_SFXState::ptr)( DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, 0x14); - BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - if (BVar6 == FALSE) { + if (!MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) { + // castle is closed: attack the walls DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe11StandGroundToGate, this)(playerID); @@ -191,16 +175,14 @@ namespace AI { return; } - if (_aiPlayerState_2 == 5) { - if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) + if (_aiPlayerState == 5) { + // attack walls + if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile <= 0) DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; - short* psVar1 = &DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; - *psVar1 = *psVar1 + 1; - short sVar3 = DAT_GameState::instance.playerDataArray[playerID].unknownCounter01; - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - *piVar2 = *piVar2 + 1; + DAT_GameState::instance.playerDataArray[playerID].unknownCounter01++; + DAT_GameState::instance.playerDataArray[playerID].attackTicker++; DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; - if (3 < sVar3) { + if (DAT_GameState::instance.playerDataArray[playerID].unknownCounter01 >= 4) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandWallAssaultTribes, this)(playerID); @@ -218,38 +200,37 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xbToAggressiveAndAttack, this)(playerID); } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); - BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - if ((BVar6 == FALSE) - && (BVar6 = MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID), - BVar6 == FALSE)) + if (!MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID) + && !MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; return; } - if (_aiPlayerState_2 == 6) { - if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile < 1) + if (_aiPlayerState == 6) { + // enemy castle breached + if (DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile <= 0) DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].attackTicker; - *piVar2 = *piVar2 + 1; - int _playerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + DAT_GameState::instance.playerDataArray[playerID].attackTicker++; + int _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; DAT_GameState::instance.playerDataArray[playerID].someResourceCounter = 0; MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::calculateAttackVectorsToCampFireOfPlayer, - DAT_GameState::ptr)(_playerID); - iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToAttackBreachedCastle, this)(playerID); - if (iVar5 != 0) + DAT_GameState::ptr)(_attackedPlayerID); + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToAttackBreachedCastle, this)(playerID)) return; - BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - if (BVar6 != FALSE) + if (MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) return; - BVar6 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - if (BVar6 != FALSE) + if (MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) return; + // the breach got closed again: back to attacking the walls DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 0); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeAttackPossibilities, this)(playerID); @@ -257,16 +238,17 @@ namespace AI { return; } - if (_aiPlayerState_2 == 7) { - piVar2 = &DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue; - *piVar2 = *piVar2 + 1; + if (_aiPlayerState == 7) { + // target died mid-attack: linger for AttUnitPatrolRecommandDelay, then retreat + DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue++; if (DAT_GameState::instance.playerDataArray[playerID].unitPatrolRecommandRelatedDelayValue - <= ((int)this->aics[_aiType].AttUnitPatrolRecommandDelay)) + <= this->aics[_aicIndex].AttUnitPatrolRecommandDelay) return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); @@ -274,34 +256,34 @@ namespace AI { return; } - if (_aiPlayerState_2 == 8) { + if (_aiPlayerState == 8) { + // retreat from attack DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, - DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeUnitsGoDefensiveAndBackToSomeLocation, this)(playerID); - if (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker) - return; - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playAnger1BikFromPlayer, this)(playerID); + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0) + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playAnger1BikFromPlayer, this)(playerID); return; } - if (_aiPlayerState_2 == 9) { - DAT_GameState::instance.playerDataArray[playerID].attackTicker += 1; - if (((DAT_GameState::instance.playerDataArray[playerID].attackTicker < 20) - && (BVar6 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::percentageNonMovingTribesGTEAICSpecified, this)(playerID), - BVar6 == FALSE)) - && (BVar6 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID), - BVar6 == FALSE)) + if (_aiPlayerState == 9) { + // retreating: back to idle once the units are home (or after 20 ticks) + DAT_GameState::instance.playerDataArray[playerID].attackTicker++; + if (DAT_GameState::instance.playerDataArray[playerID].attackTicker < 20 + && !MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::percentageNonMovingTribesGTEAICSpecified, this)( + playerID) + && !MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID)) return; - // was LAB_004d4ff7 DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 0; } } + } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 938d239c4..3cb1a3ac4 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35559,7 +35559,7 @@ SHC_3BB0A8C1_0x004D48F0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D4940 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D49E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D49E0 | 52.84% | Register allocation differences, logic checks out SHC_3BB0A8C1_0x004D5010 | 100.0% | Reimplemented From badb10d373ab12db70b8beb35f2073452daa46b3 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Thu, 17 Sep 2026 22:38:08 +0200 Subject: [PATCH 057/242] reimplement: SHC_3BB0A8C1_0x004D53E0 100% --- src/OpenSHC/AI/AICState/updateAIBehaviour.cpp | 70 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 30 insertions(+), 42 deletions(-) diff --git a/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp index 094883871..c89ef1451 100644 --- a/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp +++ b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp @@ -2,8 +2,6 @@ #include "OpenSHC/Map/TileMapState.func.hpp" #include "OpenSHC/AI/AIRecruitUnitChoice.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" -#include "OpenSHC/Game/Player/PlayerData.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TileMapState.hpp" @@ -13,30 +11,25 @@ namespace AI { using OpenSHC::AI::AIRecruitUnitChoice; using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - using OpenSHC::Game::Player::PlayerData; // FUNCTION: STRONGHOLDCRUSADER 0x004D53E0 void AICState::updateAIBehaviour() { - if (DAT_GameState::instance.mapAndTime.dayTicks == 10) { + if (DAT_GameState::instance.mapAndTime.dayTicks == 10) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::makeOutpostTribesAttack, this)(); - } + // every AI gets its own tick of the day, week and month, so the work is spread out for (int _playerID = 1; _playerID < 9; _playerID++) { - // Compiler doesn't optimize it with ADJ() like it should, not sure why it doesn't do it. - PlayerData* const _pPlayerData = &DAT_GameState::instance.playerDataArray[_playerID]; - AITypeInt const _aiType = _pPlayerData->aiType; - - if (_aiType == OpenSHC::AI::AIT_NULL) + if (DAT_GameState::instance.playerDataArray[_playerID].aiType == OpenSHC::AI::AIT_NULL) continue; - if (_pPlayerData->playerDeathRelated != 0) + if (DAT_GameState::instance.playerDataArray[_playerID].playerDeathRelated != 0) continue; - if (_pPlayerData->lordKilledByPlayerID != 0) + if (DAT_GameState::instance.playerDataArray[_playerID].lordKilledByPlayerID != 0) continue; + int _aicIndex = DAT_GameState::instance.playerDataArray[_playerID].aiType - 1; if (DAT_GameState::instance.mapAndTime.dayTicks == _playerID) { - if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { + if (DAT_GameState::instance.mapAndTime.skirmishNoRushTicks == 0) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieRangedUnits, this)(_playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitSortieMeleeUnits, this)(_playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitUnits, this)(_playerID); @@ -50,36 +43,29 @@ namespace AI { } if (DAT_GameState::instance.mapAndTime.weekTicks == _playerID) { - if (DAT_GameState::instance.mapAndTime.totalNoRushTicks == 0) { + if (DAT_GameState::instance.mapAndTime.skirmishNoRushTicks == 0) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiRecruitEngineerForOilDuty, this)(_playerID); - } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateTribeLocations, this)(_playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIPlayerState, this)(_playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiUpdateTaxesAndRations, this)(_playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setFoodBuyPlan, this)(_playerID); - if (DAT_GameState::instance.mapAndTime.monthTicks != _playerID) { + // on the month tick the strength update happens below, with the nervousness handling enabled + if (DAT_GameState::instance.mapAndTime.monthTicks != _playerID) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 0); - } - if (_pPlayerData->aiRequestDelay != 0) { - _pPlayerData->aiRequestDelay -= 1; - } - if (_pPlayerData->nervousBikCountdown != 0) { - _pPlayerData->nervousBikCountdown -= 1; - } - if (_pPlayerData->someAiCountdown3 != 0) { - _pPlayerData->someAiCountdown3 -= 1; - } - if (_pPlayerData->someAiCountdown4 != 0) { - _pPlayerData->someAiCountdown4 -= 1; - } - if (_pPlayerData->someAiCountdown5 != 0) { - _pPlayerData->someAiCountdown5 -= 1; - } - if (_pPlayerData->someAiCountdown6 != 0) { - _pPlayerData->someAiCountdown6 -= 1; - } + if (DAT_GameState::instance.playerDataArray[_playerID].aiRequestDelay != 0) + DAT_GameState::instance.playerDataArray[_playerID].aiRequestDelay--; + if (DAT_GameState::instance.playerDataArray[_playerID].nervousBikCountdown != 0) + DAT_GameState::instance.playerDataArray[_playerID].nervousBikCountdown--; + if (DAT_GameState::instance.playerDataArray[_playerID].someAiCountdown3 != 0) + DAT_GameState::instance.playerDataArray[_playerID].someAiCountdown3--; + if (DAT_GameState::instance.playerDataArray[_playerID].someAiCountdown4 != 0) + DAT_GameState::instance.playerDataArray[_playerID].someAiCountdown4--; + if (DAT_GameState::instance.playerDataArray[_playerID].someAiCountdown5 != 0) + DAT_GameState::instance.playerDataArray[_playerID].someAiCountdown5--; + if (DAT_GameState::instance.playerDataArray[_playerID].someAiCountdown6 != 0) + DAT_GameState::instance.playerDataArray[_playerID].someAiCountdown6--; } if (DAT_GameState::instance.mapAndTime.monthTicks == _playerID) { @@ -90,12 +76,14 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::updateAIStrengthState, this)(_playerID, 1); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectAttackTarget, this)(_playerID); - if (_pPlayerData->aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_RAIDING) { - _pPlayerData->canStartSpending = 1; + if (DAT_GameState::instance.playerDataArray[_playerID].aiRecruitUnitChoiceState + == OpenSHC::AI::AIRUC_RAIDING) { + DAT_GameState::instance.playerDataArray[_playerID].canStartSpending = 1; } else { - // shouldSpend = recruitGoldThreshold < currentGold - _pPlayerData->canStartSpending = (uint)(((int)this->aics[_aiType - 1].recruitGoldThreshold) - < _pPlayerData->currentResources[0xf]); + // only spend on recruiting while gold is above the AIC's threshold + DAT_GameState::instance.playerDataArray[_playerID].canStartSpending + = DAT_GameState::instance.playerDataArray[_playerID].currentResources[0xf] + > this->aics[_aicIndex].recruitGoldThreshold; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3cb1a3ac4..c70e9b119 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35571,7 +35571,7 @@ SHC_3BB0A8C1_0x004D5370 | 0.0% | Pending SHC_3BB0A8C1_0x004D53A0 | 0.0% | Pending -SHC_3BB0A8C1_0x004D53E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D53E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D55D0 | 0.0% | Pending From 63c9ce9a4281d6bb869c47e5624b449db12aa0c9 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Thu, 17 Sep 2026 22:44:06 +0200 Subject: [PATCH 058/242] reimplement: SHC_3BB0A8C1_0x004CC8D0 100% --- .../AI/AICState/unitIDIsRangedOrArmored.cpp | 25 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp index ff18d5cb7..e71dc1e49 100644 --- a/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp +++ b/src/OpenSHC/AI/AICState/unitIDIsRangedOrArmored.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/Skirmish/SkirmishDefinedData.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" @@ -10,23 +11,17 @@ namespace AI { using OpenSHC::Game::Skirmish::SkirmishDefinedData; // FUNCTION: STRONGHOLDCRUSADER 0x004CC8D0 - undefined4 AICState ::unitIDIsRangedOrArmored(int unitID) - + undefined4 AICState::unitIDIsRangedOrArmored(int unitID) { - int _unitType = (int)(short)DAT_UnitsState::instance.units[unitID].unitType; - - SkirmishDefinedData* pSVar1 = DAT_SkirmishDefinedData::ptr; + int _unitType = DAT_UnitsState::instance.units[unitID].unitType; - do { - if (pSVar1->RangedAndArmoredUnits[0] == _unitType) - return (undefined4)(1); + for (int i = 0; i < 7; i++) { + if (DAT_SkirmishDefinedData::instance.RangedAndArmoredUnits[i] == _unitType) { + return TRUE; + } + } - pSVar1 = (SkirmishDefinedData*)(pSVar1->RangedAndArmoredUnits + 1); - - } while ((int)pSVar1 < 0xb3eb50); - - return (undefined4)(0); + return FALSE; } - } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c70e9b119..09bd698ce 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34883,7 +34883,7 @@ SHC_3BB0A8C1_0x004CC7B0 | 0.0% | Pending SHC_3BB0A8C1_0x004CC840 | 0.0% | Pending -SHC_3BB0A8C1_0x004CC8D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC8D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CC910 | 0.0% | Pending From 1d7d1df13fe0bc06b2c1d1e054ce713be5f87c83 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Thu, 17 Sep 2026 22:56:08 +0200 Subject: [PATCH 059/242] reimplement: SHC_3BB0A8C1_0x004D0190 100% --- .../AI/AICState/teamIsWeakRelativeToEnemy.cpp | 67 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp index 63e7743bd..178a39760 100644 --- a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp +++ b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp @@ -10,56 +10,45 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0190 BOOLEnum AICState::teamIsWeakRelativeToEnemy(int playerID, BOOLEnum param_2) { - short _relativeStrength; - int _totalEnemyTroopValue = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; - if (_totalEnemyTroopValue == 0) { + // strength of the own team in percent of the enemy strength + int _relativeStrength; + if (DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue == 0) { _relativeStrength = 100; } else { - _relativeStrength = (short)((DAT_GameState::instance.playerDataArray[playerID].totalTeamTroopValue * 100) - / _totalEnemyTroopValue); + _relativeStrength = DAT_GameState::instance.playerDataArray[playerID].totalTeamTroopValue * 100 + / DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; } DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy = _relativeStrength; - if (param_2 != FALSE) { - BOOLEnum BVar2 - = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); - if (BVar2 != FALSE) { - if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 0x46) { - return TRUE; - } - return FALSE; - } - if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { - if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 300) { - return TRUE; - } + + // the team counts as weak below a threshold that is lower with an enclosed keep + // and much higher during the first 12000 ticks + if (param_2) { + if (MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID)) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy >= 70) + return FALSE; + } else if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy >= 300) + return FALSE; + } else if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy + >= 100) { return FALSE; } - if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 100) { - return TRUE; - } } else { - if (DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue < 100) { + // without enemy ranged troops there is no reason to become nervous + if (DAT_GameState::instance.playerDataArray[playerID].totalEnemyRangedTroopValue < 100) return FALSE; - } - BOOLEnum BVar2 - = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); - if (BVar2 != FALSE) { - if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 50) { - return TRUE; - } - return FALSE; - } - if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { - if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 250) { - return TRUE; - } + if (MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID)) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy >= 50) + return FALSE; + } else if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { + if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy >= 250) + return FALSE; + } else if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy + >= 75) { return FALSE; } - if ((short)DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy < 75) { - return TRUE; - } } - return FALSE; + return TRUE; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 09bd698ce..e28bffeb2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35397,7 +35397,7 @@ SHC_3BB0A8C1_0x004D00A0 | 0.0% | Pending SHC_3BB0A8C1_0x004D0110 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D0190 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0190 | 100.0% | Reimplemented, compiler didn't optimize one tail SHC_3BB0A8C1_0x004D0280 | 0.0% | Pending From d9a9c075f7b0a41adf25fd2b1420a880a6236128 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Thu, 17 Sep 2026 23:05:17 +0200 Subject: [PATCH 060/242] reimplement: SHC_3BB0A8C1_0x004D10B0 100% --- .../AI/AICState/someChatMessageSelection.cpp | 230 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 73 insertions(+), 159 deletions(-) diff --git a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp index a92dbbe88..c9c1f2020 100644 --- a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp +++ b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/GameCore.func.hpp" #include "OpenSHC/Random/RNG.func.hpp" #include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" @@ -21,192 +22,105 @@ namespace AI { using OpenSHC::Game::GameMode; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - 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 0x004D10B0 - void AICState ::someChatMessageSelection() - + void AICState::someChatMessageSelection() { + int candidates[9]; + int candidateCount; + int total; + int i; + int playerID; - BOOLEnum BVar1; - - DWORD DVar2; - - int iVar3; - - int iVar4; - - int iVar5; - - int iVar6; - - int aiStack_24[9]; - - BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)(); - - if ((BVar1 != FALSE) - && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode == OpenSHC::Game::GM_SKIRMISH_SINGLE_PLAYER)) { + if ((MACRO_CALL_MEMBER(OpenSHC::Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)() != FALSE) + && (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SKIRMISH_SINGLE_PLAYER)) { if (this->aiTauntResponseTimeWindow == 0) { - return; } - DVar2 = timeGetTime(); - - if (DVar2 - this->aiTauntResponseTimeWindow < 2000) { - + if (timeGetTime() - this->aiTauntResponseTimeWindow <= 2000) { return; } - iVar6 = 0; - - iVar3 = 0; - - iVar4 = 3; - - do { - - if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 4) != 0) - && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 4) + candidateCount = 0; + // Players 1..8, manually unrolled by 4 in the original. + for (playerID = 1; playerID < 9; playerID += 4) { + if ((DAT_GameSynchronyState::instance.currentAIArray[playerID] != 0) + && (DAT_GameState::instance.mapAndTime.playerTeams[playerID] != DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { - - aiStack_24[iVar6] = iVar4 + -2; - - iVar6 = iVar6 + 1; + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + candidates[candidateCount] = playerID; + candidateCount++; } - - if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 8) != 0) - && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 8) + if ((DAT_GameSynchronyState::instance.currentAIArray[playerID + 1] != 0) + && (DAT_GameState::instance.mapAndTime.playerTeams[playerID + 1] != DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { - - aiStack_24[iVar6] = iVar4 + -1; - - iVar6 = iVar6 + 1; + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + candidates[candidateCount] = playerID + 1; + candidateCount++; } - - if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 0xc) != 0) - && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 0xc) + if ((DAT_GameSynchronyState::instance.currentAIArray[playerID + 2] != 0) + && (DAT_GameState::instance.mapAndTime.playerTeams[playerID + 2] != DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { - - aiStack_24[iVar6] = iVar4; - - iVar6 = iVar6 + 1; + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + candidates[candidateCount] = playerID + 2; + candidateCount++; } - - if ((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + iVar3 + 0x10) != 0) - && (*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + iVar3 + 0x10) + if ((DAT_GameSynchronyState::instance.currentAIArray[playerID + 3] != 0) + && (DAT_GameState::instance.mapAndTime.playerTeams[playerID + 3] != DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { - - aiStack_24[iVar6] = iVar4 + 1; - - iVar6 = iVar6 + 1; + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + candidates[candidateCount] = playerID + 3; + candidateCount++; } + } - iVar5 = iVar4 + 2; - - iVar3 = iVar3 + 0x10; - - iVar4 = iVar4 + 4; - - } while (iVar5 < 9); - - if (0 < iVar6) { - - iVar3 = 0; - - iVar4 = 0; - - if (0 < iVar6) { - - do { - - iVar3 = iVar3 - + DAT_SkirmishDefinedData::instance - .MaxBreachTribes[DAT_GameState::instance.playerDataArray[aiStack_24[iVar4]].aiType - + OpenSHC::AI::AIT_FREDERICK] - .tribeType; - - iVar4 = iVar4 + 1; - - } while (iVar4 < iVar6); - - if (iVar3 != 0) { - - iVar5 = (int)SEC_RNG::instance.currentNumber1; - - MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber1, SEC_RNG::ptr)(); - - iVar5 = iVar5 % iVar3; - - iVar4 = 0; - - do { - - iVar3 = aiStack_24[iVar4]; + if (candidateCount > 0) { + total = 0; + // NOTE: 'i = total' keeps the (redundant) loop entry check of the original. + for (i = total; i < candidateCount; i++) { + total += DAT_SkirmishDefinedData::instance + .MaxBreachTribes[DAT_GameState::instance.playerDataArray[candidates[i]].aiType + + OpenSHC::AI::AIT_FREDERICK] + .tribeType; + } - iVar5 = iVar5 + if (total != 0) { + int roll = (int)SEC_RNG::instance.currentNumber1; + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber1, SEC_RNG::ptr)(); + roll = roll % total; + + for (i = 0; i < candidateCount; i++) { + playerID = candidates[i]; + roll -= DAT_SkirmishDefinedData::instance + .MaxBreachTribes[DAT_GameState::instance.playerDataArray[playerID].aiType + + OpenSHC::AI::AIT_FREDERICK] + .tribeType; + if (roll < 0) { + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[1] = 1; + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[2] = 1; + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[3] = 1; + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[4] = 1; + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[5] = 1; + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[6] = 1; + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[7] = 1; + DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[8] = 1; + DAT_GameSynchronyState::instance.DAT_ChatTauntOrMessage = -2 - DAT_SkirmishDefinedData::instance - .MaxBreachTribes[DAT_GameState::instance.playerDataArray[iVar3].aiType + .MaxBreachTribes[DAT_GameState::instance.playerDataArray[playerID].aiType + OpenSHC::AI::AIT_FREDERICK] - .tribeType; - - if (iVar5 < 0) { - - DAT_GameSynchronyState::instance.DAT_ChatTauntOrMessage = -2 - - DAT_SkirmishDefinedData::instance - .MaxBreachTribes[DAT_GameState::instance.playerDataArray[iVar3].aiType - + OpenSHC::AI::AIT_FREDERICK] - .tribeCount; - - DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[1] = 1; - - DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[2] = 1; - - DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[3] = 1; - - DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[4] = 1; - - DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[5] = 1; - - DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[6] = 1; - - DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[7] = 1; - - DAT_GameSynchronyState::instance.DAT_ChatMessageReceiverArray[8] = 1; - - DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = iVar3; - - MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, - DAT_GameSynchronyState::ptr)(OpenSHC::Commands::GCT_TAUNT_OR_CHAT); - - this->aiTauntResponseTimeWindow = 0; - - return; - } - - iVar4 = iVar4 + 1; - - } while (iVar4 < iVar6); + .tribeCount; + DAT_GameSynchronyState::instance.DAT_GameCommandParam0 = playerID; + MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::queueCommand, + DAT_GameSynchronyState::ptr)(OpenSHC::Commands::GCT_TAUNT_OR_CHAT); + break; + } } } } } this->aiTauntResponseTimeWindow = 0; - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e28bffeb2..f5a326cd5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35457,7 +35457,7 @@ SHC_3BB0A8C1_0x004D1050 | 0.0% | Pending SHC_3BB0A8C1_0x004D1090 | 0.0% | Pending -SHC_3BB0A8C1_0x004D10B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D10B0 | 100.0% | Reimplemented, one reordered push edi SHC_3BB0A8C1_0x004D11C0 | 0.0% | Pending From bf62798ac093afbefbbc328ea2a3c76f6b14be33 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Thu, 17 Sep 2026 23:17:03 +0200 Subject: [PATCH 061/242] progress --- .../AI/AICState/Constructor_AICState.cpp | 2 +- .../AI/AICState/addRallyPointForTribe.cpp | 3 +- src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp | 3 +- .../AICState/addUnitToSmallestPatrolTribe.cpp | 3 +- .../AI/AICState/aiAssignMoatDiggers.cpp | 3 +- .../AICState/aiAssignUnitToDefensiveTribe.cpp | 3 +- src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp | 3 +- .../aiChoiceAttForceRallyPercentage.cpp | 3 +- .../AICState/aiCommandSiegeEngineTribes.cpp | 3 +- .../aiCommandTribe12AggressiveApproach.cpp | 12 ++- .../AI/AICState/aiCreateSiegeUnits.cpp | 3 +- .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 3 +- .../AI/AICState/aiGiveRaidInstructions.cpp | 3 +- .../AI/AICState/aiOfTypeInCurrentGame.cpp | 3 +- .../AICState/aiReassignTunnelersToTribe.cpp | 3 +- .../AI/AICState/aiRecruitSortieMeleeUnits.cpp | 3 +- .../AICState/aiRecruitSortieRangedUnits.cpp | 3 +- src/OpenSHC/AI/AICState/aiRecruitUnits.cpp | 43 ++++++---- .../aiRegisterTribeAndAssignTarget.cpp | 3 +- .../AI/AICState/aiRequiresExtraOxtethers.cpp | 3 +- src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 3 +- ...iShouldAttackOrWaitForTeamCoordination.cpp | 17 ++-- .../AI/AICState/aiUpdateTaxesAndRations.cpp | 3 +- .../AI/AICState/assignUnitToATribe.cpp | 3 +- src/OpenSHC/AI/AICState/buyRequiredGoods.cpp | 3 +- ...mBuildingIDFromPlayersArrayOfBuildings.cpp | 3 +- .../AI/AICState/clearOutdatedAITribes.cpp | 3 +- .../clearPlayerDataInformationChunk.cpp | 3 +- .../clearRallyFlagOnAllAIAttackTribes.cpp | 3 +- .../AI/AICState/commandFourTribesToMove.cpp | 3 +- .../AICState/computeAttackPossibilities.cpp | 3 +- .../AICState/computeEnemyKeepApproachTile.cpp | 3 +- .../AI/AICState/computeNervousness.cpp | 2 +- .../AI/AICState/countSiegeEngineUnits.cpp | 3 +- .../AICState/decideOnTribeAttackLocation.cpp | 3 +- ...determineAIPlayerAttackRequestResponse.cpp | 3 +- .../AI/AICState/determineAIPlayerHelp.cpp | 3 +- src/OpenSHC/AI/AICState/digNearestMoat.cpp | 3 +- .../AI/AICState/disbandAIPlayerSiegeUnits.cpp | 3 +- ...ndAttackTribePositionAndPathToDefenses.cpp | 3 +- .../generateSiegeCreationInformation.cpp | 3 +- .../AI/AICState/getSmallestPatrolTribe.cpp | 3 +- .../getTargetableBuildingForPlayerID.cpp | 3 +- .../getUnitTypeForUnitBehaviourType.cpp | 3 +- .../giveMoveCommandToAttackTribes.cpp | 3 +- .../AICState/giveMoveCommandToSortieUnits.cpp | 18 ++--- .../AI/AICState/giveSomeRaidCommand.cpp | 3 +- .../AICState/ifHasTribe0SendUnitsToKeep.cpp | 2 +- .../AI/AICState/instructTribe166ToMove.cpp | 7 +- .../AI/AICState/makeOutpostTribesAttack.cpp | 2 +- ...eUnitsGoDefensiveAndBackToSomeLocation.cpp | 3 +- .../AICState/moveAttackTribesToLocations.cpp | 3 +- .../moveAttackingUnitsToNextRallyPoint.cpp | 3 +- ...rcentageNonMovingTribesGTEAICSpecified.cpp | 3 +- ...BuyWhenLowOnResourceAndSnoozeBuildings.cpp | 3 +- .../processAttForceRallyPercentage.cpp | 3 +- .../randomlySelectAttackUnitTypeToRecruit.cpp | 3 +- .../recomputeAIPathCostToAttackedKeep.cpp | 3 +- .../AI/AICState/recomputeAIZonerLayer.cpp | 3 +- .../AI/AICState/recomputeAttackAIZone.cpp | 3 +- .../AI/AICState/recreateEngineersTribe.cpp | 2 +- .../recruitHarrassingSiegeEngines.cpp | 3 +- ...oveOrganismsAndSetMoveDestinationPairs.cpp | 3 +- .../AI/AICState/renderDebugDataAiInfo.cpp | 3 +- src/OpenSHC/AI/AICState/requestGoods.cpp | 3 +- .../AI/AICState/selectAttackTarget.cpp | 21 +++-- ...selectBuildingFromAListOfBuildingTypes.cpp | 2 +- ...andomBuildingIDFromListOfBuildingTypes.cpp | 3 +- src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 3 +- ...oAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp | 3 +- ...sendOilMenForOilPickupOrToAIVLocations.cpp | 3 +- ...gedUnitTribesToAIVSlotsOrKeepIfNervous.cpp | 3 +- .../AICState/sendTribeAtOffset1ToCampfire.cpp | 2 +- .../AICState/sendTribeToAIVLocationSlot.cpp | 3 +- .../sendUnitsToAttackBreachedCastle.cpp | 3 +- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 3 +- ...sendWallPatrolUnitTribesToAIVLocations.cpp | 3 +- .../AI/AICState/setAICParameters_06.cpp | 3 +- .../AI/AICState/setAICParameters_07.cpp | 3 +- .../AI/AICState/setAICParameters_08.cpp | 3 +- .../AI/AICState/setAICParameters_09.cpp | 3 +- .../AI/AICState/setAICParameters_10.cpp | 3 +- .../AI/AICState/setAICParameters_11.cpp | 3 +- .../AI/AICState/setAICParameters_12.cpp | 3 +- .../AI/AICState/setAICParameters_13.cpp | 3 +- .../AI/AICState/setAICParameters_14.cpp | 3 +- .../AI/AICState/setAICParameters_15.cpp | 3 +- .../AI/AICState/setAICParameters_16.cpp | 3 +- src/OpenSHC/AI/AICState/setInitialAIC.cpp | 2 +- .../AICState/setNextMoveLocationForUnits.cpp | 3 +- ...TargetForTribeBasedOnTargetChoiceLogic.cpp | 11 +-- .../AICState/setupWorkshopProductionType.cpp | 39 ++++++--- .../AI/AICState/shareGoldAmongTeamMembers.cpp | 3 +- .../AI/AICState/smallestTribeOfUnitType.cpp | 80 +++++++++---------- src/OpenSHC/AI/AICState/updateAIBehaviour.cpp | 3 +- .../AI/AICState/updateAIPlayerState.cpp | 42 +++++----- .../AI/AICState/updateAIStrengthState.cpp | 3 +- 97 files changed, 320 insertions(+), 223 deletions(-) diff --git a/src/OpenSHC/AI/AICState/Constructor_AICState.cpp b/src/OpenSHC/AI/AICState/Constructor_AICState.cpp index 104d8e012..2eedf70e1 100644 --- a/src/OpenSHC/AI/AICState/Constructor_AICState.cpp +++ b/src/OpenSHC/AI/AICState/Constructor_AICState.cpp @@ -1,4 +1,4 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" namespace OpenSHC { namespace AI { diff --git a/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp b/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp index 1ae3180da..db4cc64bc 100644 --- a/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp +++ b/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" #include "OpenSHC/Map/Units/Unit.hpp" diff --git a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp index 216be457c..77bb32f81 100644 --- a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AITypeA.hpp" diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp index 2939e1589..a4ec79c91 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" diff --git a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp index 0cc811666..d0bfecd84 100644 --- a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp +++ b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" diff --git a/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp index cd5bb7b90..cccc97fe4 100644 --- a/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AITypeA.hpp" diff --git a/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp b/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp index 0181f8255..907bb3a06 100644 --- a/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp +++ b/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/Player/PlayerData.hpp" #include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp index de707eebc..1b408cc26 100644 --- a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" diff --git a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp index cee33b455..ff2b625bf 100644 --- a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp index 8dd97308d..a3e1f3237 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" @@ -60,16 +61,13 @@ namespace AI { DAT_PathFindingState::ptr)(attackedPlayerID, 200) != FALSE) || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 150) + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 150) != FALSE) || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 100) + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 100) != FALSE) || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 50) + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 50) != FALSE)) { MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index 886073a29..543f48f42 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" #include "OpenSHC/Map/TileMapState.func.hpp" diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp index 90ab12ecd..ac950d54f 100644 --- a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp index eaf785544..5ee5c34cb 100644 --- a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Global.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" diff --git a/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp b/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp index 0de10b080..dcb0264d5 100644 --- a/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp +++ b/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Game/Player/PlayerData.hpp" #include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp index 4b40f07e0..cc833862a 100644 --- a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" diff --git a/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp index 3b011e85d..29d463777 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AIType.hpp" diff --git a/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp index b9e473e21..55f5036c4 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AIType.hpp" diff --git a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp index 22307f6a7..057d9f7c5 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" #include "OpenSHC/Map/TileMapState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" @@ -84,8 +85,10 @@ namespace AI { if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { int _defTotal = *(int*)((int)this + iVar6 * 0x2a4 + 0x170); - if (bVar3) _defTotal = (_defTotal * 4) / 3; - if (0 < _nervousActionTracker) _defTotal = _defTotal * 4; + if (bVar3) + _defTotal = (_defTotal * 4) / 3; + if (0 < _nervousActionTracker) + _defTotal = _defTotal * 4; if (_defTotal <= DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk) return; } else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { @@ -101,7 +104,8 @@ namespace AI { if (((*(int*)((int)this + iVar6 + 0x15c) != 0) && (iVar5 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, - DAT_TileMapState::ptr)(playerID), iVar5 != 0)) + DAT_TileMapState::ptr)(playerID), + iVar5 != 0)) && ((_tribeID_defDiggingUnitMax = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10], _tribeID_defDiggingUnitMax == 0 || ((DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10] @@ -125,27 +129,32 @@ namespace AI { } _unitType = *(UnitType*)((int)this + iVar6 + 0x160); } else { - AIRecruitUnitChoiceInt _unitTypeChoice = - DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; + AIRecruitUnitChoiceInt _unitTypeChoice + = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; if (_unitTypeChoice == OpenSHC::AI::AIRUC_DEFENSIVE) { if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex) DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; if (*(int*)((int)this + (DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex + iVar4) - * 4 + 0x184) == 0) + * 4 + + 0x184) + == 0) DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; - int _unitChoiceIndex = - DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex; + int _unitChoiceIndex + = DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex; _unitType = *(UnitType*)((int)this + (iVar4 + _unitChoiceIndex) * 4 + 0x184); - DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = - _unitChoiceIndex + 1; + DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex + = _unitChoiceIndex + 1; } else if (_unitTypeChoice == OpenSHC::AI::AIRUC_RAIDING) { if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex) DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; if (*(int*)((int)this - + (DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex + iVar4) - * 4 + 0x1ac) == 0) + + (DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex + + iVar4) + * 4 + + 0x1ac) + == 0) DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; iVar5 = DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex; _unitType = *(UnitType*)((int)this + (iVar4 + iVar5) * 4 + 0x1ac); @@ -153,9 +162,8 @@ namespace AI { } else if (_unitTypeChoice == OpenSHC::AI::AIRUC_ATTACKING) { _pAICState = (AICState*)MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::randomlySelectAttackUnitTypeToRecruit, this)(_playerID2); - _unitType = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::getUnitTypeForUnitBehaviourType, this)( - _playerID2, (AIUnitBehaviourType)((int)(_pAICState))); + _unitType = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getUnitTypeForUnitBehaviourType, + this)(_playerID2, (AIUnitBehaviourType)((int)(_pAICState))); } } @@ -218,7 +226,8 @@ namespace AI { < *(int*)((int)this + iVar6 + 0x180)) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignUnitToATribe, this)(_unitID); else - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToSmallestPatrolTribe, this)(_unitID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToSmallestPatrolTribe, this)( + _unitID); } else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignUnitToDefensiveTribe, this)(_unitID); } else if (AVar2 == OpenSHC::AI::AIRUC_ATTACKING) { diff --git a/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp b/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp index 74dfe4fde..f052d2bd8 100644 --- a/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp +++ b/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" diff --git a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp index 8ccc1c4da..abcbb1837 100644 --- a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp +++ b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp index a80d00659..9b494261b 100644 --- a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp index 1f3a4f198..87fdcd61e 100644 --- a/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" #include "OpenSHC/AI/AIType.hpp" @@ -42,7 +43,8 @@ namespace AI { } int _attForceBase = *(int*)((int)this + (_aiType - 1) * 0x2a4 + 0x1f4); - int _currentWaveStrength = DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; + int _currentWaveStrength + = DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; int _totalAttack = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops; @@ -61,8 +63,8 @@ namespace AI { do { if (_iPlayer != playerID) { - int _isAlive = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_iPlayer); + int _isAlive = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_iPlayer); if (_isAlive != 0) { BOOLEnum _isAI = MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, DAT_GameSynchronyState::ptr)(_iPlayer); @@ -76,8 +78,7 @@ namespace AI { >= *(int*)((int)this + (_pPlayerData->aiType - 1) * 0x2a4 + 0x1f4) + _pPlayerData->currentWaveRandomAttackingStrength) { _readyTeamMembers = _readyTeamMembers + 1; - } - else { + } else { _unreadyTeamMembers = _unreadyTeamMembers + 1; } } @@ -94,8 +95,8 @@ namespace AI { if (_unreadyTeamMembers == 0) { return TRUE; } - DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience = - DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience + 1; + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience + = DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience + 1; if (DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience <= 0x30 || (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CAMPAIGN_MISSION)) { return FALSE; diff --git a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp index 7bd2e0f18..122c929c7 100644 --- a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp +++ b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" diff --git a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp index f3cfc8926..659a8fb29 100644 --- a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp +++ b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Global.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AITypeA.hpp" diff --git a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp index 900f0e7ad..77dd56f18 100644 --- a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp +++ b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" diff --git a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp index 73e758d0c..0a150f5b5 100644 --- a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp +++ b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Buildings/BuildingTypeInt.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" diff --git a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp index 913be6005..ba783a7c9 100644 --- a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp +++ b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" diff --git a/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp index 5d3637d4c..468798d75 100644 --- a/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp +++ b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/OS.func.hpp" #include "OpenSHC/Synchrony/GameSynchronyState.hpp" diff --git a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp index e01808143..8ef25ba8e 100644 --- a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" diff --git a/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp b/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp index d701a1a34..ad8c9a3ee 100644 --- a/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp +++ b/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp index bb31d983e..f67a8a032 100644 --- a/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp +++ b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/IO/LowLevelMemory.func.hpp" #include "OpenSHC/Map/Units/TroopValueState.func.hpp" diff --git a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp index 7f28e4267..8b9e81fde 100644 --- a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp +++ b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/IO/LowLevelMemory.func.hpp" #include "OpenSHC/Map/LandscapeState.func.hpp" #include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" diff --git a/src/OpenSHC/AI/AICState/computeNervousness.cpp b/src/OpenSHC/AI/AICState/computeNervousness.cpp index ca79afa7c..6f1c880e4 100644 --- a/src/OpenSHC/AI/AICState/computeNervousness.cpp +++ b/src/OpenSHC/AI/AICState/computeNervousness.cpp @@ -1,4 +1,4 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" diff --git a/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp b/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp index e58e36158..562c048fb 100644 --- a/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp +++ b/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/Unit.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" diff --git a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp index 5d078d371..5191a434e 100644 --- a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp +++ b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/Global.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" diff --git a/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp b/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp index ecdd9457b..d638516e3 100644 --- a/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp +++ b/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Global.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" diff --git a/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp b/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp index 41f1ba2ec..0013a64d9 100644 --- a/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp +++ b/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Global.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" diff --git a/src/OpenSHC/AI/AICState/digNearestMoat.cpp b/src/OpenSHC/AI/AICState/digNearestMoat.cpp index 9187b70c5..24e5222f4 100644 --- a/src/OpenSHC/AI/AICState/digNearestMoat.cpp +++ b/src/OpenSHC/AI/AICState/digNearestMoat.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/TileMapState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp b/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp index 531b03abe..c6619d6dd 100644 --- a/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/States/UnitState.hpp" #include "OpenSHC/Map/Units/Unit.hpp" diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp index e896ea9ea..aae1a994e 100644 --- a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" diff --git a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp index 1fddcaf46..de213a84a 100644 --- a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp +++ b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Game/GameMode.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" diff --git a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp index daeffb4e5..8412ceff5 100644 --- a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp +++ b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" diff --git a/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp index cd9b3b5e1..b4171cdca 100644 --- a/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp +++ b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/Player/PlayerData.hpp" #include "OpenSHC/Map/Buildings/BuildingTypeInt.hpp" diff --git a/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp b/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp index fcf4860b8..2314024f7 100644 --- a/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp +++ b/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/AI/AIUnitBehaviourType.hpp" diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp index a224fd2ec..198397d4e 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp index a46324383..06017cd79 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" @@ -56,18 +57,17 @@ namespace AI { && (iVar1 = MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)(playerID, - (dword)((int)((int)(short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_UnitsState::instance - .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID].tile])), + (dword)((int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID] + .tile])), (dword)((int)((int)(short)DAT_TileMapState::instance .PathConnectionLayer[DAT_UnitsState::instance.units[_unitID].tile])), 0), iVar1 != 0)) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, - DAT_TribesState::ptr)(_tribeID); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(_tribeID, - (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)(_tribeID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + _tribeID, (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; diff --git a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp index eb6658bc8..7cd54fd27 100644 --- a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp +++ b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp index b118a2cce..db603d327 100644 --- a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp +++ b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp @@ -1,4 +1,4 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" diff --git a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp index 620439b22..af70756dd 100644 --- a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp +++ b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" @@ -60,8 +61,8 @@ namespace AI { && (0 < DAT_GameState::instance.playerDataArray[playerID].someYPosition)) { MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)(_tribeID); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(_tribeID, + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someXPosition)), (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someYPosition)), 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); diff --git a/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp index 17c068b42..3b53ff92a 100644 --- a/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp +++ b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp @@ -1,4 +1,4 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" diff --git a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp index 540b6cdd5..fc5f66990 100644 --- a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp +++ b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp index 6de76caf0..e0e022eb8 100644 --- a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp b/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp index 18634bdf2..1f483f35a 100644 --- a/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" diff --git a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp index dba68ea44..990c9b55e 100644 --- a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp +++ b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp index dd0c5b813..af9196afb 100644 --- a/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp +++ b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" #include "OpenSHC/AI/AIType.hpp" diff --git a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp index b53a16f12..54eb917c0 100644 --- a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp index 0fc1d1750..e875a483a 100644 --- a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp +++ b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Random/RNG.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" diff --git a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp index 3964e3919..96ed632f2 100644 --- a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/IO/LowLevelMemory.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" diff --git a/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp index 199d93eca..f7f48b02b 100644 --- a/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/IO/LowLevelMemory.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" diff --git a/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp index 3396df9e5..427a791cc 100644 --- a/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/IO/LowLevelMemory.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" #include "OpenSHC/Map/AttackInfoSubElement.hpp" diff --git a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp index 78ed1689a..91625a23e 100644 --- a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp +++ b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp @@ -1,4 +1,4 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" diff --git a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp index f497eabdc..ec093746a 100644 --- a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp +++ b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIVState.func.hpp" #include "OpenSHC/Map/TileMapState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" diff --git a/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp b/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp index 34db026dd..39859650f 100644 --- a/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp +++ b/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/LandscapeState.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" #include "OpenSHC/AI/AIType.hpp" diff --git a/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp index 46687d253..73b22b94a 100644 --- a/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp +++ b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/OS.func.hpp" #include "OpenSHC/Text/TextManager.func.hpp" #include "OpenSHC/AI/AIC/AICSpecification.hpp" diff --git a/src/OpenSHC/AI/AICState/requestGoods.cpp b/src/OpenSHC/AI/AICState/requestGoods.cpp index 20c9e32df..551db559f 100644 --- a/src/OpenSHC/AI/AICState/requestGoods.cpp +++ b/src/OpenSHC/AI/AICState/requestGoods.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Game/Resources/ResourceType.hpp" diff --git a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp index be79bfac5..028cbb77a 100644 --- a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp +++ b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AIC/AITargetChoice.hpp" @@ -38,8 +39,9 @@ namespace AI { int _reqState = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; if (((_reqState == 2) || (_reqState == 1)) - && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) == 0) { + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) + == 0) { DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; } @@ -49,8 +51,9 @@ namespace AI { return; } if (_reqState2 == 1) { - if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk) != 0) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk) + != 0) { DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk; return; @@ -64,8 +67,9 @@ namespace AI { do { if ((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) - && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_iPlayer) != 0) { + && MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_iPlayer) + != 0) { MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, @@ -122,7 +126,8 @@ namespace AI { if (((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer2] != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_iPlayer2) != 0) + DAT_UnitsState::ptr)(_iPlayer2) + != 0) && (MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, diff --git a/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp index 75b65a9ec..7c7b2af63 100644 --- a/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp +++ b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp @@ -1,4 +1,4 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" diff --git a/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp b/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp index 072e4b84d..4e739aafc 100644 --- a/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp +++ b/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Random/RNG.func.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp index 643d56427..0c9bf7112 100644 --- a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/AI/Trading/AIResourceTradeCategory.hpp" diff --git a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp index 7b01dc9c3..16b723b64 100644 --- a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp +++ b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/AI/AIVUnitType.hpp" #include "OpenSHC/AI/AIVUnitTypeInt.hpp" diff --git a/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp index afc77615c..7cf4247be 100644 --- a/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp +++ b/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AIVUnitType.hpp" diff --git a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp index 5e202cb21..79902f734 100644 --- a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp +++ b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIVUnitType.hpp" #include "OpenSHC/AI/AIVUnitTypeInt.hpp" #include "OpenSHC/AI/Tribes/AIVUnitTypeMaxLocationPair.hpp" diff --git a/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp index f595abbde..d7d47795b 100644 --- a/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp @@ -1,4 +1,4 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" diff --git a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp index 2d8aad2b4..99dea9737 100644 --- a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIVUnitType.hpp" #include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp index 54406b440..89d81f17b 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index 00653f14a..9ba845356 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" diff --git a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp index 6683a5696..35b83c413 100644 --- a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp +++ b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" diff --git a/src/OpenSHC/AI/AICState/setAICParameters_06.cpp b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp index b80d16350..281b9ba61 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_06.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp index 589ad5bd9..7f7a8b4fa 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_08.cpp b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp index 038ccf902..db18a5d39 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_08.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_09.cpp b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp index 1000c8508..1bc8d92f8 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_09.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp index 8b1e50bce..8a11823fe 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { namespace AI { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_11.cpp b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp index 2296787e0..3eda72d0b 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_11.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp index d2c250af1..f0de63e84 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_13.cpp b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp index 1bfe3d4ef..1be44ae3b 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_13.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp index 91bb5efe5..297eb3611 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_15.cpp b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp index f05d8235b..9574a6c87 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_15.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_16.cpp b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp index d7e7a4390..f54f13b99 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_16.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setInitialAIC.cpp b/src/OpenSHC/AI/AICState/setInitialAIC.cpp index e8bcb8cdb..cb991a970 100644 --- a/src/OpenSHC/AI/AICState/setInitialAIC.cpp +++ b/src/OpenSHC/AI/AICState/setInitialAIC.cpp @@ -1,4 +1,4 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" namespace OpenSHC { namespace AI { diff --git a/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp b/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp index 072dc6674..80b02a58c 100644 --- a/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp +++ b/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/LandscapeState.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" #include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" diff --git a/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp index 3c35fb36f..da5f9a721 100644 --- a/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp +++ b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AIC/AITargetChoice.hpp" @@ -44,7 +45,8 @@ namespace AI { if ((DAT_GameState::instance.mapAndTime.playerTeams[_player] != DAT_GameState::instance.mapAndTime.playerTeams[owner])) { - int _lord = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_player); + int _lord = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_player); if (_lord != 0) { @@ -86,8 +88,7 @@ namespace AI { } else if (_targetChoice == OpenSHC::AI::AIC::AITC_BALANCED) { - int _points = _ptrPlayerData->currentPopulation * 5 - + _ptrPlayerData->totalTroopValue + int _points = _ptrPlayerData->currentPopulation * 5 + _ptrPlayerData->totalTroopValue + _ptrPlayerData->currentResources[0xf] / 100 + DAT_DirectionAlgorithmState::instance.distanceHigh * 2; if (_points <= _minPoints) { @@ -116,7 +117,7 @@ namespace AI { != DAT_GameState::instance.mapAndTime.playerTeams[owner])) { int _lordBackup = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_playerID_backup); + DAT_UnitsState::ptr)(_playerID_backup); if (_lordBackup != 0) { diff --git a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp index 2ce935755..a9cdc875b 100644 --- a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp +++ b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" @@ -38,15 +39,19 @@ namespace AI { DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, OpenSHC::Map::Buildings::BT_BLACKSMITH); DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)_aiTypeMin1; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = (ResourceTypeShort)_aiTypeMin1; return; } if (_aiTypeMin1 == 0x16) { - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_SWORD; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_SWORD; + DAT_BuildingsState::instance.buildings[buildingID].producedItemType + = OpenSHC::Game::Resources::RT_SWORD; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = OpenSHC::Game::Resources::RT_SWORD; } else { DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_MACE; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_MACE; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = OpenSHC::Game::Resources::RT_MACE; } return; } @@ -58,15 +63,19 @@ namespace AI { DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, OpenSHC::Map::Buildings::BT_POLETURNER); DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)_aiTypeMin1; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = (ResourceTypeShort)_aiTypeMin1; return; } if (_aiTypeMin1 == 0x13) { - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_SPEAR; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_SPEAR; + DAT_BuildingsState::instance.buildings[buildingID].producedItemType + = OpenSHC::Game::Resources::RT_SPEAR; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = OpenSHC::Game::Resources::RT_SPEAR; } else { DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_PIKE; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_PIKE; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = OpenSHC::Game::Resources::RT_PIKE; } return; } @@ -78,15 +87,19 @@ namespace AI { DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, OpenSHC::Map::Buildings::BT_FLETCHER); DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)_aiTypeMin1; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = (ResourceTypeShort)_aiTypeMin1; return; } if (_aiTypeMin1 == 0x11) { DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_BOW; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_BOW; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = OpenSHC::Game::Resources::RT_BOW; } else { - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_CROSSBOW; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = OpenSHC::Game::Resources::RT_CROSSBOW; + DAT_BuildingsState::instance.buildings[buildingID].producedItemType + = OpenSHC::Game::Resources::RT_CROSSBOW; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext + = OpenSHC::Game::Resources::RT_CROSSBOW; } } diff --git a/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp b/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp index 80ba930bb..af2fe4131 100644 --- a/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp +++ b/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/OS.func.hpp" #include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" #include "OpenSHC/Text/TextManager.func.hpp" diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp index 02619dda4..8d9de46e3 100644 --- a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -9,55 +9,51 @@ namespace OpenSHC { namespace AI { - // FUNCTION: STRONGHOLDCRUSADER 0x004CC9B0 - int AICState::smallestTribeOfUnitType(int playerID, UnitType unitType) + // FUNCTION: STRONGHOLDCRUSADER 0x004CC990 + int AICState::smallestTribeOfUnitType(int playerID, AIVUnitType unitType) { - int iVar7 = 0; - int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType == AITA_NULL) { + int i = 0; + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { return 0; } - int iVar3 = (int)this->aics[_aiType - 1].defWallPatrolGroups; - int iVar6 = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[(int)unitType]; - int _tribeID = 0; - int local_c = 0; - short sVar4 = 1000; - if ((iVar3 < iVar6) && (((unitType == 0x8 || (unitType == 0xa)) || (unitType == 0x11)))) { - iVar6 = iVar3; + + int count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[unitType]; + int smallestTribeID = 0; + int smallestIndex = 0; + int smallestSize = 1000; + if (count > (int)this->aics[DAT_GameState::instance.playerDataArray[playerID].aiType - 1].defWallPatrolGroups + && (unitType == 8 || unitType == 10 || unitType == 17)) { + count = (int)this->aics[DAT_GameState::instance.playerDataArray[playerID].aiType - 1].defWallPatrolGroups; } - iVar3 = DAT_SkirmishDefinedData::instance.AITribeIDOffsetForUnitType[(int)unitType]; - if (0 < iVar6) { - short* _aiTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar3; - do { - int iVar5 = (int)*_aiTribeID; - if ((iVar5 == 0) - || (DAT_TribesState::instance.tribes[iVar5].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7])) { - _tribeID = MACRO_CALL_MEMBER( - Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[iVar3 + iVar7] = (short)_tribeID; - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] - = DAT_TribesState::instance.tribes[_tribeID].uid; - return _tribeID; - } - short sVar1 = DAT_TribesState::instance.tribes[iVar5].size; - if (sVar1 < sVar4) { - _tribeID = iVar5; - local_c = iVar7; - sVar4 = sVar1; + + int offset = DAT_SkirmishDefinedData::instance.AITribeIDOffsetForAIVUnitType[unitType]; + for (;; i++) { + if (i >= count) { + if (smallestTribeID == 0) { + return 0; } - _aiTribeID = _aiTribeID + 1; - iVar7 = iVar7 + 1; - } while (iVar7 < iVar6); - iVar7 = local_c; - if (_tribeID != 0) { - DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[iVar3 + iVar7] = (short)_tribeID; - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar3 + iVar7] - = DAT_TribesState::instance.tribes[_tribeID].uid; - return _tribeID; + break; + } + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[offset + i]; + if (tribeID == 0 + || DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[offset + i]) { + smallestTribeID = MACRO_CALL_MEMBER( + Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + smallestIndex = i; + break; + } + if (DAT_TribesState::instance.tribes[tribeID].size < smallestSize) { + smallestSize = DAT_TribesState::instance.tribes[tribeID].size; + smallestTribeID = tribeID; + smallestIndex = i; } } - return 0; + + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[offset + smallestIndex] = (short)smallestTribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[offset + smallestIndex] + = DAT_TribesState::instance.tribes[smallestTribeID].uid; + return smallestTribeID; } } } diff --git a/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp index c89ef1451..eef4ddd57 100644 --- a/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp +++ b/src/OpenSHC/AI/AICState/updateAIBehaviour.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Map/TileMapState.func.hpp" #include "OpenSHC/AI/AIRecruitUnitChoice.hpp" #include "OpenSHC/AI/AIType.hpp" diff --git a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp index 0a242e001..5050ed89e 100644 --- a/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIPlayerState.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Audio/SFX/SFXState.func.hpp" #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" @@ -54,8 +55,8 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setCurrentAttackRaidParameter, this)(playerID); // fixme: struct layout. This looks like an int[10][8] attack tracker starting at // attackedByPlayerArrayUnk (0x2BDC) and ending where aivUnitLocationSlots begins (0x2D1C). - (&DAT_GameState::instance.playerDataArray[DAT_GameState::instance.playerDataArray[playerID] - .attackedPlayerID] + (&DAT_GameState::instance + .playerDataArray[DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID] .attackedByPlayerArrayUnk)[playerID * 8]++; } else if ((MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::hasNoTroopsOrAllAreDiggers, this)(playerID) && _aiPlayerState != 9) @@ -158,9 +159,8 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::Audio::SFX::SFXState_Func::playSFXAtLocationFullVolume, DAT_SFXState::ptr)( DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, 0x14); - if (!MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) { + if (!MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) { // castle is closed: attack the walls DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiCommandTribe12AggressiveApproach, this)(playerID); @@ -200,12 +200,10 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTribe0xbToAggressiveAndAttack, this)(playerID); } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendAITribe_0xf_toAttackPatrol, this)(playerID); - if (!MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID) - && !MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) + if (!MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID) + && !MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 6; return; @@ -222,13 +220,11 @@ namespace AI { DAT_GameState::ptr)(_attackedPlayerID); if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToAttackBreachedCastle, this)(playerID)) return; - if (MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) + if (MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) return; - if (MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, DAT_GameState::ptr)( - playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) + if (MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canUnitsNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID)) return; // the breach got closed again: back to attacking the walls DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 5; @@ -246,9 +242,8 @@ namespace AI { return; DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - MACRO_CALL_MEMBER( - OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); @@ -261,9 +256,8 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID].aiPlayerState = 9; DAT_GameState::instance.playerDataArray[playerID].attackTicker = 0; MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::disbandAIPlayerSiegeUnits, this)(playerID); - MACRO_CALL_MEMBER( - OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, DAT_BuildingsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::removeSiegeBuildings, + DAT_BuildingsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].currentAttackWave, playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addEngineersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiReassignTunnelersToTribe, this)(playerID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::findAttackTribePositionAndPathToDefenses, this)(playerID); diff --git a/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp index 1a034cf6e..249bea57d 100644 --- a/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp +++ b/src/OpenSHC/AI/AICState/updateAIStrengthState.cpp @@ -1,4 +1,5 @@ -#include "OpenSHC/AI/AICState.func.hpp" +#include "../AICState.func.hpp" + #include "OpenSHC/Random/RNG.func.hpp" #include "OpenSHC/AI/AINervousDestroyBuildingCategory.hpp" #include "OpenSHC/AI/AINervousDestroyBuildingCategoryInt.hpp" From a6fa273890e18028ecd20e72dc07319b161ac94a Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sat, 19 Sep 2026 14:20:38 +0200 Subject: [PATCH 062/242] reimplement: SHC_3BB0A8C1_0x004CC990 40.90% --- .../AI/AICState/smallestTribeOfUnitType.cpp | 35 ++++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp index 8d9de46e3..6c3238d9e 100644 --- a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -12,36 +12,35 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC990 int AICState::smallestTribeOfUnitType(int playerID, AIVUnitType unitType) { - int i = 0; if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { return 0; } + int maxGroups = this->aics[DAT_GameState::instance.playerDataArray[playerID].aiType - 1].defWallPatrolGroups; int count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[unitType]; + if (count > maxGroups && (unitType == 8 || unitType == 10 || unitType == 17)) { + count = maxGroups; + } + int smallestTribeID = 0; int smallestIndex = 0; int smallestSize = 1000; - if (count > (int)this->aics[DAT_GameState::instance.playerDataArray[playerID].aiType - 1].defWallPatrolGroups - && (unitType == 8 || unitType == 10 || unitType == 17)) { - count = (int)this->aics[DAT_GameState::instance.playerDataArray[playerID].aiType - 1].defWallPatrolGroups; - } - int offset = DAT_SkirmishDefinedData::instance.AITribeIDOffsetForAIVUnitType[unitType]; - for (;; i++) { - if (i >= count) { - if (smallestTribeID == 0) { - return 0; - } - break; - } + for (int i = 0; i < count; i++) { int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[offset + i]; if (tribeID == 0 || DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[offset + i]) { - smallestTribeID = MACRO_CALL_MEMBER( + // FIXME: The original binary jumps from here directly into the shared assignment code at the + // end of the function, skipping the "smallestTribeID == 0" check. A goto reproduces this and + // matches the assembly much better (~55% vs ~41%), but we avoid goto, so the assignment is + // duplicated here. + tribeID = MACRO_CALL_MEMBER( Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - smallestIndex = i; - break; + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[offset + i] = (short)tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[offset + i] + = DAT_TribesState::instance.tribes[tribeID].uid; + return tribeID; } if (DAT_TribesState::instance.tribes[tribeID].size < smallestSize) { smallestSize = DAT_TribesState::instance.tribes[tribeID].size; @@ -50,6 +49,10 @@ namespace AI { } } + if (smallestTribeID == 0) { + return 0; + } + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[offset + smallestIndex] = (short)smallestTribeID; DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[offset + smallestIndex] = DAT_TribesState::instance.tribes[smallestTribeID].uid; diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f5a326cd5..63269ea4d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34887,7 +34887,7 @@ SHC_3BB0A8C1_0x004CC8D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CC910 | 0.0% | Pending -SHC_3BB0A8C1_0x004CC990 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC990 | 40.90% | Reimplemented functionally, different register usage SHC_3BB0A8C1_0x004CCAF0 | 0.0% | Pending From c904f447a92daab71e7de8c18dfe8c71550385b2 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sat, 19 Sep 2026 14:50:22 +0200 Subject: [PATCH 063/242] reimplement: SHC_3BB0A8C1_0x004CB610 100% --- ...shouldWaitWithBuildingNegativeFearFactor.cpp | 17 +++++++++-------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp index db2fd86bb..768c6f8de 100644 --- a/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp +++ b/src/OpenSHC/AI/AICState/shouldWaitWithBuildingNegativeFearFactor.cpp @@ -7,10 +7,9 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB610 - BOOLEnum AICState::shouldWaitWithBuildingNegativeFearFactor(int param_1, Commands::MappersEnum param_2) + BOOLEnum AICState::shouldWaitWithBuildingNegativeFearFactor(int playerID, Commands::MappersEnum mapper) { - int* piVar1; - switch (param_2) { + switch (mapper) { case Commands::M_MAPPER_GALLOWS: case Commands::M_MAPPER_STOCKS: case Commands::M_MAPPER_CESS_PIT1: @@ -24,13 +23,15 @@ namespace AI { case Commands::M_MAPPER_RACK_FLOGGING: case Commands::M_MAPPER_CHOPPING_BLOCK: case Commands::M_MAPPER_DUNKING_STOOL: - if ((DAT_GameState::instance.playerDataArray[param_1].popularity < 5000) - || (piVar1 = &DAT_GameState::instance.playerDataArray[param_1].aivNegativeFearFactorDelay, - *piVar1 = *piVar1 + 1, - DAT_GameState::instance.playerDataArray[param_1].aivNegativeFearFactorDelay < 100)) { + if (DAT_GameState::instance.playerDataArray[playerID].popularity < 5000) { return TRUE; } - DAT_GameState::instance.playerDataArray[param_1].aivNegativeFearFactorDelay = 0; + DAT_GameState::instance.playerDataArray[playerID].aivNegativeFearFactorDelay++; + if (DAT_GameState::instance.playerDataArray[playerID].aivNegativeFearFactorDelay < 100) { + return TRUE; + } + DAT_GameState::instance.playerDataArray[playerID].aivNegativeFearFactorDelay = 0; + return FALSE; } return FALSE; } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 63269ea4d..ab79ea693 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34223,7 +34223,7 @@ SHC_3BB0A8C1_0x004CB540 | 0.0% | Pending SHC_3BB0A8C1_0x004CB5B0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CB610 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB610 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB66C | 0.0% | Pending From 11aaf6a42beaa343f6db6103d800f4f4e74b0225 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sat, 19 Sep 2026 15:01:21 +0200 Subject: [PATCH 064/242] reimplement: SHC_3BB0A8C1_0x004CB890 100% --- .../AICState/shouldDestroyWoodCutterUnk.cpp | 40 +++++++++++-------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp index 7b9edebb0..ef62ccba5 100644 --- a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp +++ b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp @@ -3,6 +3,7 @@ #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" #include "OpenSHC/Globals/DAT_AIVState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" @@ -14,33 +15,38 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB890 BOOLEnum AICState::shouldDestroyWoodCutterUnk(int playerID) { - int _hut; - if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { return FALSE; + } + int buildingID; if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0) { - _hut = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + buildingID = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT); } else { - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] <= 0x14) + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_WOOD] <= 20) { return FALSE; - if (DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 2) + } + if (DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 2) { return FALSE; - if (DAT_GameState::instance.playerDataArray[playerID].someCount10 < 25) + } + if (DAT_GameState::instance.playerDataArray[playerID].someCount10 < 25) { return FALSE; - _hut = DAT_GameState::instance.playerDataArray[playerID].someCount11; + } + buildingID = DAT_GameState::instance.playerDataArray[playerID].someCount11; } - if (_hut == 0) - return FALSE; - - MACRO_CALL_MEMBER(AIVState_Func::resetCountdownInHeatMap, DAT_AIVState::ptr)( - (int)(short)DAT_BuildingsState::instance.buildings[_hut].x, - (int)(short)DAT_BuildingsState::instance.buildings[_hut].y); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(_hut, playerID, 50); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hut); - return TRUE; + if (buildingID != 0) { + MACRO_CALL_MEMBER(AIVState_Func::resetCountdownInHeatMap, DAT_AIVState::ptr)( + (short)DAT_BuildingsState::instance.buildings[buildingID].x, + (short)DAT_BuildingsState::instance.buildings[buildingID].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(buildingID, playerID, 50); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( + buildingID); + return TRUE; + } + return FALSE; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index ab79ea693..bfa367d60 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34847,7 +34847,7 @@ SHC_3BB0A8C1_0x004CB804 | 0.0% | Pending SHC_3BB0A8C1_0x004CB810 | 0.0% | Pending -SHC_3BB0A8C1_0x004CB890 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB890 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB940 | 0.0% | Pending From 80fb2e478868f9649d384cd5c10ffbba1196ff0b Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sat, 19 Sep 2026 15:02:54 +0200 Subject: [PATCH 065/242] style improvement --- src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp index 6c80452e9..d44c311ef 100644 --- a/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp +++ b/src/OpenSHC/AI/AICState/shouldNotBuildKillingPits.cpp @@ -10,7 +10,7 @@ namespace AI { BOOLEnum AICState::shouldNotBuildKillingPits(int playerID, Commands::MappersEnum commandBuildingType) { if (commandBuildingType == Commands::M_MAPPER_KILLING_PIT) { - return (BOOLEnum)(DAT_AIVState::instance.mapExtraInfo.playerTotalKillingPits[playerID] >= 100); + return DAT_AIVState::instance.mapExtraInfo.playerTotalKillingPits[playerID] >= 100; } return FALSE; } From 88e8bfcd8e825e063ee9a431c8ff29f3b85ed533 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sat, 19 Sep 2026 15:35:02 +0200 Subject: [PATCH 066/242] reimplement: SHC_3BB0A8C1_0x004D05D0 100% --- .../AI/AICState/shareGoldAmongTeamMembers.cpp | 225 ++++-------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 50 insertions(+), 177 deletions(-) diff --git a/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp b/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp index af2fe4131..da204a269 100644 --- a/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp +++ b/src/OpenSHC/AI/AICState/shareGoldAmongTeamMembers.cpp @@ -1,10 +1,13 @@ +// disable deprecation warnings for strcpy +#pragma warning(disable : 4996) + #include "../AICState.func.hpp" #include "OpenSHC/OS.func.hpp" #include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" #include "OpenSHC/Text/TextManager.func.hpp" #include "OpenSHC/DE/SHCDE/eTextSections.hpp" -#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -13,191 +16,61 @@ namespace OpenSHC { namespace AI { - using OpenSHC::DE::SHCDE::eTextSections; - using OpenSHC::Game::Player::PlayerData; - - /* - 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 */ + // FIXME: The original function never sets a return value (eax is left over from the last computation), + // so it was most likely a void function. The header declares int, which forces the "return 0"s below + // and costs an extra "xor eax, eax" in the assembly. Change the return type to void in the header. // FUNCTION: STRONGHOLDCRUSADER 0x004D05D0 - int AICState ::shareGoldAmongTeamMembers(int playerID, int gold) - + void AICState::shareGoldAmongTeamMembers(int playerID, int gold) { - - int* piVar1; - - char cVar2; - - int _playerOffset; - - int _goldPerPlayer; - - char* pcVar3; - - char* pcVar4; - - PlayerData* _ptrPlayerData; - - int _totalPlayers; - - int _candidates[9]; - - int _targetPlayer; - - int _playerIndex; - - int _playerIndexTracker; - - int* _ptrCurrentGold; - - _totalPlayers = 0; - - _ptrPlayerData = &DAT_GameState::instance.playerDataArray[2]; - - _playerOffset = 0; - - _playerIndex = 3; - - do { - - if ((((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 4) != 0) - || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 4) - != -1)) - && (_playerIndex + -2 != playerID)) - && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 4) - == DAT_GameState::instance.mapAndTime.playerTeams[playerID] - && (DAT_GameState::instance.playerDataArray[1].lordKilledByPlayerID == 0)))) { - - /* - if lord of team member not dead, then: */ - - _candidates[_totalPlayers] = _playerIndex + -2; - - _totalPlayers = _totalPlayers + 1; - } - - if (((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 8) != 0) - || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 8) - != -1)) - && ((_playerIndex + -1 != playerID - && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 8) - == DAT_GameState::instance.mapAndTime.playerTeams[playerID] - && (_ptrPlayerData->lordKilledByPlayerID == 0)))))) { - - _candidates[_totalPlayers] = _playerIndex + -1; - - _totalPlayers = _totalPlayers + 1; - } - - if ((((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 0xc) != 0) - || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 0xc) - != -1)) - && (_playerIndex != playerID)) - && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 0xc) - == DAT_GameState::instance.mapAndTime.playerTeams[playerID] - && (DAT_GameState::instance.playerDataArray[3].lordKilledByPlayerID == 0)))) { - - _candidates[_totalPlayers] = _playerIndex; - - _totalPlayers = _totalPlayers + 1; + int candidateCount = 0; + int candidates[9]; + for (int i = 1; i < 9; i++) { + if ((DAT_GameSynchronyState::instance.currentAIArray[i] != 0 + || DAT_GameSynchronyState::instance.currentPlayerFullIDArray[i] != -1) + && i != playerID + && DAT_GameState::instance.mapAndTime.playerTeams[i] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID] + && DAT_GameState::instance.playerDataArray[i].lordKilledByPlayerID == 0) { + candidates[candidateCount] = i; + candidateCount++; } + } - if (((*(int*)((int)DAT_GameSynchronyState::instance.currentAIArray + _playerOffset + 0x10) != 0) - || (*(int*)((int)DAT_GameSynchronyState::instance.currentPlayerFullIDArray + _playerOffset + 0x10) - != -1)) - && ((_playerIndex + 1 != playerID - && ((*(int*)((int)DAT_GameState::instance.mapAndTime.playerTeams + _playerOffset + 0x10) - == DAT_GameState::instance.mapAndTime.playerTeams[playerID] - && (DAT_GameState::instance.playerDataArray[4].lordKilledByPlayerID == 0)))))) { + if (candidateCount == 0) { + return; + } - _candidates[_totalPlayers] = _playerIndex + 1; + int goldPerPlayer = gold / candidateCount; + if (goldPerPlayer == 0) { + return; + } - _totalPlayers = _totalPlayers + 1; + for (int j = 0; j < candidateCount; j++) { + int targetPlayer = candidates[j]; + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[targetPlayer] != -1) { + // "Goods received from ally" + strcpy(DAT_GameSynchronyState::instance.receivedChatMessage, + MACRO_CALL_MEMBER(Text::TextManager_Func::getTextStringInGroupAtOffset, DAT_TextManagerObject::ptr)( + DE::SHCDE::TEXT_ALLIES2, 1)); + MACRO_CALL_MEMBER(Synchrony::GameSynchronyState_Func::addChatMessageToDisplayList, + DAT_GameSynchronyState::ptr)(targetPlayer, 0); + + // "Gold" + MACRO_CALL(OS_Func::_sprintf)(DAT_GameSynchronyState::instance.receivedChatMessage, "%d %s - ", + goldPerPlayer, + MACRO_CALL_MEMBER(Text::TextManager_Func::getTextStringInGroupAtOffset, DAT_TextManagerObject::ptr)( + DE::SHCDE::TEXT_GOODS, Game::Resources::RT_GOLD)); + MACRO_CALL_MEMBER(Synchrony::GameSynchronyState_Func::addChatMessageToDisplayList, + DAT_GameSynchronyState::ptr)(targetPlayer, playerID); } - _playerIndexTracker = _playerIndex + 2; - - _playerOffset = _playerOffset + 16; - - _ptrPlayerData = _ptrPlayerData + 0x39f4; - - _playerIndex = _playerIndex + 4; - - } while (_playerIndexTracker < 9); - - /* - fixme: repurposed variable */ - - if (((_totalPlayers != 0) - && (_goldPerPlayer = gold / _totalPlayers, _playerOffset = _goldPerPlayer, _goldPerPlayer != 0)) - && (_playerIndex = 0, 0 < _totalPlayers)) { - - _ptrCurrentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources + 0xf; - - do { - - _targetPlayer = _candidates[_playerIndex]; - - if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_targetPlayer] != -1) { - - /* - "Goods received from ally" - added by script: "Goods received from ally" */ - - pcVar3 = MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::getTextStringInGroupAtOffset, - DAT_TextManagerObject::ptr)(OpenSHC::DE::SHCDE::TEXT_ALLIES2, 1); - - pcVar4 = DAT_GameSynchronyState::instance.receivedChatMessage; - - do { - - cVar2 = *pcVar3; - - *pcVar4 = cVar2; - - pcVar3 = pcVar3 + 1; - - pcVar4 = pcVar4 + 1; - - } while (cVar2 != '\0'); - - MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::addChatMessageToDisplayList, - DAT_GameSynchronyState::ptr)(_targetPlayer, 0); - - /* - "Goods types" - added by script: "Gold" */ - - pcVar3 = MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::getTextStringInGroupAtOffset, - DAT_TextManagerObject::ptr)(OpenSHC::DE::SHCDE::TEXT_GOODS, 0xf); - - MACRO_CALL(OpenSHC::OS_Func::_sprintf)( - DAT_GameSynchronyState::instance.receivedChatMessage, "%d %s - ", _goldPerPlayer, pcVar3); - - MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::addChatMessageToDisplayList, - DAT_GameSynchronyState::ptr)(_targetPlayer, playerID); - } - - *_ptrCurrentGold = *_ptrCurrentGold - _goldPerPlayer; - - piVar1 = DAT_GameState::instance.playerDataArray[_targetPlayer].currentResources + 0xf; - - *piVar1 = *piVar1 + _goldPerPlayer; - - _playerOffset = _targetPlayer * 0x39f4 + 0x115c304; - - _playerIndex = _playerIndex + 1; - - } while (_playerIndex < _totalPlayers); + DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] + -= goldPerPlayer; + DAT_GameState::instance.playerDataArray[targetPlayer].currentResources[Game::Resources::RT_GOLD] + += goldPerPlayer; } - - return _playerOffset; + return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index bfa367d60..ac906c90e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35405,7 +35405,7 @@ SHC_3BB0A8C1_0x004D0520 | 0.0% | Pending SHC_3BB0A8C1_0x004D0580 | 0.0% | Pending -SHC_3BB0A8C1_0x004D05D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D05D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0720 | 0.0% | Pending From a66c25768c2a33a3440cd61113e8e396dc9b9604 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sat, 19 Sep 2026 15:49:05 +0200 Subject: [PATCH 067/242] reimplement: SHC_3BB0A8C1_0x004CBE30 100% --- .../AICState/setupWorkshopProductionType.cpp | 116 +++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 47 insertions(+), 71 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp index a9cdc875b..37f46f67a 100644 --- a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp +++ b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp @@ -2,11 +2,9 @@ #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/Game/Resources/ResourceType.hpp" #include "OpenSHC/Game/Resources/ResourceTypeShort.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" -#include "OpenSHC/Map/Buildings/BuildingTypeShort.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -14,96 +12,74 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - using OpenSHC::Game::Resources::ResourceType; using OpenSHC::Game::Resources::ResourceTypeShort; - using OpenSHC::Map::Buildings::BuildingType; - using OpenSHC::Map::Buildings::BuildingTypeShort; // FUNCTION: STRONGHOLDCRUSADER 0x004CBE30 - void AICState ::setupWorkshopProductionType(int playerID, int buildingID) + void AICState::setupWorkshopProductionType(int playerID, int buildingID) { - AITypeInt AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AIT_NULL) { return; + } - BuildingTypeShort _buildingType = DAT_BuildingsState::instance.buildings[buildingID].buildingType; - int _aiTypeMin1 = AVar1 + ~OpenSHC::AI::AIT_NULL; - - if (_buildingType == OpenSHC::Map::Buildings::BT_BLACKSMITH) { - _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 200); - if (_aiTypeMin1 == -999) { - _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, - DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, - OpenSHC::Map::Buildings::BT_BLACKSMITH); - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = (ResourceTypeShort)_aiTypeMin1; + int aicIndex = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == Map::Buildings::BT_BLACKSMITH) { + int setting = this->aics[aicIndex].blacksmithSetting; + if (setting == -999) { + int itemType = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::chooseProductionItemType, + DAT_BuildingsState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].owner, Map::Buildings::BT_BLACKSMITH); + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)itemType; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)itemType; return; } - if (_aiTypeMin1 == 0x16) { - DAT_BuildingsState::instance.buildings[buildingID].producedItemType - = OpenSHC::Game::Resources::RT_SWORD; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = OpenSHC::Game::Resources::RT_SWORD; - } else { - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_MACE; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = OpenSHC::Game::Resources::RT_MACE; + if (setting == Game::Resources::RT_SWORD) { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = Game::Resources::RT_SWORD; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = Game::Resources::RT_SWORD; + return; } + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = Game::Resources::RT_MACE; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = Game::Resources::RT_MACE; return; } - if (_buildingType == OpenSHC::Map::Buildings::BT_POLETURNER) { - _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 0xd0); - if (_aiTypeMin1 == -999) { - _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, - DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, - OpenSHC::Map::Buildings::BT_POLETURNER); - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = (ResourceTypeShort)_aiTypeMin1; + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == Map::Buildings::BT_POLETURNER) { + int setting = this->aics[aicIndex].poleturnerSetting; + if (setting == -999) { + int itemType = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::chooseProductionItemType, + DAT_BuildingsState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].owner, Map::Buildings::BT_POLETURNER); + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)itemType; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)itemType; return; } - if (_aiTypeMin1 == 0x13) { - DAT_BuildingsState::instance.buildings[buildingID].producedItemType - = OpenSHC::Game::Resources::RT_SPEAR; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = OpenSHC::Game::Resources::RT_SPEAR; - } else { - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_PIKE; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = OpenSHC::Game::Resources::RT_PIKE; + if (setting == Game::Resources::RT_SPEAR) { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = Game::Resources::RT_SPEAR; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = Game::Resources::RT_SPEAR; + return; } + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = Game::Resources::RT_PIKE; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = Game::Resources::RT_PIKE; return; } - if (_buildingType == OpenSHC::Map::Buildings::BT_FLETCHER) { - _aiTypeMin1 = *(int*)((int)this + _aiTypeMin1 * 0x2a4 + 0xcc); - if (_aiTypeMin1 == -999) { - _aiTypeMin1 = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::chooseProductionItemType, - DAT_BuildingsState::ptr)((int)DAT_BuildingsState::instance.buildings[buildingID].owner, - OpenSHC::Map::Buildings::BT_FLETCHER); - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)_aiTypeMin1; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = (ResourceTypeShort)_aiTypeMin1; + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == Map::Buildings::BT_FLETCHER) { + int setting = this->aics[aicIndex].fletcherSetting; + if (setting == -999) { + int itemType = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::chooseProductionItemType, + DAT_BuildingsState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].owner, Map::Buildings::BT_FLETCHER); + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)itemType; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)itemType; return; } - if (_aiTypeMin1 == 0x11) { - DAT_BuildingsState::instance.buildings[buildingID].producedItemType = OpenSHC::Game::Resources::RT_BOW; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = OpenSHC::Game::Resources::RT_BOW; - } else { - DAT_BuildingsState::instance.buildings[buildingID].producedItemType - = OpenSHC::Game::Resources::RT_CROSSBOW; - DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext - = OpenSHC::Game::Resources::RT_CROSSBOW; + if (setting == Game::Resources::RT_BOW) { + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = Game::Resources::RT_BOW; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = Game::Resources::RT_BOW; + return; } + DAT_BuildingsState::instance.buildings[buildingID].producedItemType = Game::Resources::RT_CROSSBOW; + DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = Game::Resources::RT_CROSSBOW; } - - return; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index ac906c90e..b7b05cf0a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34855,7 +34855,7 @@ SHC_3BB0A8C1_0x004CB9F0 | 0.0% | Pending SHC_3BB0A8C1_0x004CBA50 | 0.0% | Pending -SHC_3BB0A8C1_0x004CBE30 | 0.0% | Pending +SHC_3BB0A8C1_0x004CBE30 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CBFA0 | 100.0% | Reimplemented From 4a6ad95361367cb49151a58eafbbc7beec13cde0 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sat, 19 Sep 2026 16:21:39 +0200 Subject: [PATCH 068/242] reimplement: SHC_3BB0A8C1_0x004CF400 62.22% --- .../setTribe0xCtoAggressiveAndAttack.cpp | 28 ++++++++++++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp index 2290c59f5..c60bbedf3 100644 --- a/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp +++ b/src/OpenSHC/AI/AICState/setTribe0xCtoAggressiveAndAttack.cpp @@ -13,17 +13,25 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF400 void AICState::setTribe0xCtoAggressiveAndAttack(int playerID) { - int tribeID; - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) - && (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xc], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xc]) - && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { - DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( - tribeID, Map::Units::STBT_0x3f2); - } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return; } + + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[12]; + if (tribeID == 0) { + return; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[12]) { + return; + } + if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) { + return; + } + + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f2); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b7b05cf0a..53e4764ea 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35357,7 +35357,7 @@ SHC_3BB0A8C1_0x004CF270 | 0.0% | Pending SHC_3BB0A8C1_0x004CF2E0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CF400 | 0.0% | Pending +SHC_3BB0A8C1_0x004CF400 | 62.22% | Reimplemented functionally, our compiler improves on original by avoiding recomputations SHC_3BB0A8C1_0x004CF470 | 0.0% | Pending From f1faa4128aac22077a82cf7120992e989d2cff16 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sat, 19 Sep 2026 16:36:07 +0200 Subject: [PATCH 069/242] reimplement: SHC_3BB0A8C1_0x004CF6E0 SHC_3BB0A8C1_0x004CF560 different register usage --- ...x11ToAggressiveAndAttackIfConditionMet.cpp | 34 ++++++++++++------- .../setTribe0xbToAggressiveAndAttack.cpp | 28 +++++++++------ status/addresses-SHC-3BB0A8C1.txt | 4 +-- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp b/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp index b44d4a6c2..bedc117df 100644 --- a/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp +++ b/src/OpenSHC/AI/AICState/setTribe0x11ToAggressiveAndAttackIfConditionMet.cpp @@ -12,20 +12,30 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF560 - void AICState::setTribe0x11ToAggressiveAndAttackIfConditionMet(int param_1) + void AICState::setTribe0x11ToAggressiveAndAttackIfConditionMet(int playerID) { - int tribeID; - if (((0 < *(int*)((int)DAT_TroopValueState::instance.attackInfo.moatValuesArray + param_1 * 0x177bc + -4)) - && (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL)) - && (tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0x11], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[0x11]) - && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { - DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( - tribeID, Map::Units::STBT_0x3f7); - } + if (DAT_TroopValueState::instance.attackInfo.playerInfo[playerID - 1].moat2 <= 0) { + return; } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return; + } + + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[17]; + if (tribeID == 0) { + return; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[17]) { + return; + } + if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) { + return; + } + + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f7); } } } diff --git a/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp index 87e451e47..1dc2cf667 100644 --- a/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp +++ b/src/OpenSHC/AI/AICState/setTribe0xbToAggressiveAndAttack.cpp @@ -13,17 +13,25 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF6E0 void AICState::setTribe0xbToAggressiveAndAttack(int playerID) { - int tribeID; - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) - && (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb]) - && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { - DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( - tribeID, Map::Units::STBT_0x3f2); - } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return; } + + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[11]; + if (tribeID == 0) { + return; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[11]) { + return; + } + if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) { + return; + } + + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f2); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 53e4764ea..0cef99de7 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35363,13 +35363,13 @@ SHC_3BB0A8C1_0x004CF470 | 0.0% | Pending SHC_3BB0A8C1_0x004CF4F0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CF560 | 0.0% | Pending +SHC_3BB0A8C1_0x004CF560 | 37.74% | Reimplemented functionally, different register usage SHC_3BB0A8C1_0x004CF5E0 | 100.0% | Reimplemented without for-loop SHC_3BB0A8C1_0x004CF660 | 100.0% | Reimplemented without for-loop -SHC_3BB0A8C1_0x004CF6E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CF6E0 | 62.22% | Reimplemented functionally, different register usage SHC_3BB0A8C1_0x004CF750 | 0.0% | Pending From 78bdf23039dc847fc6f5c428c2b68d55e8e94e25 Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sat, 19 Sep 2026 16:43:01 +0200 Subject: [PATCH 070/242] reimplement: SHC_3BB0A8C1_0x004CACB0 100% --- ...TargetForTribeBasedOnTargetChoiceLogic.cpp | 195 +++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 75 insertions(+), 122 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp index da5f9a721..f9d369e1e 100644 --- a/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp +++ b/src/OpenSHC/AI/AICState/setTargetForTribeBasedOnTargetChoiceLogic.cpp @@ -3,8 +3,7 @@ #include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AIC/AITargetChoice.hpp" -#include "OpenSHC/AI/AIC/AITargetChoiceInt.hpp" -#include "OpenSHC/Game/Player/PlayerData.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" #include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -15,138 +14,92 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIC::AITargetChoice; - using OpenSHC::AI::AIC::AITargetChoiceInt; - using OpenSHC::Game::Player::PlayerData; - // FUNCTION: STRONGHOLDCRUSADER 0x004CACB0 - void AICState ::setTargetForTribeBasedOnTargetChoiceLogic(int owner, int tribe) - + void AICState::setTargetForTribeBasedOnTargetChoiceLogic(int owner, int tribe) { + if (DAT_GameState::instance.playerDataArray[owner].aiType == 0) { + return; + } - int _aiType = DAT_GameState::instance.playerDataArray[owner].aiType; - - int _targetPlayer = 0; - - if (_aiType != 0) { - - int _ownerKeepY = DAT_GameState::instance.playerDataArray[owner].campground.yEntry; - int _ownerKeepX = DAT_GameState::instance.playerDataArray[owner].campground.xEntry; - - int _minDistance = 10000; - int _maxGold = 0; - int _minPoints = 1000000; - - int _player = 1; - PlayerData* _ptrPlayerData = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); - - do { - - if ((DAT_GameState::instance.mapAndTime.playerTeams[_player] - != DAT_GameState::instance.mapAndTime.playerTeams[owner])) { - - int _lord = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_player); - - if (_lord != 0) { - - MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, - DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, - (_ptrPlayerData->campground).yEntry, _ownerKeepX, _ownerKeepY); - - AITargetChoiceInt _targetChoice = this->aics[_aiType - 1].TargetChoice; - - if (_targetChoice == OpenSHC::AI::AIC::AITC_PLAYER) { - - if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_player] != -1) { - - int _distance = DAT_DirectionAlgorithmState::instance.distanceHigh; - if (_distance <= _minDistance) { - _minDistance = _distance; - _targetPlayer = _player; - } - } - - } else if (_targetChoice == OpenSHC::AI::AIC::AITC_CLOSEST) { - - int _distance = DAT_DirectionAlgorithmState::instance.distanceHigh; - if (_distance <= _minDistance) { - _minDistance = _distance; - _targetPlayer = _player; - } - - } else if (_targetChoice == OpenSHC::AI::AIC::AITC_GOLD) { - - int _gold = _ptrPlayerData->currentResources[0xf]; - if (_maxGold <= _gold) { - _minDistance = _minDistance; - _maxGold = _gold; - _minPoints = _minPoints; - _targetPlayer = _player; - } + int aicIndex = DAT_GameState::instance.playerDataArray[owner].aiType - 1; + + int targetPlayer = 0; + int minDistance = 10000; + int maxGold = 0; + int minPoints = 1000000; + int ownerKeepX = DAT_GameState::instance.playerDataArray[owner].campground.xEntry; + int ownerKeepY = DAT_GameState::instance.playerDataArray[owner].campground.yEntry; + for (int player = 1; player < 9; player++) { + if (DAT_GameState::instance.mapAndTime.playerTeams[player] + == DAT_GameState::instance.mapAndTime.playerTeams[owner]) { + continue; + } + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(player) + == 0) { + continue; + } - } else if (_targetChoice == OpenSHC::AI::AIC::AITC_BALANCED) { + MACRO_CALL_MEMBER(Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(DAT_GameState::instance.playerDataArray[player].campground.xEntry, + DAT_GameState::instance.playerDataArray[player].campground.yEntry, ownerKeepX, ownerKeepY); - int _points = _ptrPlayerData->currentPopulation * 5 + _ptrPlayerData->totalTroopValue - + _ptrPlayerData->currentResources[0xf] / 100 - + DAT_DirectionAlgorithmState::instance.distanceHigh * 2; - if (_points <= _minPoints) { - _minDistance = _minDistance; - _maxGold = _maxGold; - _minPoints = _points; - _targetPlayer = _player; - } - } - } + if (this->aics[aicIndex].TargetChoice == AIC::AITC_PLAYER) { + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[player] != -1 + && DAT_DirectionAlgorithmState::instance.distanceHigh <= minDistance) { + minDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + targetPlayer = player; } + } else if (this->aics[aicIndex].TargetChoice == AIC::AITC_CLOSEST) { + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= minDistance) { + minDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + targetPlayer = player; + } + } else if (this->aics[aicIndex].TargetChoice == AIC::AITC_GOLD) { + if (DAT_GameState::instance.playerDataArray[player].currentResources[Game::Resources::RT_GOLD] + >= maxGold) { + maxGold + = DAT_GameState::instance.playerDataArray[player].currentResources[Game::Resources::RT_GOLD]; + targetPlayer = player; + } + } else if (this->aics[aicIndex].TargetChoice == AIC::AITC_BALANCED) { + int points = DAT_GameState::instance.playerDataArray[player].currentPopulation * 5 + + DAT_GameState::instance.playerDataArray[player].totalTroopValue + + DAT_GameState::instance.playerDataArray[player].currentResources[Game::Resources::RT_GOLD] / 100 + + DAT_DirectionAlgorithmState::instance.distanceHigh * 2; + if (points <= minPoints) { + minPoints = points; + targetPlayer = player; + } + } + } - _player = _player + 1; - _ptrPlayerData = _ptrPlayerData + 1; - - } while (_player < 9); - - if (_targetPlayer == 0) { - - int _playerID_backup = 1; - PlayerData* _ptrPlayerData_backup = &DAT_GameState::instance.playerDataArray[1]; - - do { - - if ((DAT_GameState::instance.mapAndTime.playerTeams[_playerID_backup] - != DAT_GameState::instance.mapAndTime.playerTeams[owner])) { - - int _lordBackup = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_playerID_backup); - - if (_lordBackup != 0) { - - MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, - DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData_backup->campground).xEntry, - (_ptrPlayerData_backup->campground).yEntry, _ownerKeepX, _ownerKeepY); - - if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _minDistance) { - _minDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; - _targetPlayer = _playerID_backup; - } - } - } - - _playerID_backup = _playerID_backup + 1; - _ptrPlayerData_backup = _ptrPlayerData_backup + 1; - - } while (_playerID_backup < 9); + if (targetPlayer == 0) { + // Fallback: pick the closest enemy with a living lord + for (int player = 1; player < 9; player++) { + if (DAT_GameState::instance.mapAndTime.playerTeams[player] + == DAT_GameState::instance.mapAndTime.playerTeams[owner]) { + continue; + } + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(player) + == 0) { + continue; + } - if (_targetPlayer == 0) { - return; + MACRO_CALL_MEMBER(Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(DAT_GameState::instance.playerDataArray[player].campground.xEntry, + DAT_GameState::instance.playerDataArray[player].campground.yEntry, ownerKeepX, ownerKeepY); + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= minDistance) { + minDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + targetPlayer = player; } } - DAT_TribesState::instance.tribes[tribe].targetPlayer_outpost = (short)_targetPlayer; + if (targetPlayer == 0) { + return; + } } - return; + DAT_TribesState::instance.tribes[tribe].targetPlayer_outpost = (short)targetPlayer; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 0cef99de7..03105d706 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34191,7 +34191,7 @@ SHC_3BB0A8C1_0x004CA8A0 | 0.0% | Pending SHC_3BB0A8C1_0x004CAC70 | 0.0% | Pending -SHC_3BB0A8C1_0x004CACB0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CACB0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CAD10 | 0.0% | Pending From 0d5a71bbbae11ac9b95aafe702849a1cb621308b Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sat, 19 Sep 2026 16:46:46 +0200 Subject: [PATCH 071/242] reimplement: SHC_3BB0A8C1_0x004CE3B0 100% --- .../AICState/setNextMoveLocationForUnits.cpp | 41 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp b/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp index 80b02a58c..0afc6660e 100644 --- a/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp +++ b/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp @@ -13,40 +13,23 @@ namespace OpenSHC { namespace AI { - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CE3B0 - void AICState ::setNextMoveLocationForUnits(int playerID) - + void AICState::setNextMoveLocationForUnits(int playerID) { - - if ((short)DAT_TileMapState::instance.OrganismLayer - [DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] - .addXgetTile - + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX] - != 0) { - - MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)( - (int)(short)DAT_TileMapState::instance.OrganismLayer - [DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] - .addXgetTile - + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]); + int organismID = (short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]; + if (organismID != 0) { + MACRO_CALL_MEMBER(Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)(organismID); } - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + MACRO_CALL_MEMBER(Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, - (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY)), -1, -1, 4000, FALSE); - - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::setDestinationPairsBasedOnPreviousSearch, - DAT_PathFindingState::ptr)( - playerID + -1, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - - return; + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, -1, -1, 4000, FALSE); + MACRO_CALL_MEMBER(Map::Navigation::PathFindingState_Func::setDestinationPairsBasedOnPreviousSearch, + DAT_PathFindingState::ptr)(playerID - 1, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 03105d706..f48677041 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35311,7 +35311,7 @@ SHC_3BB0A8C1_0x004CE200 | 0.0% | Pending SHC_3BB0A8C1_0x004CE270 | 0.0% | Pending -SHC_3BB0A8C1_0x004CE3B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CE3B0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE430 | 0.0% | Pending From b56a91b46df6657b6692971f6bb8561ca4b4aa6e Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 08:12:23 +0200 Subject: [PATCH 072/242] improve style --- src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp index 8f0706f81..471100a98 100644 --- a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp +++ b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp @@ -8,15 +8,13 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB1B0 int AICState::setNextFarmTypeToBuild(PlayerID playerID) - { - unsigned int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (_aiType == AITA_NULL) { return 0; } _aiType += -1; - int* _ptrAiFarmIndex = &DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex; - *_ptrAiFarmIndex = *_ptrAiFarmIndex + 1; + DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex += 1; if (8 <= DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex) { DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; } From 07d628006b58dfb9e5ab6d52c010c54ff1285c39 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 08:13:42 +0200 Subject: [PATCH 073/242] reimplement: SHC_3BB0A8C1_0x004D18B0 100% --- src/OpenSHC/AI/AICState/setInitialAIC.cpp | 7 ------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setInitialAIC.cpp b/src/OpenSHC/AI/AICState/setInitialAIC.cpp index cb991a970..0f1970d6d 100644 --- a/src/OpenSHC/AI/AICState/setInitialAIC.cpp +++ b/src/OpenSHC/AI/AICState/setInitialAIC.cpp @@ -3,14 +3,9 @@ namespace OpenSHC { namespace AI { - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D18B0 void AICState ::setInitialAIC() - { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::wipeAICMemory, this)(); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_01, this)(1); @@ -44,8 +39,6 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_15, this)(0xf); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAICParameters_16, this)(0x10); - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f48677041..fa0ab1912 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35469,7 +35469,7 @@ SHC_3BB0A8C1_0x004D1700 | 0.0% | Pending SHC_3BB0A8C1_0x004D1710 | 0.0% | Pending -SHC_3BB0A8C1_0x004D18B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D18B0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D1950 | 0.0% | Pending From e524977ad1120a1c8ff37784090452199bf70bd7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 08:23:07 +0200 Subject: [PATCH 074/242] reimplement: SHC_3BB0A8C1_0x004CF5E0 100% --- ...htTribe0xc0TribesToAggressiveAndAttack.cpp | 35 ++++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp index 79dbdfb54..bf1b2a003 100644 --- a/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp +++ b/src/OpenSHC/AI/AICState/setEightTribe0xc0TribesToAggressiveAndAttack.cpp @@ -13,22 +13,25 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF5E0 void AICState::setEightTribe0xc0TribesToAggressiveAndAttack(int playerID) { - if (DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) { - int iVar1 = 0; - short* psVar2 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xc0; - do { - int _tribeID = (int)*psVar2; - if (((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar1 + 0xc0])) - && (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { - DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( - _tribeID, Map::Units::STBT_0x3f2); - } - iVar1 = iVar1 + 1; - psVar2 = psVar2 + 1; - } while (iVar1 < 8); + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return; + } + + for (int i = 0; i < 8; i++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[i + 0xc0]; + if (tribeID == 0) { + continue; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[i + 0xc0]) { + continue; + } + if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) { + continue; + } + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f2); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index fa0ab1912..efdc9bdfb 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35365,7 +35365,7 @@ SHC_3BB0A8C1_0x004CF4F0 | 0.0% | Pending SHC_3BB0A8C1_0x004CF560 | 37.74% | Reimplemented functionally, different register usage -SHC_3BB0A8C1_0x004CF5E0 | 100.0% | Reimplemented without for-loop +SHC_3BB0A8C1_0x004CF5E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CF660 | 100.0% | Reimplemented without for-loop From 5a37488aaf386088932608ab01e617c5abd304c4 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 17:14:53 +0200 Subject: [PATCH 075/242] reimplement: SHC_3BB0A8C1_0x004CDE60 76.09% stuck --- .../AI/AICState/setCurrentAttackStrength.cpp | 45 ++++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp index a762c3c96..6f3b346e7 100644 --- a/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp +++ b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp @@ -11,29 +11,30 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CDE60 void AICState::setCurrentAttackStrength(int playerID) { - int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType != AITA_NULL) { - int _randomNumber = (int)SEC_RNG::instance.currentNumber2; - MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - int _attForceRandom = (int)this->aics[_aiType - 1].AttForceRandom; - int* _attackWave = &DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; - *_attackWave = *_attackWave + 1; - int _currentGold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return; + } + + aiType -= 1; + + int randomPercent = SEC_RNG::instance.currentNumber2 % 100; + MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength + = (this->aics[aiType].AttForceRandom * randomPercent) / 100; + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave += 1; + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] > 10000) { + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength + += DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 7; + } else { DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength - = (_attForceRandom * (_randomNumber % 100)) / 100; - int _currentAttackWave = DAT_GameState::instance.playerDataArray[playerID].currentAttackWave; - if (_currentGold < 10001) { - int* _ptrAttackStrength - = &DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; - *_ptrAttackStrength = *_ptrAttackStrength + _currentAttackWave * 5; - } else { - int* _ptrAttackStrength - = &DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; - *_ptrAttackStrength = *_ptrAttackStrength + _currentAttackWave * 7; - } - if (200 < DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength) { - DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 200; - } + += DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 5; + } + + if (DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength > 200) { + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 200; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index efdc9bdfb..06d25031d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35295,7 +35295,7 @@ SHC_3BB0A8C1_0x004CDCA0 | 0.0% | Pending SHC_3BB0A8C1_0x004CDCF0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CDE60 | 0.0% | Pending +SHC_3BB0A8C1_0x004CDE60 | 76.09% | Reimplemented functionally different register usage SHC_3BB0A8C1_0x004CDF10 | 0.0% | Pending From d1102caad3bbd31c450010e104238e3f16d2d64a Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 17:27:17 +0200 Subject: [PATCH 076/242] reimplement: SHC_3BB0A8C1_0x004CDF10 72.00% stuck --- .../setCurrentAttackRaidParameter.cpp | 43 ++++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp index 21e9aeba4..c53378ce5 100644 --- a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp +++ b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp @@ -11,27 +11,30 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CDF10 void AICState::setCurrentAttackRaidParameter(int playerID) { - int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType != AITA_NULL) { - int _rng = (int)SEC_RNG::instance.currentNumber2; - MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - AICSpecification const* spec = &this->aics[_aiType - 1]; - int _gold = DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf]; - int _raidUnitsRandom = (int)spec->RaidUnitsRandom; - if (_gold < 1000) { - _raidUnitsRandom = 0; - } else if (4999 < _gold) { - _raidUnitsRandom = _raidUnitsRandom * 2; - } - if (DAT_GameState::instance - .playerDataArray[DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk] - .currentResources[0xf] - < 500) { - _raidUnitsRandom = -((int)spec->RaidUnitsBase / 2); - } - DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter - = (_raidUnitsRandom * (_rng % 100)) / 100; + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) { + return; } + + int randomPercent = SEC_RNG::instance.currentNumber2 % 100; + MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + + int raidUnits = this->aics[aiType - 1].RaidUnitsRandom; + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < 1000) { + raidUnits = 0; + } else if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] >= 5000) { + raidUnits *= 2; + } + + if (DAT_GameState::instance + .playerDataArray[DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk] + .currentResources[0xf] + < 500) { + raidUnits = -(this->aics[aiType - 1].RaidUnitsBase / 2); + } + + DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + = (raidUnits * randomPercent) / 100; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 06d25031d..45c442f5c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35297,7 +35297,7 @@ SHC_3BB0A8C1_0x004CDCF0 | 0.0% | Pending SHC_3BB0A8C1_0x004CDE60 | 76.09% | Reimplemented functionally different register usage -SHC_3BB0A8C1_0x004CDF10 | 0.0% | Pending +SHC_3BB0A8C1_0x004CDF10 | 72.0% | Reimplemented functionally, same different register usage as above SHC_3BB0A8C1_0x004CDFD0 | 0.0% | Pending From a58ef148e8535a4e99e2604fdf0c44f4e595ec25 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 17:39:29 +0200 Subject: [PATCH 077/242] reimplement: SHC_3BB0A8C1_0x004CDFD0 100% --- .../AI/AICState/setAttackPrimeInfo.cpp | 19 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp index 7910e23a0..25e1873db 100644 --- a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp +++ b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp @@ -11,17 +11,16 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CDFD0 void AICState::setAttackPrimeInfo(int playerID, int attackedPlayerID) { - int _tile = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile; - int _zone = (int)(char)DAT_TileMapState::instance.AIZoneLayer[_tile]; - int _pathCon = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_tile]; - int _zoneSize = DAT_PathFindingState::instance.zoneSizesArray[_pathCon]; - DAT_TroopValueState::instance.attackInfo.startCon = _pathCon; - int _attackedTile = DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry; - DAT_TroopValueState::instance.attackInfo.startZone = _zone; - DAT_TroopValueState::instance.attackInfo.zoneSize = _zoneSize; + int tile = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile; + DAT_TroopValueState::instance.attackInfo.startZone = (char)DAT_TileMapState::instance.AIZoneLayer[tile]; + DAT_TroopValueState::instance.attackInfo.startCon = (short)DAT_TileMapState::instance.PathConnectionLayer[tile]; + DAT_TroopValueState::instance.attackInfo.zoneSize + = DAT_PathFindingState::instance.zoneSizesArray[DAT_TroopValueState::instance.attackInfo.startCon]; DAT_TroopValueState::instance.attackInfo.unknownOne_0x20f90 = 1; - DAT_TroopValueState::instance.attackInfo.keepCon - = (int)(short)DAT_TileMapState::instance.PathConnectionLayer[_attackedTile]; + DAT_TroopValueState::instance.attackInfo.keepCon = (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_GameState::instance + .playerDataArray[attackedPlayerID] + .campground.tileEntry]; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 45c442f5c..b3b73e54b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35299,7 +35299,7 @@ SHC_3BB0A8C1_0x004CDE60 | 76.09% | Reimplemented functionally different register SHC_3BB0A8C1_0x004CDF10 | 72.0% | Reimplemented functionally, same different register usage as above -SHC_3BB0A8C1_0x004CDFD0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CDFD0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE040 | 0.0% | Pending From c7a2912cdf84cd0a2fe2f51716a0aec0712c3cff Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 18:40:16 +0200 Subject: [PATCH 078/242] reimplement: SHC_3BB0A8C1_0x004D4340 54.63% stuck --- ...sendWallPatrolUnitTribesToAIVLocations.cpp | 175 ++++++------------ .../AICState/setAttackCoordinationLevel.cpp | 29 +-- status/addresses-SHC-3BB0A8C1.txt | 2 +- 3 files changed, 73 insertions(+), 133 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp index 35b83c413..be55240a6 100644 --- a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp +++ b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp @@ -24,132 +24,71 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D4340 - void AICState ::sendWallPatrolUnitTribesToAIVLocations(int playerID) - + void AICState::sendWallPatrolUnitTribesToAIVLocations(int playerID) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) { + return; + } - BOOLEnum _enclosed; - - int _tribeID; - - AIVUnitTypeInt* _ptr; - - int _patrolGroupIndex; - - int _index; - - int _minCount; - - int _stepSize; - - int _defWallPatrolGroups; - - AITypeInt _aiType; - - int _count; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType != OpenSHC::AI::AIT_NULL) { - - _enclosed = MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); - - /* - defWallPatrolGroups */ - - _ptr = &DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[0].aivUnitType; - - do { - - _defWallPatrolGroups = *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x114); - - _count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*_ptr]; - - _index = 0; - - _minCount = _count; - - if (_defWallPatrolGroups < _count) { - - _minCount = _defWallPatrolGroups; + BOOLEnum enclosed = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + + for (int i = 0; i < 3; i++) { + int count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount + [DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[i].aivUnitType]; + int groups = count; + if (count > this->aics[aiType - 1].defWallPatrolGroups) { + groups = this->aics[aiType - 1].defWallPatrolGroups; + } + if (groups <= 0) { + continue; + } + + int stepSize = count / groups; + if (stepSize <= 0) { + stepSize = 1; + } + + for (int j = 0, patrolGroupIndex = 0; j < groups; j++, patrolGroupIndex += stepSize) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[i] + .tribeArrayOffset + + j]; + if (tribeID == 0) { + continue; } - - if (0 < _minCount) { - - _stepSize = _count / _minCount; - - if (_stepSize < 1) { - - _stepSize = 1; - } - - if (0 < _minCount) { - - _patrolGroupIndex = 0; - - do { - - _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID] - .aiTribeIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset - + _index]; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset - + _index])) { - - if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) - || (_enclosed != FALSE)) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( - _tribeID, (AIVUnitType)((int)(*_ptr)), - (DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits - + _patrolGroupIndex) - % _count); - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, playerID); - } - - if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) - || (_enclosed != FALSE)) { - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - } - - else { - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - } - } - - _patrolGroupIndex = _patrolGroupIndex + _stepSize; - - _index = _index + 1; - - } while (_index < _minCount); - } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[i] + .tribeArrayOffset + + j]) { + continue; } - _ptr = _ptr + 2; + int slot = (DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits + + patrolGroupIndex) + % count; + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0 + && enclosed == FALSE) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(tribeID, playerID); + } else { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)(tribeID, + (AIVUnitType)DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[i].aivUnitType, + slot); + } - } while ((int)_ptr < 0xb42794); + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0 + && enclosed == FALSE) { + DAT_TribesState::instance.tribes[tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + } else { + DAT_TribesState::instance.tribes[tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + } + } } - - return; } } diff --git a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp index 339f09d84..b6a98e489 100644 --- a/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp +++ b/src/OpenSHC/AI/AICState/setAttackCoordinationLevel.cpp @@ -12,21 +12,22 @@ namespace AI { void AICState::setAttackCoordinationLevel(int playerID) { int const _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType != AITA_NULL) { - int _willingnessPercentage = (int)this->aics[_aiType - 1].AttCoordinationPreference - + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; - if (90 < _willingnessPercentage) { - _willingnessPercentage = 90; - } - int _rngMod100 = (int)(short)SEC_RNG::instance.currentNumber2 % 100; - MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - if (_rngMod100 < _willingnessPercentage / 2) { - DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = 2; - return; - } - DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel - = (uint)(_rngMod100 < _willingnessPercentage); + if (_aiType == AITA_NULL) { + return; } + int _willingnessPercentage = this->aics[_aiType - 1].AttCoordinationPreference + + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; + if (90 < _willingnessPercentage) { + _willingnessPercentage = 90; + } + int _rngMod100 = SEC_RNG::instance.currentNumber2 % 100; + MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + if (_rngMod100 < _willingnessPercentage / 2) { + DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel = 2; + return; + } + DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel + = _rngMod100 < _willingnessPercentage; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b3b73e54b..76938d28e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35539,7 +35539,7 @@ SHC_3BB0A8C1_0x004D4130 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D4220 | 0.0% | Pending -SHC_3BB0A8C1_0x004D4340 | 0.0% | Pending +SHC_3BB0A8C1_0x004D4340 | 54.63% | Reimplemented, different register usage SHC_3BB0A8C1_0x004D4400 | 0.0% | Pending From 4d5e7fd3369f260eb3bba2758974da82b853713b Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 19:26:26 +0200 Subject: [PATCH 079/242] reimplement: SHC_3BB0A8C1_0x004CE5F0 100% --- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 99 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 41 insertions(+), 60 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index 9ba845356..9f0595474 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -17,78 +17,59 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - /** - * I seem unable to make this match better than 75.42% even though this function flow is dumb: _ghX and _ghY are - * only specified if not navigatable, which is checked twice for some reason. - */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CE5F0 void AICState::sendUnitsToPlayerIDsKeepIfPossible(int playerID1, int playerID2) { - uint _p1_campfireX = DAT_GameState::instance.playerDataArray[playerID1].campground.xEntry; - uint _p1_campfireY = DAT_GameState::instance.playerDataArray[playerID1].campground.yEntry; - - int const _canNavigate = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID1, playerID2); - - uint _ghX; - uint _ghY; + uint campfireX = DAT_GameState::instance.playerDataArray[playerID1].campground.xEntry; + uint campfireY = DAT_GameState::instance.playerDataArray[playerID1].campground.yEntry; - if (_canNavigate == FALSE) { - dword const _gatehouseTile - = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findOwnedGatehouse, - DAT_PathFindingState::ptr)(playerID2, _p1_campfireX, _p1_campfireY); - if (_gatehouseTile == 0) { + uint gatehouseX; + uint gatehouseY; + if (MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( + playerID1, playerID2) + == FALSE) { + uint gatehouseTile = MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findOwnedGatehouse, + DAT_PathFindingState::ptr)(playerID2, campfireX, campfireY); + if (gatehouseTile != 0) { + gatehouseY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[gatehouseTile]; + gatehouseX = gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[gatehouseY].addXgetTile; + } else { DAT_GameState::instance.playerDataArray[playerID1].requestStateUnk = 0; return; } - _ghY = (uint)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_gatehouseTile]; - _ghX = _gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[_ghY].addXgetTile; } - for (int _index = 0; _index < 11; _index++) { - int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; - int _tribeIndex = 0; - int const _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - - for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { - - int const _tribeID - = (int)DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID1] - .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + for (int i = 0; i < 11; i++) { + int tribeTypeStart = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType; + int tribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeCount; + for (int j = 0; j < tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID1].aiTribeIDs[tribeTypeStart + j]; + if (tribeID == 0) { + continue; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID1].aiTribeUIDs[j + tribeTypeStart]) { + continue; + } - int const _canNav2 - = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID1, playerID2); + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - if (_canNav2 != FALSE) { - if (_tribeTypeStart == 0xbe) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, playerID2); - } else { - int const _hasHorses - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, - DAT_TribesState::ptr)(_tribeID); - if (_hasHorses != FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, playerID2); - } else { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)( - _tribeID, playerID2); - } - } + if (MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, + DAT_GameState::ptr)(playerID1, playerID2) + != FALSE) { + if (tribeTypeStart == 0xbe) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(tribeID, playerID2); + } else if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(tribeID) + != FALSE) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(tribeID, playerID2); } else { - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - _tribeID, _ghX, _ghY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, playerID2); } + } else { + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, gatehouseX, gatehouseY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 76938d28e..082f5529a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35319,7 +35319,7 @@ SHC_3BB0A8C1_0x004CE4D0 | 0.0% | Pending SHC_3BB0A8C1_0x004CE530 | 0.0% | Pending -SHC_3BB0A8C1_0x004CE5F0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CE5F0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE660 | 0.0% | Pending From 35980a6f11875019c54c99b10143415fde4811de Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 19:26:58 +0200 Subject: [PATCH 080/242] reimplement: SHC_3BB0A8C1_0x004CD0C0 100% --- src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp | 12 +++++++----- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp index dd0c25b0d..fcb585017 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToKeep.cpp @@ -11,12 +11,14 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CD0C0 void AICState::sendUnitsToKeep(int tribeID, int playerID) { - int iVar1 = DAT_GameState::instance.playerDataArray[playerID].keep.id; - if (0 < iVar1) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, - (int)(short)DAT_BuildingsState::instance.buildings[iVar1].x + 3, - (int)(short)DAT_BuildingsState::instance.buildings[iVar1].y + 4, 0); + int keepID = DAT_GameState::instance.playerDataArray[playerID].keep.id; + if (keepID <= 0) { + return; } + + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, + (short)DAT_BuildingsState::instance.buildings[keepID].x + 3, + (short)DAT_BuildingsState::instance.buildings[keepID].y + 4, 0); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 082f5529a..676375df9 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35265,7 +35265,7 @@ SHC_3BB0A8C1_0x004CCFB0 | 0.0% | Pending SHC_3BB0A8C1_0x004CD070 | 0.0% | Pending -SHC_3BB0A8C1_0x004CD0C0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CD0C0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CD110 | 0.0% | Pending From 6d5169f8da5dd477585ee64fd45483b30fb865d5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 19:31:56 +0200 Subject: [PATCH 081/242] reimplement: SHC_3BB0A8C1_0x004CD110 100% --- src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp | 12 +++++++----- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp b/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp index b81436f3d..c824f5d75 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToCampfire.cpp @@ -11,12 +11,14 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CD110 void AICState::sendUnitsToCampfire(int tribeID, int playerID) { - if (0 < DAT_GameState::instance.playerDataArray[playerID].campground.id) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, - DAT_GameState::instance.playerDataArray[playerID].campground.xEntry, - DAT_GameState::instance.playerDataArray[playerID].campground.yEntry, 0); - DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + if (DAT_GameState::instance.playerDataArray[playerID].campground.id <= 0) { + return; } + + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)(tribeID, + DAT_GameState::instance.playerDataArray[playerID].campground.xEntry, + DAT_GameState::instance.playerDataArray[playerID].campground.yEntry, 0); + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 676375df9..02535b0b7 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35267,7 +35267,7 @@ SHC_3BB0A8C1_0x004CD070 | 0.0% | Pending SHC_3BB0A8C1_0x004CD0C0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CD110 | 0.0% | Pending +SHC_3BB0A8C1_0x004CD110 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CD160 | 0.0% | Pending From 68648d5cdac115e3d540e2f4109387fb9f51bc29 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 19:33:08 +0200 Subject: [PATCH 082/242] reimplement: SHC_3BB0A8C1_0x004CF750 100% --- src/OpenSHC/AI/AICState/sendTribeToAttack.cpp | 28 ++++++++++++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp b/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp index 86bc99714..82f959aed 100644 --- a/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeToAttack.cpp @@ -13,17 +13,25 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF750 void AICState::sendTribeToAttack(int playerID) { - int tribeID; - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) - && (tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbd], tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbd]) - && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { - DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( - tribeID, Map::Units::STBT_0x3fb); - } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return; } + + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbd]; + if (tribeID == 0) { + return; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbd]) { + return; + } + if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) { + return; + } + + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3fb); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 02535b0b7..758f83a1e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35371,7 +35371,7 @@ SHC_3BB0A8C1_0x004CF660 | 100.0% | Reimplemented without for-loop SHC_3BB0A8C1_0x004CF6E0 | 62.22% | Reimplemented functionally, different register usage -SHC_3BB0A8C1_0x004CF750 | 0.0% | Pending +SHC_3BB0A8C1_0x004CF750 | 62.22% | Reimplemented functionally, our compiler improves on original by avoiding recomputations SHC_3BB0A8C1_0x004CF7C0 | 100.0% | Reimplemented, for-loop didn't work From 971e0ca8a1d6cf4603180441624b75d79742bfb7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 19:53:42 +0200 Subject: [PATCH 083/242] reimplement: SHC_3BB0A8C1_0x004D30E0 100% --- .../sendUnitsToAttackBreachedCastle.cpp | 210 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 70 insertions(+), 142 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp index 89d81f17b..ccfd04650 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp @@ -7,6 +7,7 @@ #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" +#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -21,160 +22,87 @@ namespace AI { using OpenSHC::Map::Units::SomeTribeBehaviorType; using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + using OpenSHC::WindowsHelper::Enums::BOOLEnum; // FUNCTION: STRONGHOLDCRUSADER 0x004D30E0 - undefined4 AICState ::sendUnitsToAttackBreachedCastle(int attackingPlayerIndex) - + undefined4 AICState::sendUnitsToAttackBreachedCastle(int attackingPlayerIndex) { - - int tribeType; - - int _defendingLordIndex; - - int _successUnk; - - int iVar1; - - int _vector; - - int _tribeID; - - short* local_20; - - int local_18; - - int (*_ptrGroupCount)[2]; - - int _attackedPlayerID; - - int _groupCount; - - short _targetUnit; - - bool sentUnitsToAttackLord; - - _vector = 0; - + int vector = 0; if (DAT_GameState::instance.playerDataArray[attackingPlayerIndex].aiType == OpenSHC::AI::AIT_NULL) { - - return (undefined4)(1); + return 1; } - sentUnitsToAttackLord = false; - - _defendingLordIndex = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, + BOOLEnum sentUnitsToAttackLord = FALSE; + int defendingLordID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID); - _ptrGroupCount = (int (*)[2])(&DAT_SkirmishDefinedData::instance.MaxBreachTribes[0].tribeCount); - - do { - - tribeType = _ptrGroupCount[-1][1]; - - _groupCount = (*_ptrGroupCount)[0]; - - if ((((tribeType != 18) && (tribeType != 14)) && (tribeType != 13)) && (local_18 = 0, 0 < _groupCount)) { - - local_20 = DAT_GameState::instance.playerDataArray[attackingPlayerIndex].aiTribeIDs + tribeType; - - do { - - _tribeID = (int)*local_20; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[attackingPlayerIndex] - .aiTribeUIDs[local_18 + tribeType])) { - - _targetUnit = DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - - if ((sentUnitsToAttackLord) || ((_defendingLordIndex == 0 || (tribeType == 186)))) { - - iVar1 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveSomeRaidCommand, this)( - _tribeID, tribeType); - - if (iVar1 == 0) { - - if (tribeType == 0xba) { - - _vector = _vector + 4; - } - - DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType - = OpenSHC::Map::Units::STBT_8; - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - iVar1 = DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID; - - MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, - DAT_DirectionAlgorithmState::ptr)( - (int)DAT_UnitsState::instance.units[_targetUnit].x, - (int)((int)(DAT_UnitsState::instance.units[_targetUnit].y)), - DAT_GameState::instance.mapAndTime.attackVectors[iVar1][_vector].x, - DAT_GameState::instance.mapAndTime.attackVectors[iVar1][_vector].y); - - if (4 < DAT_DirectionAlgorithmState::instance.distanceHigh) { - - _attackedPlayerID = DAT_GameState::instance.playerDataArray[attackingPlayerIndex] - .attackedPlayerID; - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(_tribeID, - (uint)((int)(DAT_GameState::instance.mapAndTime - .attackVectors[_attackedPlayerID][_vector] - .x)), - (uint)((int)(DAT_GameState::instance.mapAndTime - .attackVectors[_attackedPlayerID][_vector] - .y)), - 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - } - - _vector = _vector + 1; - } - - } - - else { - - /* - Send units to attack lord */ - - _successUnk = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - _tribeID, (uint)((int)((int)DAT_UnitsState::instance.units[_defendingLordIndex].x)), - (uint)((int)((int)DAT_UnitsState::instance.units[_defendingLordIndex].y)), 0, 0, - OpenSHC::Map::Units::Instructions::UMSE_0); - - if (_successUnk == 0) { - - return (undefined4)(0); - } + for (int i = 0; i < 11; i++) { + int tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[i].tribeType; + int tribeCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[i].tribeCount; + if (tribeType == 18 || tribeType == 14 || tribeType == 13) { + continue; + } - sentUnitsToAttackLord = true; - } + for (int j = 0; j < tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[attackingPlayerIndex].aiTribeIDs[tribeType + j]; + if (tribeID == 0) { + continue; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[attackingPlayerIndex].aiTribeUIDs[j + tribeType]) { + continue; + } + + int targetUnitID = (short)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + + if (sentUnitsToAttackLord != FALSE || defendingLordID == 0 || tribeType == 186) { + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::giveSomeRaidCommand, this)(tribeID, tribeType) + != 0) { + continue; } - local_20 = local_20 + 1; - - local_18 = local_18 + 1; - - } while (local_18 < _groupCount); + if (tribeType == 186) { + vector += 4; + } + DAT_TribesState::instance.tribes[tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_8; + DAT_TribesState::instance.tribes[tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + + int attackedPlayerID + = DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(DAT_UnitsState::instance.units[targetUnitID].x, + DAT_UnitsState::instance.units[targetUnitID].y, + DAT_GameState::instance.mapAndTime.attackVectors[attackedPlayerID][vector].x, + DAT_GameState::instance.mapAndTime.attackVectors[attackedPlayerID][vector].y); + + if (DAT_DirectionAlgorithmState::instance.distanceHigh > 4) { + attackedPlayerID + = DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID; + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, DAT_GameState::instance.mapAndTime.attackVectors[attackedPlayerID][vector].x, + DAT_GameState::instance.mapAndTime.attackVectors[attackedPlayerID][vector].y, 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + } + vector += 1; + } else { + // Send units to attack lord + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, DAT_UnitsState::instance.units[defendingLordID].x, + DAT_UnitsState::instance.units[defendingLordID].y, 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0) + == 0) { + return 0; + } + sentUnitsToAttackLord = TRUE; + } } + } - _ptrGroupCount = _ptrGroupCount + 1; - - } while ((int)_ptrGroupCount < 0xb42acc); - - return (undefined4)(1); + return 1; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 758f83a1e..9f720774e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35509,7 +35509,7 @@ SHC_3BB0A8C1_0x004D2EC0 | 0.0% | Pending SHC_3BB0A8C1_0x004D2F80 | 0.0% | Pending -SHC_3BB0A8C1_0x004D30E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D30E0 | 100.0% | Reimplemented, barring one register usage difference SHC_3BB0A8C1_0x004D3320 | 87.69% | Reimplemented, different register usage, effectively 100% From 44bd0e19b228d2a254136d29b4f2e4d9f6a19e15 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 19:58:39 +0200 Subject: [PATCH 084/242] reimplement: SHC_3BB0A8C1_0x004D2E00 100% --- .../AICState/sendTribeToAIVLocationSlot.cpp | 43 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp index 99dea9737..a93f91fa0 100644 --- a/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeToAIVLocationSlot.cpp @@ -15,37 +15,34 @@ namespace AI { using OpenSHC::WindowsHelper::Enums::BOOLEnum; // FUNCTION: STRONGHOLDCRUSADER 0x004D2E00 - void AICState ::sendTribeToAIVLocationSlot(int tribeID, AIVUnitType aivUnitType, int slotIndex) + void AICState::sendTribeToAIVLocationSlot(int tribeID, AIVUnitType aivUnitType, int slotIndex) { - int _owner = DAT_TribesState::instance.tribes[tribeID].owner; - int _tile = 0; - int _slotIndex = 0; - int* _ptrSlot = (int*)(_owner * 0x39f4 + 0x115eb14 + aivUnitType * 0x28); - - // Find the slot at slotIndex, skipping empty entries - while (*_ptrSlot == 0 || (slotIndex = slotIndex + -1, -1 < slotIndex)) { - _slotIndex = _slotIndex + 1; - _ptrSlot = _ptrSlot + 1; - if (9 < _slotIndex) + int owner = DAT_TribesState::instance.tribes[tribeID].owner; + + // Find the slotIndex-th non-empty slot + int tile = 0; + for (int i = 0; i < 10; i++) { + if (DAT_GameState::instance.playerDataArray[owner].aivUnitLocationSlots[aivUnitType][i] == 0) { + continue; + } + slotIndex--; + if (slotIndex < 0) { + tile = DAT_GameState::instance.playerDataArray[owner].aivUnitLocationSlots[aivUnitType][i]; break; + } } - if (_slotIndex <= 9) - _tile = DAT_GameState::instance.playerDataArray[_owner].aivUnitLocationSlots[aivUnitType][_slotIndex]; + int y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]; + int x = tile - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; - short _y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; - int _x = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; - - BOOLEnum _canNavigate - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, _tile); - - if (_canNavigate == FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, _owner); + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, tile) + != FALSE) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + tribeID, x, y, 0); return; } - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( - tribeID, (uint)((int)(_tile - _x)), (uint)((int)((int)_y)), 0); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, owner); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9f720774e..b8605a2a3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35503,7 +35503,7 @@ SHC_3BB0A8C1_0x004D28B0 | 0.0% | Pending SHC_3BB0A8C1_0x004D2A70 | 0.0% | Pending -SHC_3BB0A8C1_0x004D2E00 | 0.0% | Pending +SHC_3BB0A8C1_0x004D2E00 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D2EC0 | 0.0% | Pending From ff0a34d676c491489ed10b2245f3c12292d4c1b1 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 20:01:30 +0200 Subject: [PATCH 085/242] reimplement: SHC_3BB0A8C1_0x004D2870 100% --- .../AI/AICState/sendTribeAtOffset1ToCampfire.cpp | 13 +++++++------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp index d7d47795b..272c3b113 100644 --- a/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp +++ b/src/OpenSHC/AI/AICState/sendTribeAtOffset1ToCampfire.cpp @@ -9,12 +9,13 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D2870 void AICState::sendTribeAtOffset1ToCampfire(int playerID) { - int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[1]; - if ((0 < _tribeID) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[1])) { - MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); - } + int _tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[1]; + if (_tribeID <= 0) + return; + if (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[1]) + return; + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b8605a2a3..4aae4607d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35497,7 +35497,7 @@ SHC_3BB0A8C1_0x004D27E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D2830 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D2870 | 0.0% | Pending +SHC_3BB0A8C1_0x004D2870 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D28B0 | 0.0% | Pending From 969c7eb187b599075312102676aab81ced9358a6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 20:04:30 +0200 Subject: [PATCH 086/242] reimplement: SHC_3BB0A8C1_0x004D4130 100% --- ...gedUnitTribesToAIVSlotsOrKeepIfNervous.cpp | 81 ++++++++----------- 1 file changed, 32 insertions(+), 49 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp index 79902f734..704a12842 100644 --- a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp +++ b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp @@ -18,58 +18,41 @@ namespace AI { using OpenSHC::AI::Tribes::AIVUnitTypeMaxLocationPair; // FUNCTION: STRONGHOLDCRUSADER 0x004D4130 - void AICState ::sendRangedUnitTribesToAIVSlotsOrKeepIfNervous(int playerID) - + void AICState::sendRangedUnitTribesToAIVSlotsOrKeepIfNervous(int playerID) { - - AIVUnitTypeInt* _ptr = &DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[0].aivUnitType; - - do { - - int _limit = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*_ptr]; - - int _index = 0; - - if (0 < _limit) { - - do { - - int _tribe = (int)DAT_GameState::instance.playerDataArray[playerID] - .aiTribeIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index]; - - if ((_tribe != 0) - && (DAT_TribesState::instance.tribes[_tribe].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index])) { - - if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { - - if ((DAT_TileMapState::instance.LogicLayer[DAT_UnitsState::instance - .units[DAT_TribesState::instance.tribes[_tribe].selectionTargetUnitID] - .tile] - & 0x10000100U) - == 0) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribe, playerID); - } - - } else { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( - _tribe, (AIVUnitType)((int)(*_ptr)), _index); - } + for (int i = 0; i < 5; i++) { + int count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount + [DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[i].aivUnitType]; + for (int j = 0; j < count; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[i] + .tribeArrayOffset + + j]; + if (tribeID == 0) { + continue; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[i] + .tribeArrayOffset + + j]) { + continue; + } + + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { + if ((DAT_TileMapState::instance.LogicLayer[DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID] + .tile] + & 0x10000100U) + == 0) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); } - - _index = _index + 1; - - } while (_index < _limit); + } else { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)(tribeID, + (AIVUnitType)DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[i].aivUnitType, j); + } } - - _ptr = _ptr + 2; - - } while ((int)_ptr < 0xb42744); - - return; + } } } From b2baeb3db758b74232f5e5bf8868f18c1ebe9328 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 20:07:51 +0200 Subject: [PATCH 087/242] reimplement: SHC_3BB0A8C1_0x004D44E0 100% --- ...sendOilMenForOilPickupOrToAIVLocations.cpp | 107 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 33 insertions(+), 76 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp index 7cf4247be..f5d86fd16 100644 --- a/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp +++ b/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp @@ -16,89 +16,46 @@ namespace AI { using OpenSHC::AI::AIVUnitType; using OpenSHC::Map::Units::UnitInstructionType; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D44E0 - void AICState ::sendOilMenForOilPickupOrToAIVLocations(int playerID) - + void AICState::sendOilMenForOilPickupOrToAIVLocations(int playerID) { + int oilSmelterID = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id; + int count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1]; + if (count < 1) { + return; + } + if (count == 10) { + count = 9; + } - short* _ptrTribeIDArray; - - int _oilManLocationsCount; - - int _tribeID; - - int _index; - - int _oilSmelter; - - _oilSmelter = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id; - - _oilManLocationsCount = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1]; - - if (0 < _oilManLocationsCount) { - - if (_oilManLocationsCount == 10) { - - _oilManLocationsCount = 9; + // Oil men tribes start at offset 71 in the tribe ID array + for (int i = 1; i <= count; i++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[70 + i]; + if (tribeID == 0) { + continue; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[70 + i]) { + continue; } - _index = 1; - - if (0 < _oilManLocationsCount) { - - /* - oil men offset in tribe id array */ - - _ptrTribeIDArray = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 71; - - do { - - _tribeID = (int)*_ptrTribeIDArray; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0x46])) { - - if (DAT_UnitsState::instance - .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID] - .resourceToDeposit - == 0) { - - if (_oilSmelter != 0) { - - /* - send for oil duty */ - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, - DAT_UnitsState::ptr)(_tribeID, - OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, - _oilSmelter, DAT_BuildingsState::instance.buildings[_oilSmelter].uid, 0); - } - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, - DAT_TribesState::ptr)(_tribeID); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( - _tribeID, OpenSHC::AI::AIVUT_ENGINEER, _index + -1); - } - } - - _index = _index + 1; - - _ptrTribeIDArray = _ptrTribeIDArray + 1; + if (DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID] + .resourceToDeposit + != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, + DAT_TribesState::ptr)(tribeID); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( + tribeID, OpenSHC::AI::AIVUT_ENGINEER, i - 1); + continue; + } - } while (_index <= _oilManLocationsCount); + // Send for oil duty + if (oilSmelterID != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + tribeID, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, oilSmelterID, + DAT_BuildingsState::instance.buildings[oilSmelterID].uid, 0); } } - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4aae4607d..73f57e341 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35543,7 +35543,7 @@ SHC_3BB0A8C1_0x004D4340 | 54.63% | Reimplemented, different register usage SHC_3BB0A8C1_0x004D4400 | 0.0% | Pending -SHC_3BB0A8C1_0x004D44E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D44E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D4530 | 0.0% | Pending From 7f8c96413f50cdc638c2426eb3f9a1ace2b62e46 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 20:09:56 +0200 Subject: [PATCH 088/242] reimplement: SHC_3BB0A8C1_0x004D4220 100% --- ...oAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp | 117 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 38 insertions(+), 81 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp index 16b723b64..cc8bb42ab 100644 --- a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp +++ b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp @@ -20,90 +20,47 @@ namespace AI { using OpenSHC::Map::Units::Behavior::UnitStanceEnum; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D4220 - void AICState ::sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed(int playerID) - + void AICState::sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed(int playerID) { - - BOOLEnum _enclosed; - - AIVUnitTypeInt* _ptr; - - int _tribe; - - int _index; - - int _limit; - - int* _nervous; - - _enclosed = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)( - playerID); - - _ptr = &DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[0].aivUnitType; - - do { - - _limit = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*_ptr]; - - _index = 0; - - if (0 < _limit) { - - _nervous = &DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; - - do { - - _tribe = (int)DAT_GameState::instance.playerDataArray[playerID] - .aiTribeIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index]; - - if ((_tribe != 0) - && (DAT_TribesState::instance.tribes[_tribe].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[((AIVUnitTypeMaxLocationPair*)(_ptr + -1))->tribeArrayOffset + _index])) { - - if ((*_nervous < 1) || (_enclosed != FALSE)) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( - _tribe, (AIVUnitType)((int)(*_ptr)), _index); - - } - - else { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribe, playerID); - } - } - - /* - bug:fixme: _tribe could be 0 */ - - if ((*_nervous < 1) || (_enclosed != FALSE)) { - - DAT_TribesState::instance.tribes[_tribe].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - + BOOLEnum enclosed = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + + for (int i = 0; i < 6; i++) { + int count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount + [DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[i].aivUnitType]; + for (int j = 0; j < count; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[i] + .tribeArrayOffset + + j]; + if (tribeID != 0 + && DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[i] + .tribeArrayOffset + + j]) { + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0 + || enclosed != FALSE) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)(tribeID, + (AIVUnitType)DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[i].aivUnitType, + j); + } else { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); } - - else { - - DAT_TribesState::instance.tribes[_tribe].unitStance - = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - } - - _index = _index + 1; - - } while (_index < _limit); + } + + // NOTE: the original sets the stance even when the tribe is invalid (tribeID may be 0) + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0 + || enclosed != FALSE) { + DAT_TribesState::instance.tribes[tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + } else { + DAT_TribesState::instance.tribes[tribeID].unitStance + = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + } } - - _ptr = _ptr + 2; - - } while ((int)_ptr < 0xb4277c); - - return; + } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 73f57e341..6c05b1391 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35537,7 +35537,7 @@ SHC_3BB0A8C1_0x004D40B0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D4130 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D4220 | 0.0% | Pending +SHC_3BB0A8C1_0x004D4220 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D4340 | 54.63% | Reimplemented, different register usage From 7898e1c8ad90cb070ae2ceb95d8e112c90c767c5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 20:16:08 +0200 Subject: [PATCH 089/242] reimplement: SHC_3BB0A8C1_0x004CF4F0 57.10% stuck --- .../sendAITribe_0xf_toAttackPatrol.cpp | 31 ++++++++++++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp b/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp index 791472b60..8dd7eaed8 100644 --- a/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp +++ b/src/OpenSHC/AI/AICState/sendAITribe_0xf_toAttackPatrol.cpp @@ -13,19 +13,26 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF4F0 void AICState::sendAITribe_0xf_toAttackPatrol(int playerID) { - int _tribeID; - /* bug: only sends 0xf, while 0xf+1 could also be send if defined by 'AIC: AttUnitPatrolGroupsCount' */ - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) - && (_tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xf], _tribeID != 0)) { - if ((DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xf]) - && (DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID != 0)) { - DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; - MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::sendAttackingPatrolTribeToComputedDestination, - DAT_TroopValueState::ptr)(_tribeID); - return; - } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return; } + + // Bug: only tribe 15 is sent, although tribe 16 can also exist if 'AIC: AttUnitPatrolGroupsCount' is 2 + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[15]; + if (tribeID == 0) { + return; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[15]) { + return; + } + if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) { + return; + } + + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::sendAttackingPatrolTribeToComputedDestination, + DAT_TroopValueState::ptr)(tribeID); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 6c05b1391..943504fa4 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35361,7 +35361,7 @@ SHC_3BB0A8C1_0x004CF400 | 62.22% | Reimplemented functionally, our compiler impr SHC_3BB0A8C1_0x004CF470 | 0.0% | Pending -SHC_3BB0A8C1_0x004CF4F0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CF4F0 | 57.10% | Reimplemented functionally, our compiler improves on original by avoiding recomputations SHC_3BB0A8C1_0x004CF560 | 37.74% | Reimplemented functionally, different register usage From 94f898c77c0781ac72f316a3e895f64d79df9272 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 20:24:18 +0200 Subject: [PATCH 090/242] reimplement: SHC_3BB0A8C1_0x004D1D60 52.50% stuck --- src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 85 ++++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp index 0c9bf7112..535e504ae 100644 --- a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -22,81 +22,74 @@ namespace AI { using OpenSHC::Game::Resources::ResourceType; // FUNCTION: STRONGHOLDCRUSADER 0x004D1D60 - void AICState ::sellExcessGoods(int param_1) + void AICState::sellExcessGoods(int playerID) { - AITypeInt aiType = DAT_GameState::instance.playerDataArray[param_1].aiType; - if (aiType == OpenSHC::AI::AIT_NULL) + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) { return; + } int aicIndex = aiType - 1; - AICSpecification& aic = this->aics[aicIndex]; - int nervousActions = DAT_GameState::instance.playerDataArray[param_1].aiNervousActionsTracker; - int& goldResource = DAT_GameState::instance.playerDataArray[param_1].currentResources[0xf]; - int& popularity = DAT_GameState::instance.playerDataArray[param_1].popularity; - - for (int entryIndex = 0; entryIndex < 20; entryIndex = entryIndex + 1) { - ResourceType resourceType = (OpenSHC::Game::Resources::ResourceType)DAT_SkirmishDefinedData::instance - .AIResourceTradeAICMapping[entryIndex] - .game; - AIResourceTradeCategoryInt category - = DAT_SkirmishDefinedData::instance.AIResourceTradeAICMapping[entryIndex].aic; - int variance = aic.maxResourceVariance; - int& currentResource = DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType]; + int nervousActions = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + for (int i = 0; i < 20; i++) { + ResourceType resourceType + = (ResourceType)DAT_SkirmishDefinedData::instance.AIResourceTradeAICMapping[i].game; + int category = DAT_SkirmishDefinedData::instance.AIResourceTradeAICMapping[i].aic; + int variance = this->aics[aicIndex].maxResourceVariance; int amount; if (category == OpenSHC::AI::Trading::AIRTC_WOOD) { - amount = aic.maxWood; + amount = this->aics[aicIndex].maxWood; } else if (category == OpenSHC::AI::Trading::AIRTC_FOOD) { - amount = aic.maxFood; + amount = this->aics[aicIndex].maxFood; } else if (category == OpenSHC::AI::Trading::AIRTC_STONE) { - amount = aic.maxStone; + amount = this->aics[aicIndex].maxStone; } else if (category == OpenSHC::AI::Trading::AIRTC_WEAPONS) { - amount = aic.maxEquipment; + amount = this->aics[aicIndex].maxEquipment; } else if (category == OpenSHC::AI::Trading::AIRTC_ALE) { - amount = aic.maxBeer; + amount = this->aics[aicIndex].maxBeer; } else { - amount = aic.maxResourceOther; + amount = this->aics[aicIndex].maxResourceOther; } + amount += variance; - amount = amount + variance; - - if ((nervousActions > 0) && (goldResource < 0x1f4)) { - + if (nervousActions > 0 && DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < 500) { + // Nervous and low on gold: keep a quarter of the food and up to 10000 weapons, sell everything else if (category == OpenSHC::AI::Trading::AIRTC_FOOD) { amount = amount / 4; + } else if (category == OpenSHC::AI::Trading::AIRTC_WEAPONS) { + amount = 10000; } else { - amount = ((category != OpenSHC::AI::Trading::AIRTC_WEAPONS) - 1) & 10000; + amount = 0; } variance = 0; - - } else { - if (popularity < aic.criticalPopularity) { - if (category != OpenSHC::AI::Trading::AIRTC_FOOD) { - if (category == OpenSHC::AI::Trading::AIRTC_WEAPONS) { - amount = 0; - } else { - amount = amount / 4; - } + } else if (DAT_GameState::instance.playerDataArray[playerID].popularity + < this->aics[aicIndex].criticalPopularity) { + // Critical popularity: keep all food, sell all weapons, keep a quarter of everything else + if (category != OpenSHC::AI::Trading::AIRTC_FOOD) { + if (category == OpenSHC::AI::Trading::AIRTC_WEAPONS) { + amount = 0; + } else { + amount = amount / 4; } - variance = 0; - } else { - amount = amount - + DAT_GameState::instance.playerDataArray[param_1].resourcesToAcquireArray[resourceType]; } + variance = 0; + } else { + amount += DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType]; } - int* sellResourceList = &aic.sellResource01; - for (int sellResourceIndex = 0; sellResourceIndex < 0xf; sellResourceIndex = sellResourceIndex + 1) { - if (resourceType == sellResourceList[sellResourceIndex]) { + // Resources the AIC always sells are kept at zero + for (int j = 0; j < 15; j++) { + if (resourceType == (&this->aics[aicIndex].sellResource01)[j]) { amount = 0; variance = 0; break; } } - if (currentResource > amount) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellGoods, this)(param_1, resourceType, - (DAT_GameState::instance.playerDataArray[param_1].currentResources[resourceType] - amount) + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType] > amount) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellGoods, this)(playerID, resourceType, + DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType] - amount + variance); return; } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 943504fa4..4c92752f2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35475,7 +35475,7 @@ SHC_3BB0A8C1_0x004D1950 | 0.0% | Pending SHC_3BB0A8C1_0x004D1A00 | 0.0% | Pending -SHC_3BB0A8C1_0x004D1D60 | 0.0% | Pending +SHC_3BB0A8C1_0x004D1D60 | 52.5% | Stuck SHC_3BB0A8C1_0x004D1F00 | 100.0% | Reimplemented, for-loop didn't work From ef96b3511d43398685d4a4435081a6147020a6d5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 20:32:14 +0200 Subject: [PATCH 091/242] reimplement: SHC_3BB0A8C1_0x004CDCA0 100.0% --- ...andomBuildingIDFromListOfBuildingTypes.cpp | 23 ++++--------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp b/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp index 4e739aafc..c5845f0bb 100644 --- a/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp +++ b/src/OpenSHC/AI/AICState/selectRandomBuildingIDFromListOfBuildingTypes.cpp @@ -8,30 +8,17 @@ namespace OpenSHC { namespace AI { - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CDCA0 - int AICState ::selectRandomBuildingIDFromListOfBuildingTypes(int playerID, undefined4 param_2) - + int AICState::selectRandomBuildingIDFromListOfBuildingTypes(int playerID, undefined4 param_2) { - - int iVar1; - - int iVar2; - - iVar1 = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; - - if (iVar1 < 1) { - + int count = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + if (count <= 0) { return 0; } - iVar2 = (int)SEC_RNG::instance.currentNumber2; - + int index = SEC_RNG::instance.currentNumber2 % count; MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - - return (int)DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings[iVar2 % iVar1]; + return DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings[index]; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4c92752f2..0e89603de 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35291,7 +35291,7 @@ SHC_3BB0A8C1_0x004CDB20 | 0.0% | Pending SHC_3BB0A8C1_0x004CDBC0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CDCA0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CDCA0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CDCF0 | 0.0% | Pending From 63c5f111447a677754b0f9b0c1717a52c3822e00 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 20:34:01 +0200 Subject: [PATCH 092/242] reimplement: SHC_3BB0A8C1_0x004CDAB0 100% --- ...selectBuildingFromAListOfBuildingTypes.cpp | 74 +++++-------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 18 insertions(+), 58 deletions(-) diff --git a/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp index 7c7b2af63..11008c453 100644 --- a/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp +++ b/src/OpenSHC/AI/AICState/selectBuildingFromAListOfBuildingTypes.cpp @@ -7,68 +7,28 @@ namespace OpenSHC { namespace AI { - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CDAB0 - int AICState ::selectBuildingFromAListOfBuildingTypes(int playerID) - + int AICState::selectBuildingFromAListOfBuildingTypes(int playerID) { - - int _selectedBuildingID; - - int _loopCounter; - - int _loopLimit; - - short* psVar1; - - int _arraySize; - - int _buildingID; - - _arraySize = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; - - _selectedBuildingID = 0; - - _loopLimit = 0x2e; - - if (0 < _arraySize) { - - psVar1 = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings; - - do { - - _buildingID = (int)*psVar1; - - if ((_buildingID != 0) && (_loopCounter = 0, 0 < _loopLimit)) { - - do { - - if ((int)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType - == DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1[_loopCounter]) { - - /* - fancy break statement? */ - - _selectedBuildingID = _buildingID; - - _loopLimit = _loopCounter; - } - - _loopCounter = _loopCounter + 1; - - } while (_loopCounter < _loopLimit); + // Pick the targetable building whose type comes first in BuildingTargetPrioritySet1 + int selectedBuildingID = 0; + int bestPriority = 46; + for (int i = 0; i < DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; i++) { + int buildingID = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings[i]; + if (buildingID == 0) { + continue; + } + for (int j = 0; j < bestPriority; j++) { + if ((short)DAT_BuildingsState::instance.buildings[buildingID].buildingType + == DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1[j]) { + // Found a better match; lowering the bound also ends this loop + bestPriority = j; + selectedBuildingID = buildingID; } - - psVar1 = psVar1 + 1; - - _arraySize = _arraySize + -1; - - } while (_arraySize != 0); + } } - return _selectedBuildingID; + return selectedBuildingID; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 0e89603de..1fecaecaf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35285,7 +35285,7 @@ SHC_3BB0A8C1_0x004CD8F0 | 0.0% | Pending SHC_3BB0A8C1_0x004CDA50 | 0.0% | Pending -SHC_3BB0A8C1_0x004CDAB0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CDAB0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CDB20 | 0.0% | Pending From 482fa2cd20b31f078dc33f8750ad10abc905d90e Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 20:44:23 +0200 Subject: [PATCH 093/242] reimplement: SHC_3BB0A8C1_0x004D4680 64.80% --- .../AI/AICState/selectAttackTarget.cpp | 213 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 103 insertions(+), 112 deletions(-) diff --git a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp index 028cbb77a..4dd36397c 100644 --- a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp +++ b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp @@ -23,130 +23,121 @@ namespace AI { using OpenSHC::Game::Player::PlayerData; // FUNCTION: STRONGHOLDCRUSADER 0x004D4680 - void AICState ::selectAttackTarget(int playerID) + void AICState::selectAttackTarget(int playerID) { - AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - int _selectedPlayer = 0; - - if (_aiType != OpenSHC::AI::AIT_NULL) { - int fromXPosition = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; - int fromYPosition = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; - int _lowestDistance = 10000; - int _highestGold = 0; - int _lowestPoints = 1000000; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeNervousness, this)(playerID); - - int _reqState = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; - if (((_reqState == 2) || (_reqState == 1)) - && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) - == 0) { - DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; - } + int selectedPlayerID = 0; + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) { + return; + } - int _reqState2 = DAT_GameState::instance.playerDataArray[playerID].requestStateUnk; - if (_reqState2 == 2) { - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = 0; + int aicIndex = aiType - 1; + int fromX = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; + int fromY = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; + int lowestDistance = 10000; + int highestGold = 0; + int lowestPoints = 1000000; + + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::computeNervousness, this)(playerID); + + // Drop a pending request if the asking player's lord is dead + if ((DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2 + || DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 1) + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) + == 0) { + DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; + } + + if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2) { + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = 0; + return; + } + if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 1) { + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk) + != 0) { + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID + = DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk; return; } - if (_reqState2 == 1) { - if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( - DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk) - != 0) { - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID - = DAT_GameState::instance.playerDataArray[playerID].requestedAttackTargetUnk; - return; - } - DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; + DAT_GameState::instance.playerDataArray[playerID].requestStateUnk = 0; + } + + for (int i = 1; i < 9; i++) { + if (DAT_GameState::instance.mapAndTime.playerTeams[i] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + continue; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i) + == 0) { + continue; } - PlayerData* _pPlayerData2 = (PlayerData*)(&DAT_GameState::instance.playerDataArray[1]); - int _iPlayer = 1; - - do { - if ((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] - != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) - && MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_iPlayer) - != 0) { - - MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, - DAT_DirectionAlgorithmState::ptr)((_pPlayerData2->campground).xEntry, - (_pPlayerData2->campground).yEntry, fromXPosition, fromYPosition); - - AITargetChoiceInt _targetChoiceType = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].TargetChoice; - int _currentGoldValue = _highestGold; - int _points = _lowestPoints; - - if (_targetChoiceType == OpenSHC::AI::AIC::AITC_PLAYER) { - if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_iPlayer] != -1) { - if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance) { - _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; - _lowestPoints = _points; - _highestGold = _currentGoldValue; - _selectedPlayer = _iPlayer; - } - } - } else if (_targetChoiceType == OpenSHC::AI::AIC::AITC_CLOSEST) { - if (DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance) { - _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; - _lowestPoints = _points; - _highestGold = _currentGoldValue; - _selectedPlayer = _iPlayer; - } - } else if (_targetChoiceType == OpenSHC::AI::AIC::AITC_GOLD) { - _currentGoldValue = _pPlayerData2->currentResources[0xf]; - if (_highestGold <= _pPlayerData2->currentResources[0xf]) { - _lowestPoints = _points; - _highestGold = _currentGoldValue; - _selectedPlayer = _iPlayer; - } - } else if (_targetChoiceType == OpenSHC::AI::AIC::AITC_BALANCED) { - _points = _pPlayerData2->currentPopulation * 5 + _pPlayerData2->totalTroopValue - + _pPlayerData2->currentResources[0xf] / 100 - + DAT_DirectionAlgorithmState::instance.distanceHigh * 2; - if (_points <= _lowestPoints) { - _lowestPoints = _points; - _highestGold = _currentGoldValue; - _selectedPlayer = _iPlayer; - } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(DAT_GameState::instance.playerDataArray[i].campground.xEntry, + DAT_GameState::instance.playerDataArray[i].campground.yEntry, fromX, fromY); + + int targetChoice = this->aics[aicIndex].TargetChoice; + if (targetChoice == OpenSHC::AI::AIC::AITC_PLAYER) { + // Closest human player + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[i] != -1) { + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= lowestDistance) { + lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + selectedPlayerID = i; } } + } else if (targetChoice == OpenSHC::AI::AIC::AITC_CLOSEST) { + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= lowestDistance) { + lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + selectedPlayerID = i; + } + } else if (targetChoice == OpenSHC::AI::AIC::AITC_GOLD) { + if (DAT_GameState::instance.playerDataArray[i].currentResources[0xf] >= highestGold) { + highestGold = DAT_GameState::instance.playerDataArray[i].currentResources[0xf]; + selectedPlayerID = i; + } + } else if (targetChoice == OpenSHC::AI::AIC::AITC_BALANCED) { + int points = DAT_GameState::instance.playerDataArray[i].currentPopulation * 5 + + DAT_GameState::instance.playerDataArray[i].totalTroopValue + + DAT_GameState::instance.playerDataArray[i].currentResources[0xf] / 100 + + DAT_DirectionAlgorithmState::instance.distanceHigh * 2; + if (points <= lowestPoints) { + lowestPoints = points; + selectedPlayerID = i; + } + } + } - _iPlayer = _iPlayer + 1; - _pPlayerData2 = _pPlayerData2 + 0xe7d; - } while (_iPlayer < 9); - - if (_selectedPlayer == 0) { - int _iPlayer2 = 1; - PlayerData* _ptrPlayerData = &DAT_GameState::instance.playerDataArray[1]; - do { - if (((DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer2] - != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) - && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_iPlayer2) - != 0) - && (MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, - DAT_DirectionAlgorithmState::ptr)((_ptrPlayerData->campground).xEntry, - (_ptrPlayerData->campground).yEntry, fromXPosition, fromYPosition), - DAT_DirectionAlgorithmState::instance.distanceHigh <= _lowestDistance)) { - _lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; - _selectedPlayer = _iPlayer2; - } - _iPlayer2 = _iPlayer2 + 1; - _ptrPlayerData = _ptrPlayerData + 0xe7d; - } while (_iPlayer2 < 9); + // Fall back to the closest enemy + if (selectedPlayerID == 0) { + for (int i = 1; i < 9; i++) { + if (DAT_GameState::instance.mapAndTime.playerTeams[i] + == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + continue; + } + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i) + == 0) { + continue; + } - if (_selectedPlayer == 0) - return; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(DAT_GameState::instance.playerDataArray[i].campground.xEntry, + DAT_GameState::instance.playerDataArray[i].campground.yEntry, fromX, fromY); + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= lowestDistance) { + lowestDistance = DAT_DirectionAlgorithmState::instance.distanceHigh; + selectedPlayerID = i; + } } - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk = _selectedPlayer; - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = _selectedPlayer; + if (selectedPlayerID == 0) { + return; + } } + + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk = selectedPlayerID; + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID = selectedPlayerID; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1fecaecaf..59ee1d6a9 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35551,7 +35551,7 @@ SHC_3BB0A8C1_0x004D45E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D4630 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D4680 | 0.0% | Pending +SHC_3BB0A8C1_0x004D4680 | 64.80% | Stuck, register usage SHC_3BB0A8C1_0x004D4870 | 0.0% | Pending From ebcf32e626a7ce2fd53c7c8876b77c92ac3df83c Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 20:48:43 +0200 Subject: [PATCH 094/242] reimplement: SHC_3BB0A8C1_0x004D1F00 100% --- src/OpenSHC/AI/AICState/requestGoods.cpp | 93 ++++++++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/OpenSHC/AI/AICState/requestGoods.cpp b/src/OpenSHC/AI/AICState/requestGoods.cpp index 551db559f..2c10772ed 100644 --- a/src/OpenSHC/AI/AICState/requestGoods.cpp +++ b/src/OpenSHC/AI/AICState/requestGoods.cpp @@ -15,56 +15,55 @@ namespace AI { using OpenSHC::Game::Resources::ResourceType; // FUNCTION: STRONGHOLDCRUSADER 0x004D1F00 - void AICState ::requestGoods(int playerID, ResourceType resourceType, int amount) - + void AICState::requestGoods(int playerID, ResourceType resourceType, int amount) { - - if ((((((DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) - && (DAT_GameState::instance.playerDataArray[playerID].aiRequestDelay == 0)) - && (resourceType != OpenSHC::Game::Resources::RT_WHEAT)) - && ((resourceType != OpenSHC::Game::Resources::RT_HOPS - && (resourceType != OpenSHC::Game::Resources::RT_ALE)))) - && ((((resourceType != OpenSHC::Game::Resources::RT_BREAD - && ((resourceType != OpenSHC::Game::Resources::RT_CHEESE - && (resourceType != OpenSHC::Game::Resources::RT_MEAT)))) - && (resourceType != OpenSHC::Game::Resources::RT_APPLE)) - || (DAT_GameState::instance.playerDataArray[playerID].totalFood < 5)))) - && (((((resourceType != OpenSHC::Game::Resources::RT_BREAD - && (resourceType != OpenSHC::Game::Resources::RT_CHEESE)) - && (resourceType != OpenSHC::Game::Resources::RT_MEAT)) - && (resourceType != OpenSHC::Game::Resources::RT_APPLE)) - || (DAT_GameState::instance.playerDataArray[playerID].totalFood < 5)))) { - - int iVar1; - int _playerID = 1; - - short* psVar2 = DAT_GameState::instance.playerDataArray[1].requestedGoodsArray1Unk + playerID; - - do { - - if (((DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_playerID] != -1) - && (DAT_GameState::instance.mapAndTime.playerTeams[_playerID] - == DAT_GameState::instance.mapAndTime.playerTeams[playerID])) - && ((iVar1 = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(_playerID), - iVar1 != 0 && (*psVar2 == 0)))) { - - *psVar2 = (short)resourceType; - - psVar2[10] = (short)amount; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playGoodsRequestBikFromPlayerToPlayer, this)( - playerID, _playerID); - } - - _playerID = _playerID + 1; - - psVar2 = psVar2 + 0x1cfa; - - } while (_playerID < 9); + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) { + return; + } + if (DAT_GameState::instance.playerDataArray[playerID].aiRequestDelay != 0) { + return; + } + // Never request raw farm goods or ale + if (resourceType == OpenSHC::Game::Resources::RT_WHEAT || resourceType == OpenSHC::Game::Resources::RT_HOPS + || resourceType == OpenSHC::Game::Resources::RT_ALE) { + return; + } + // Only request food when almost out of it + if ((resourceType == OpenSHC::Game::Resources::RT_BREAD || resourceType == OpenSHC::Game::Resources::RT_CHEESE + || resourceType == OpenSHC::Game::Resources::RT_MEAT + || resourceType == OpenSHC::Game::Resources::RT_APPLE) + && DAT_GameState::instance.playerDataArray[playerID].totalFood >= 5) { + return; + } + // fixme: NOTE: the original performs the exact same food check a second time, it cannot be removed + if ((resourceType == OpenSHC::Game::Resources::RT_BREAD || resourceType == OpenSHC::Game::Resources::RT_CHEESE + || resourceType == OpenSHC::Game::Resources::RT_MEAT + || resourceType == OpenSHC::Game::Resources::RT_APPLE) + && DAT_GameState::instance.playerDataArray[playerID].totalFood >= 5) { + return; } - return; + // Ask every human teammate that has no pending request from this player + for (int i = 1; i < 9; i++) { + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[i] == -1) { + continue; + } + if (DAT_GameState::instance.mapAndTime.playerTeams[i] + != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { + continue; + } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i) + == 0) { + continue; + } + if (DAT_GameState::instance.playerDataArray[i].requestedGoodsArray1Unk[playerID] != 0) { + continue; + } + + DAT_GameState::instance.playerDataArray[i].requestedGoodsArray1Unk[playerID] = resourceType; + DAT_GameState::instance.playerDataArray[i].requestedGoodsArray2Unk[playerID] = amount; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playGoodsRequestBikFromPlayerToPlayer, this)(playerID, i); + } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 59ee1d6a9..63d52f0c4 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35477,7 +35477,7 @@ SHC_3BB0A8C1_0x004D1A00 | 0.0% | Pending SHC_3BB0A8C1_0x004D1D60 | 52.5% | Stuck -SHC_3BB0A8C1_0x004D1F00 | 100.0% | Reimplemented, for-loop didn't work +SHC_3BB0A8C1_0x004D1F00 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D2000 | 0.0% | Pending From e068437b2fcd910ecc0906377b7c8e3a18455f69 Mon Sep 17 00:00:00 2001 From: Gynt Date: Mon, 21 Sep 2026 20:59:21 +0200 Subject: [PATCH 095/242] reimplement: SHC_3BB0A8C1_0x004D1320 69.88% stuck --- .../AI/AICState/renderDebugDataAiInfo.cpp | 309 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 103 insertions(+), 208 deletions(-) diff --git a/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp index 73b22b94a..949062c85 100644 --- a/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp +++ b/src/OpenSHC/AI/AICState/renderDebugDataAiInfo.cpp @@ -16,7 +16,6 @@ #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" #include "OpenSHC/Globals/DAT_RenderingDefinedData.hpp" #include "OpenSHC/Globals/DAT_TextManagerObject.hpp" -#include "OpenSHC/Globals/MSVC_SecurityCookie.hpp" namespace OpenSHC { namespace AI { @@ -29,220 +28,116 @@ namespace AI { using OpenSHC::Text::TextAlignment; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - 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 0x004D1320 - void AICState ::renderDebugDataAiInfo(int x, int y, int width, int height) - + void AICState::renderDebugDataAiInfo(int x, int y, int width, int height) { + char text[1000]; - uint foregroundColor; - - int iVar1; - - PlayerData* _playerData; - - int yParam; - - char* pcVar2; - - uint foregroundColor_00; - - char (*pPlayerNames)[250]; - - int _aiTypeMin1; - - AICSpecification* local_3f4; - - AICState* local_3f0; - - char local_3ec[1000]; - - uint local_4; - - int _playerID; - - local_4 = MSVC_SecurityCookie::instance ^ (uint)&_playerID; - - local_3f0 = this; - - _playerID = 1; - - _playerData = &DAT_GameState::instance.playerDataArray[1]; - - pPlayerNames = DAT_GameSynchronyState::instance.DAT_PlayerNames + 1; - - do { - - yParam = y + 0x18; - - if (((_playerData->playerDeathRelated == 0) && (_playerData->lordKilledByPlayerID == 0)) - && ((_playerData->aiType != OpenSHC::AI::AIT_NULL - || (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_playerID] != -1)))) { - - /* - aiType - 1 */ - - _aiTypeMin1 = _playerData->aiType + ~OpenSHC::AI::AIT_NULL; - - foregroundColor - = DAT_RenderingDefinedData::instance - .DAT_ColorArray[DAT_BlendingDefinedData::instance.SEC_PlayerSlotUnitColor[_playerID]]; - - MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( - _playerID, x + 6, yParam, OpenSHC::Text::TTA_LEFT, 0xc2f0eb, 0x12, FALSE, 0); - - MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( - "-", x + 0x10, yParam, OpenSHC::Text::TTA_LEFT, 0xc2f0eb, 0x12, FALSE, 0); - - MACRO_CALL_MEMBER( - OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( - *pPlayerNames, x + 0x1a, y + 0x19, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); - - if (_playerData->aiStrengthFeeling == OpenSHC::AI::AIST_WEAK) { - - pcVar2 = "Weak"; - - } - - else if (_playerData->aiStrengthFeeling == OpenSHC::AI::AIST_DEFAULT) { - - pcVar2 = "Normal"; - - } - - else { - - pcVar2 = "Strong"; - } - - MACRO_CALL_MEMBER( - OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( - pcVar2, x + 0xca, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); - - MACRO_CALL_MEMBER( - OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( - "P:", x + 0x106, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); - - MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumber2, DAT_TextManagerObject::ptr)( - _playerData->aivCurrentPause, x + 0x108, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, - TRUE, 0); - - MACRO_CALL(OpenSHC::OS_Func::_sprintf)( - local_3ec, "Atk:%d W:%d", _playerData->attackedPlayerID, _playerData->aiAttackCoordinationLevel); - - MACRO_CALL_MEMBER( - OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( - local_3ec, x + 0x12e, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); - - if (_playerData->aiType == OpenSHC::AI::AIT_NULL) { - - iVar1 = DAT_AIVState::instance.aivs[_playerData->aivID].castleID; - - pcVar2 = "AIV:n/a"; - - } - - else { - - iVar1 = DAT_AIVState::instance.aivs[_playerData->aivID].castleID; - - pcVar2 = "AIV: %d"; - } - - MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, (char const*)((int)(pcVar2)), iVar1 + 1); - - MACRO_CALL_MEMBER( - OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( - local_3ec, x + 0x17e, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); - - local_3f4 = local_3f0->aics + _aiTypeMin1; - - /* - total engineers? */ - - MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, "E:%d/%d", _playerData->totalTroopsType6, - _playerData->unknownCounter_01 + local_3f0->aics[_aiTypeMin1].SortieUnitRangedMin); - - MACRO_CALL_MEMBER( - OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( - local_3ec, x + 0x1c4, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); - - /* - total attack troops - engineer troops */ - - iVar1 = _playerData->totalAttackTroops - _playerData->totalAttackingEngineerTroops; - - /* - ai player state == attacking */ - - if (_playerData->aiPlayerState == 0) { - - /* - AttForceBase + currentWaveRandomAttackingStrength */ - - MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, "Sg:%d/%d", iVar1, - _playerData->currentWaveRandomAttackingStrength + local_3f4->AttForceBase); - - foregroundColor_00 = foregroundColor; - - } - - else { - - MACRO_CALL(OpenSHC::OS_Func::_sprintf)(local_3ec, "%d/%d", iVar1, _playerData->attackTicker); - - foregroundColor_00 = 0xffffff; - } - - MACRO_CALL_MEMBER( - OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( - local_3ec, x + 0x200, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor_00, 0, 0x12, FALSE, 0); - - iVar1 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, local_3f0)( - _aiTypeMin1, _playerID); - - MACRO_CALL(OpenSHC::OS_Func::_sprintf)( - local_3ec, "Hr:%d/%d", _playerData->totalRaidingTroopsUnk, iVar1); - - /* - display raid/harassing units */ - - MACRO_CALL_MEMBER( - OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( - local_3ec, x + 0x250, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + // One row of 24 pixels per player, starting one row below y + y += 24; + for (int playerID = 1; playerID <= 8; playerID++, y += 24) { + if (DAT_GameState::instance.playerDataArray[playerID].playerDeathRelated != 0) { + continue; + } + if (DAT_GameState::instance.playerDataArray[playerID].lordKilledByPlayerID != 0) { + continue; + } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL + && DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] == -1) { + continue; + } - /* - TotalDefensiveTroops / DefWalls */ + int aicIndex = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + uint color = DAT_RenderingDefinedData::instance + .ColorArray[DAT_BlendingDefinedData::instance.PlayerSlotUnitColor[playerID]]; + + // Player number and name + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumberToScreen2, DAT_TextManagerObject::ptr)( + playerID, x + 6, y, OpenSHC::Text::TTA_LEFT, 0xc2f0eb, 18, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderTextToScreen, DAT_TextManagerObject::ptr)( + "-", x + 16, y, OpenSHC::Text::TTA_LEFT, 0xc2f0eb, 18, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + DAT_GameSynchronyState::instance.DAT_PlayerNames[playerID], x + 26, y + 1, OpenSHC::Text::TTA_LEFT, + color, 0, 18, FALSE, 0); + + // Strength feeling + if (DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling == OpenSHC::AI::AIST_WEAK) { + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, + DAT_TextManagerObject::ptr)("Weak", x + 202, y, OpenSHC::Text::TTA_LEFT, color, 0, 18, FALSE, 0); + } else if (DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + == OpenSHC::AI::AIST_DEFAULT) { + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, + DAT_TextManagerObject::ptr)("Normal", x + 202, y, OpenSHC::Text::TTA_LEFT, color, 0, 18, FALSE, 0); + } else { + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, + DAT_TextManagerObject::ptr)("Strong", x + 202, y, OpenSHC::Text::TTA_LEFT, color, 0, 18, FALSE, 0); + } + // Current AIV pause + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + "P:", x + 262, y, OpenSHC::Text::TTA_LEFT, color, 0, 18, FALSE, 0); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderNumber2, DAT_TextManagerObject::ptr)( + DAT_GameState::instance.playerDataArray[playerID].aivCurrentPause, x + 264, y, OpenSHC::Text::TTA_LEFT, + color, 0, 18, TRUE, 0); + + // Attack target and coordination level + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(text, "Atk:%d W:%d", + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, + DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + text, x + 302, y, OpenSHC::Text::TTA_LEFT, color, 0, 18, FALSE, 0); + + // fixme: Castle (AIV); the castle ID is passed even for human players, whose format ignores it + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) { + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(text, "AIV:n/a", + DAT_AIVState::instance.aivs[DAT_GameState::instance.playerDataArray[playerID].aivID].castleID + 1); + } else { + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(text, "AIV: %d", + DAT_AIVState::instance.aivs[DAT_GameState::instance.playerDataArray[playerID].aivID].castleID + 1); + } + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + text, x + 382, y, OpenSHC::Text::TTA_LEFT, color, 0, 18, FALSE, 0); + + // Engineers + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(text, "E:%d/%d", + DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6, + DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 + + this->aics[aicIndex].SortieUnitRangedMin); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + text, x + 452, y, OpenSHC::Text::TTA_LEFT, color, 0, 18, FALSE, 0); + + // Siege troops (attack troops without engineers): attack ticker in white when not attacking, + // otherwise the attack force target + int siegeTroops = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops; + if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState != 0) { MACRO_CALL(OpenSHC::OS_Func::_sprintf)( - local_3ec, "Df:%d/%d", _playerData->totalDefensiveTroopsUnk, local_3f4->DefWalls); - - MACRO_CALL_MEMBER( - OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( - local_3ec, x + 0x291, yParam, OpenSHC::Text::TTA_LEFT, foregroundColor, 0, 0x12, FALSE, 0); + text, "%d/%d", siegeTroops, DAT_GameState::instance.playerDataArray[playerID].attackTicker); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, + DAT_TextManagerObject::ptr)(text, x + 512, y, OpenSHC::Text::TTA_LEFT, 0xffffff, 0, 18, FALSE, 0); + } else { + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(text, "Sg:%d/%d", siegeTroops, + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength + + this->aics[aicIndex].AttForceBase); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, + DAT_TextManagerObject::ptr)(text, x + 512, y, OpenSHC::Text::TTA_LEFT, color, 0, 18, FALSE, 0); } - pPlayerNames = pPlayerNames + 1; - - _playerID = _playerID + 1; - - _playerData = _playerData + 0xe7d; - - y = yParam; - - } while (_playerID < 9); - - ; - - return; + // Raiding/harassing troops + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(text, "Hr:%d/%d", + DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk, + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( + aicIndex, playerID)); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + text, x + 592, y, OpenSHC::Text::TTA_LEFT, color, 0, 18, FALSE, 0); + + // Defensive troops + MACRO_CALL(OpenSHC::OS_Func::_sprintf)(text, "Df:%d/%d", + DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk, + this->aics[aicIndex].DefWalls); + MACRO_CALL_MEMBER(OpenSHC::Text::TextManager_Func::renderInGameTextWithShadow, DAT_TextManagerObject::ptr)( + text, x + 657, y, OpenSHC::Text::TTA_LEFT, color, 0, 18, FALSE, 0); + } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 63d52f0c4..cbb503393 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35463,7 +35463,7 @@ SHC_3BB0A8C1_0x004D11C0 | 0.0% | Pending SHC_3BB0A8C1_0x004D12A0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D1320 | 0.0% | Pending +SHC_3BB0A8C1_0x004D1320 | 69.88% | Partially reimplemented, stuck SHC_3BB0A8C1_0x004D1700 | 0.0% | Pending From d984845bb2fd50a6db027308c28af1bb54c06349 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 08:33:00 +0200 Subject: [PATCH 096/242] reimplement: SHC_3BB0A8C1_0x004CE430 100% --- ...oveOrganismsAndSetMoveDestinationPairs.cpp | 48 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 15 insertions(+), 35 deletions(-) diff --git a/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp b/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp index 39859650f..4736730bd 100644 --- a/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp +++ b/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp @@ -20,47 +20,27 @@ namespace AI { using OpenSHC::AI::AITypeInt; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CE430 - void AICState ::removeOrganismsAndSetMoveDestinationPairs(int playerID) - + void AICState::removeOrganismsAndSetMoveDestinationPairs(int playerID) { - - AITypeInt _aiType; - - if ((short)DAT_TileMapState::instance.OrganismLayer - [DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] - .addXgetTile - + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX] - != 0) { - - MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)( - (int)(short)DAT_TileMapState::instance.OrganismLayer - [DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] - .addXgetTile - + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]); + // Clear a tree standing on the target tile + int organismID = (short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]; + if (organismID != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)(organismID); } - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - /* - bug: special hardcoded exception for AI type 8 */ - + // Hardcoded exception: the Sultan keeps a smaller distance than all other AIs + int extraDistance = DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_SULTAN ? 8 : 20; MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, - (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY)), -1, -1, 10000, FALSE); - + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, -1, -1, 10000, FALSE); MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::setMoveDestinationPairs, - DAT_PathFindingState::ptr)(playerID + -1, - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, - (int)((int)(*(int*)(DAT_TroopValueState::instance.attackInfo.scaleValuesArray + playerID * 0x177bc + -0x1c) - + (-(uint)(_aiType != OpenSHC::AI::AIT_SULTAN) & 0xc) + 8))); - - return; + DAT_PathFindingState::ptr)(playerID - 1, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, + DAT_TroopValueState::instance.attackInfo.playerInfo[playerID - 1].someMinimumDistance + extraDistance); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index cbb503393..0e40853b5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35313,7 +35313,7 @@ SHC_3BB0A8C1_0x004CE270 | 0.0% | Pending SHC_3BB0A8C1_0x004CE3B0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CE430 | 0.0% | Pending +SHC_3BB0A8C1_0x004CE430 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE4D0 | 0.0% | Pending From 519d47cbfe8fb22569623219a9183e8fbc31e41f Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 08:44:30 +0200 Subject: [PATCH 097/242] reimplement: SHC_3BB0A8C1_0x004CD2A0 59.60% block ordering problem --- .../recruitHarrassingSiegeEngines.cpp | 298 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 104 insertions(+), 196 deletions(-) diff --git a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp index ec093746a..f58644824 100644 --- a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp +++ b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp @@ -4,8 +4,10 @@ #include "OpenSHC/Map/TileMapState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" +#include "OpenSHC/AI/AIUnitBehaviourType.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" #include "OpenSHC/Commands/MappersEnum.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/Unit.hpp" @@ -34,220 +36,126 @@ namespace AI { using OpenSHC::Map::Units::UnitType; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CD2A0 - void AICState ::recruitHarrassingSiegeEngines(int playerID) - + void AICState::recruitHarrassingSiegeEngines(int playerID) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + int engineersGuild = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; - uint _unitID; - - int iVar1; - - Unit* pUVar4; - - int _unit; - - int _tribeID; - - int _harrassingSiegeEnginesMax; - - int _recruitTimeoutValue; - - int _engineersGuild; - - int _aiType; - - int _tribeUID; - - int _buildingID; - - int _aicEnginesArrayIndex; - - MappersEnum _siegeEngineToBuild; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - _engineersGuild = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; - - if ((_aiType != 0) && (499 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf])) { - - _harrassingSiegeEnginesMax = *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x1ec); - - if (0 < _harrassingSiegeEnginesMax) { - - _recruitTimeoutValue = DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout; - - if (_recruitTimeoutValue != 0) { - - DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout - = _recruitTimeoutValue + -1; - - return; - } - - if ((DAT_GameState::instance.playerDataArray[playerID].harassingSiegeEnginesCountUnk - < _harrassingSiegeEnginesMax) - && (DAT_GameState::instance.playerDataArray[playerID].unknownHarrassingSiegeRelated < 0x14)) { - - _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa5]; - - if ((_tribeID == 0) - || ((DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa5] - || (DAT_TribesState::instance.tribes[_tribeID].size < 2)))) { - - if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) { - - return; - } - - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < 30) { - - return; - } - - if (_engineersGuild < 1) { - - return; - } - - if (DAT_BuildingsState::instance.buildings[_engineersGuild].buildingType - != OpenSHC::Map::Buildings::BT_ENGINEERSGUILD) { - - return; - } - - _unitID = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( - OpenSHC::Map::Units::UT_E_ENGINEER, (undefined4)((int)(_engineersGuild)), playerID, 0); - - if (_unitID == 0) { - - return; - } - - if ((_tribeID == 0) - || (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa5])) { - - _tribeID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, - DAT_TribesState::ptr)(playerID); - } - - _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; - - DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa5] = (short)_tribeID; - - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa5] = _tribeUID; - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( - _unitID, _tribeID); - - DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType = 0x16; - - } - - else { - - if (7 < DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex) { - - DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = 0; - } - - iVar1 = (_aiType + -1) * 0xa9; - - if (*(int*)((int)this - + (DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex - + iVar1) - * 4 - + 0x1cc) - == 0) { - - DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = 0; - } - - _aicEnginesArrayIndex - = DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex; - - _siegeEngineToBuild = *(MappersEnum*)((int)this + (iVar1 + _aicEnginesArrayIndex) * 4 + 0x1cc); - - DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex - = _aicEnginesArrayIndex + 1; - - iVar1 = MACRO_CALL_MEMBER( - OpenSHC::AI::AIVState_Func::findSpotNearEngineersGuild, DAT_AIVState::ptr)(playerID); - - if (iVar1 == 0) { - - return; - } - - iVar1 = DAT_AIVState::instance.buildingAppropriateGridYPosition * 5; - - _aicEnginesArrayIndex = DAT_AIVState::instance.buildingAppropriateGridYPosition * 5; - - DAT_TribesState::instance.tribes[_tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; - - DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType - = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - - /* - palce siege engine tent? */ - - MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)( - playerID, _aicEnginesArrayIndex, iVar1, _siegeEngineToBuild, 3, 0xf); - - _buildingID = DAT_TileMapState::instance.placedBuildingID; - - if (DAT_TileMapState::instance.buildingPlacementFail != FALSE) { - - return; - } + if (aiType == 0) { + return; + } + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[OpenSHC::Game::Resources::RT_GOLD] < 500) { + return; + } - DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.placedBuildingID].attackWave - = 0; + int aicIndex = aiType - 1; + int harrassingSiegeEnginesMax = this->aics[aicIndex].HarassingSiegeEnginesMax; + if (harrassingSiegeEnginesMax <= 0) { + return; + } - DAT_BuildingsState::instance.buildings[_buildingID].unknownSiegeTentRelated01 = 2; + if (DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout != 0) { + DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout -= 1; + return; + } - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, - DAT_TribesState::ptr)(_tribeID, - OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _buildingID, - DAT_BuildingsState::instance.buildings[_buildingID].uid, 0); - } + if (DAT_GameState::instance.playerDataArray[playerID].harassingSiegeEnginesCountUnk + >= harrassingSiegeEnginesMax) { + return; + } + if (DAT_GameState::instance.playerDataArray[playerID].unknownHarrassingSiegeRelated >= 20) { + return; + } - _unit = 1; + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[165]; + if (tribeID == 0 + || DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[165] + || DAT_TribesState::instance.tribes[tribeID].size < 2) { + // Not enough engineers yet: recruit one at the engineers guild + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0 + || DAT_GameState::instance.playerDataArray[playerID].currentResources[OpenSHC::Game::Resources::RT_GOLD] + < 30 + || engineersGuild <= 0 + || DAT_BuildingsState::instance.buildings[engineersGuild].buildingType + != OpenSHC::Map::Buildings::BT_ENGINEERSGUILD) { + return; + } - if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { + uint unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + OpenSHC::Map::Units::UT_E_ENGINEER, engineersGuild, playerID, 0); + if (unitID == 0) { + return; + } - pUVar4 = &DAT_UnitsState::instance.units[1]; + if (tribeID == 0 + || DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[165]) { + tribeID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + } - do { + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[165] = (short)tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[165] + = DAT_TribesState::instance.tribes[tribeID].uid; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, tribeID); + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = OpenSHC::AI::AIUBT_HARASS_SIEGE; + } + else { + // Enough engineers: pick the next siege engine from the AIC list and place its tent + if (DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex >= 8) { + DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = 0; + } + if ((&this->aics[aicIndex].HarassingSiegeEngine1) + [DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex] + == 0) { + DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = 0; + } - if ((((pUVar4->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) && (pUVar4->dying == 0)) - && ((pUVar4->unitType == OpenSHC::Map::Units::UT_S_CATAPULT - || (pUVar4->unitType == OpenSHC::Map::Units::UT_S_FBALLISTA)))) - && (pUVar4->aiUnitBehaviourType == 0x15)) { + int engineIndex = DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex; + MappersEnum siegeEngineToBuild = (MappersEnum)(&this->aics[aicIndex].HarassingSiegeEngine1)[engineIndex]; + DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = engineIndex + 1; - pUVar4->siegeTargetPlayerID - = (short)DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; - } + if (MACRO_CALL_MEMBER(OpenSHC::AI::AIVState_Func::findSpotNearEngineersGuild, DAT_AIVState::ptr)(playerID) + == 0) { + return; + } - _unit = _unit + 1; + DAT_TribesState::instance.tribes[tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - pUVar4 = pUVar4 + 0x248; + // Place the siege tent + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID, + DAT_AIVState::instance.buildingApproriateGridXPosition * 5, + DAT_AIVState::instance.buildingAppropriateGridYPosition * 5, siegeEngineToBuild, 3, 15); + if (DAT_TileMapState::instance.buildingPlacementFail != FALSE) { + return; + } - } while (_unit < (int)DAT_UnitsState::instance.maxUnitCount); - } + int buildingID = DAT_TileMapState::instance.placedBuildingID; + DAT_BuildingsState::instance.buildings[buildingID].attackWave = 0; + DAT_BuildingsState::instance.buildings[buildingID].unknownSiegeTentRelated01 = 2; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( + tribeID, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, buildingID, + DAT_BuildingsState::instance.buildings[buildingID].uid, 0); + } - DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout = 8; - } + // Point all harassing siege engines at the currently attacked player + for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { + if (DAT_UnitsState::instance.units[unitID].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE + && DAT_UnitsState::instance.units[unitID].dying == 0 + && (DAT_UnitsState::instance.units[unitID].unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || DAT_UnitsState::instance.units[unitID].unitType == OpenSHC::Map::Units::UT_S_FBALLISTA) + && DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType == OpenSHC::AI::AIUBT_SIEGE_01) { + DAT_UnitsState::instance.units[unitID].siegeTargetPlayerID + = (short)DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; } } - return; + DAT_GameState::instance.playerDataArray[playerID].harrasingEngineRecruitTimeout = 8; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 0e40853b5..bbfc5baa6 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35273,7 +35273,7 @@ SHC_3BB0A8C1_0x004CD160 | 0.0% | Pending SHC_3BB0A8C1_0x004CD250 | 0.0% | Pending -SHC_3BB0A8C1_0x004CD2A0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CD2A0 | 59.60% | Reimplemented functionally, code block ordering problem SHC_3BB0A8C1_0x004CD560 | 0.0% | Pending From 180492addb4bab5ccf59a5f6be20af3b4085cb66 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 08:46:27 +0200 Subject: [PATCH 098/242] reimplement: SHC_3BB0A8C1_0x004D4630 100% improve style --- src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp index 91625a23e..ea0aff1d7 100644 --- a/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp +++ b/src/OpenSHC/AI/AICState/recreateEngineersTribe.cpp @@ -9,15 +9,17 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D4630 void AICState::recreateEngineersTribe(int playerID) { - if (0 < DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops) { - int _tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12])) { + if (0 >= DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops) { + return; + } + int _tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12]; + if (_tribeID != 0) { + if (DAT_TribesState::instance.tribes[_tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0x12]) { DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0x12] = 0; } - MACRO_CALL_MEMBER(AICState_Func::addEngineersToTribe, this)(playerID); } + MACRO_CALL_MEMBER(AICState_Func::addEngineersToTribe, this)(playerID); } } } From b1c7425c4e07a92d1a4a47af1a0b4eb74aeefaa7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 09:00:37 +0200 Subject: [PATCH 099/242] reimplement: SHC_3BB0A8C1_0x004CE110 100% --- .../AI/AICState/recomputeAttackAIZone.cpp | 68 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 23 insertions(+), 47 deletions(-) diff --git a/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp index 427a791cc..905549bec 100644 --- a/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAttackAIZone.cpp @@ -17,55 +17,31 @@ namespace AI { using OpenSHC::Map::AttackInfoSubElement; // FUNCTION: STRONGHOLDCRUSADER 0x004CE110 - void AICState ::recomputeAttackAIZone() - + void AICState::recomputeAttackAIZone() { - - int* _pBorderDistance; - - int _playerID; - - AttackInfoSubElement* _pi; - - int _fullID; - - _playerID = 1; - - _pi = DAT_TroopValueState::instance.attackInfo.playerInfo; - - _pBorderDistance = &DAT_GameState::instance.playerDataArray[1].unknownPathBorderDistanceRelated; - - do { - - _fullID = DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_playerID]; - - _pi->currentPlayerID_OR_attackedPlayerID_OR_one = _playerID; - - if ((_fullID != -1) || (DAT_GameSynchronyState::instance.currentAIArray[_playerID] != 0)) { - - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( - 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); - - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, - DAT_PathFindingState::ptr)(_playerID, 2); - - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkLayerAndAIPathCostLayer, - DAT_PathFindingState::ptr)(252, 0, 1, _playerID); - - *_pBorderDistance = DAT_PathFindingState::instance.distance; - - _pi->currentPlayerID_OR_attackedPlayerID_OR_one = 1; + for (int playerID = 1; playerID < 9; playerID++) { + int fullID = DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID]; + DAT_TroopValueState::instance.attackInfo.playerInfo[playerID - 1].currentPlayerID_OR_attackedPlayerID_OR_one + = playerID; + if (fullID == -1 + && DAT_GameSynchronyState::instance.currentAIArray[playerID] == 0 + // fixme: this comparison looks dumb since fullID is already known to be the value, so a cmp eax eax + // is generated, but we need it for the 100% match. + && fullID == DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID]) { + continue; } - _playerID = _playerID + 1; - - _pBorderDistance = _pBorderDistance + 0xe7d; - - _pi = _pi + 1; - - } while (_playerID < 9); - - return; + MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 80400, '\0', DAT_TileMapState::instance.AIZoneLayer); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, + DAT_PathFindingState::ptr)(playerID, 2, 1); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkLayerAndAIPathCostLayer, + DAT_PathFindingState::ptr)(252, 0, 1, playerID); + DAT_GameState::instance.playerDataArray[playerID].unknownPathBorderDistanceRelated + = DAT_PathFindingState::instance.distance; + DAT_TroopValueState::instance.attackInfo.playerInfo[playerID - 1].currentPlayerID_OR_attackedPlayerID_OR_one + = 1; + } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index bbfc5baa6..5fd24f5a9 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35303,7 +35303,7 @@ SHC_3BB0A8C1_0x004CDFD0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE040 | 0.0% | Pending -SHC_3BB0A8C1_0x004CE110 | 0.0% | Pending +SHC_3BB0A8C1_0x004CE110 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE1A0 | 0.0% | Pending From a2fe0aa457bf8e685780efaf36afe8f84ce63e58 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 09:05:56 +0200 Subject: [PATCH 100/242] reimplement: SHC_3BB0A8C1_0x004CE040 100% --- .../recomputeAIPathCostToAttackedKeep.cpp | 77 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 23 insertions(+), 56 deletions(-) diff --git a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp index 96ed632f2..45197c9e8 100644 --- a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp @@ -16,78 +16,45 @@ namespace AI { using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CE040 - void AICState ::recomputeAIPathCostToAttackedKeep(int playerID, int useBorderDistance) - + void AICState::recomputeAIPathCostToAttackedKeep(int playerID, int useBorderDistance) { + int attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + int keepArea = (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_GameState::instance.playerDataArray[playerID].campground.tileEntry]; - BOOLEnum BVar1; - - uint _borderDistance; - - bool _cannotNavigateToKeep; - - int _attackedPlayerID; - - int _bd; - - ushort _keepArea; - - _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; - - _keepArea = DAT_TileMapState::instance - .PathConnectionLayer[DAT_GameState::instance.playerDataArray[playerID].campground.tileEntry]; - - _bd = DAT_GameState::instance.playerDataArray[_attackedPlayerID].unknownPathBorderDistanceRelated; - - if (_bd < 120) { - - _borderDistance = ((_bd < 90) - 1 & 20) + 50; - + int borderDistance; + if (DAT_GameState::instance.playerDataArray[attackedPlayerID].unknownPathBorderDistanceRelated > 120) { + borderDistance = 98; } - else { - - _borderDistance = 98; + borderDistance + = DAT_GameState::instance.playerDataArray[attackedPlayerID].unknownPathBorderDistanceRelated > 90 ? 70 + : 50; } - if (useBorderDistance == 0) { - - _borderDistance = 0; + borderDistance = 0; } - *(int*)((int)DAT_TroopValueState::instance.attackInfo.hackValuesArray + playerID * 0x177bc + -0x10) - = _attackedPlayerID; + DAT_TroopValueState::instance.attackInfo.playerInfo[playerID - 1].currentPlayerID_OR_attackedPlayerID_OR_one + = attackedPlayerID; MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( - 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); - - BVar1 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, - DAT_GameState::ptr)(playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); - - _cannotNavigateToKeep = BVar1 == FALSE; - - if (_cannotNavigateToKeep) { - - _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + 80400, '\0', DAT_TileMapState::instance.AIZoneLayer); + if (MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::canNavigateFromKeepToKeep, DAT_GameState::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID) + != FALSE) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 1, 1); } - else { - - _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 0, 1); } - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, - DAT_PathFindingState::ptr)(_attackedPlayerID, (int)((int)((uint)!_cannotNavigateToKeep))); - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkLayerAndAIPathCostLayer, - DAT_PathFindingState::ptr)(110, _borderDistance, (dword)((int)((int)(short)_keepArea)), playerID); - - return; + DAT_PathFindingState::ptr)(110, borderDistance, keepArea, playerID); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5fd24f5a9..a036517e5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35301,7 +35301,7 @@ SHC_3BB0A8C1_0x004CDF10 | 72.0% | Reimplemented functionally, same different reg SHC_3BB0A8C1_0x004CDFD0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CE040 | 0.0% | Pending +SHC_3BB0A8C1_0x004CE040 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE110 | 100.0% | Reimplemented From 77d9f2426e4dbd11cecf73c6bd09e01a6d46c898 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 09:06:25 +0200 Subject: [PATCH 101/242] reimplement: SHC_3BB0A8C1_0x004CE1A0 100% --- .../AI/AICState/recomputeAIZonerLayer.cpp | 18 +++--------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp index f7f48b02b..2478afb94 100644 --- a/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAIZonerLayer.cpp @@ -12,31 +12,19 @@ namespace OpenSHC { namespace AI { - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CE1A0 - void AICState ::recomputeAIZonerLayer() - + void AICState::recomputeAIZonerLayer() { - DAT_TroopValueState::instance.attackInfo.playerInfo[0].currentPlayerID_OR_attackedPlayerID_OR_one = 1; - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( - 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIZoneLayer))); - + 80400, '\0', DAT_TileMapState::instance.AIZoneLayer); MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, DAT_PathFindingState::ptr)(1, 2); - + OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, DAT_PathFindingState::ptr)(1, 2, 1); MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::updateWalkLayerAndAIPathCostLayer, DAT_PathFindingState::ptr)(252, 0, 1, 1); - DAT_GameState::instance.playerDataArray[1].unknownPathBorderDistanceRelated = DAT_PathFindingState::instance.distance; - DAT_TroopValueState::instance.attackInfo.playerInfo[0].currentPlayerID_OR_attackedPlayerID_OR_one = 1; - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a036517e5..08eb853cf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35305,7 +35305,7 @@ SHC_3BB0A8C1_0x004CE040 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE110 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CE1A0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CE1A0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE200 | 0.0% | Pending From d09996fd0fb35d46debdc31722c92f81b91b2937 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 09:36:58 +0200 Subject: [PATCH 102/242] progress --- .../AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp | 5 +++-- src/OpenSHC/AI/AICState/setFoodBuyPlan.cpp | 1 - src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp index be55240a6..f3285132e 100644 --- a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp +++ b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp @@ -32,6 +32,7 @@ namespace AI { return; } + int aicIndex = aiType - 1; BOOLEnum enclosed = MACRO_CALL_MEMBER( OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); @@ -39,8 +40,8 @@ namespace AI { int count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount [DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[i].aivUnitType]; int groups = count; - if (count > this->aics[aiType - 1].defWallPatrolGroups) { - groups = this->aics[aiType - 1].defWallPatrolGroups; + if (count > this->aics[aicIndex].defWallPatrolGroups) { + groups = this->aics[aicIndex].defWallPatrolGroups; } if (groups <= 0) { continue; diff --git a/src/OpenSHC/AI/AICState/setFoodBuyPlan.cpp b/src/OpenSHC/AI/AICState/setFoodBuyPlan.cpp index 981ad02d9..780b9a3d4 100644 --- a/src/OpenSHC/AI/AICState/setFoodBuyPlan.cpp +++ b/src/OpenSHC/AI/AICState/setFoodBuyPlan.cpp @@ -15,7 +15,6 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB060 void AICState::setFoodBuyPlan(int playerID) { - int const aiType = DAT_GameState::ptr->playerDataArray[playerID].aiType; // Early return if not an AI player (human player has aiType == 0) diff --git a/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp b/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp index 1b9dcf37b..45c33ff67 100644 --- a/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp +++ b/src/OpenSHC/AI/AICState/setTriggerForAITauntResponse.cpp @@ -9,8 +9,7 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D1090 void AICState::setTriggerForAITauntResponse() { - BOOLEnum BVar1 = MACRO_CALL_MEMBER(Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)(); - if (BVar1 != FALSE) { + if (MACRO_CALL_MEMBER(Game::GameCore_Func::getAreWeInAInGameMenu, DAT_GameCore::ptr)() != FALSE) { this->aiTauntResponseTimeWindow = timeGetTime(); } } From 87b378723db0562d6abb8832e44fcc5f166d5fbe Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 09:45:23 +0200 Subject: [PATCH 103/242] reimplement: SHC_3BB0A8C1_0x004CC070 100% --- .../randomlySelectAttackUnitTypeToRecruit.cpp | 238 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 72 insertions(+), 168 deletions(-) diff --git a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp index e875a483a..4b0108c3d 100644 --- a/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp +++ b/src/OpenSHC/AI/AICState/randomlySelectAttackUnitTypeToRecruit.cpp @@ -16,215 +16,119 @@ namespace AI { using OpenSHC::AI::AITypeInt; using OpenSHC::AI::AIUnitBehaviourType; - /* - doc: - Determines which AI unit behaviour groups need recruiting because AIC Max units hasn't been - reached for that category, then randomly selects one of those groups to recruit - - @returns AiUnitBehaviourType The selected unit behaviour type - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CC070 - AIUnitBehaviourType AICState ::randomlySelectAttackUnitTypeToRecruit(int playerID) - + AIUnitBehaviourType AICState::randomlySelectAttackUnitTypeToRecruit(int playerID) { - - int* piVar1; - - dword _engineersCount; - - int _index2; - - int _rng; - - int _index; - - int _aiTypeMin1; - - dword _maxDiggingUnits; - - dword _maxAssassins; - - dword _maxUnit2; - - dword _maxLaddermen; - - dword _maxTunnelers; - - dword _maxUnitPatrol; - - AITypeInt _aiType; - - int _attackedPlayerID; - - dword _maxEngineers; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType == OpenSHC::AI::AIT_NULL) { - + AITypeInt aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) { return OpenSHC::AI::AIUBT_ATTUNITMAIN; } - _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; - - _index = 0; - - /* - clear out flags */ - - piVar1 = &DAT_SkirmishDefinedData::instance.attackUnitRequired[0].required; - - do { - - *piVar1 = 0; - - piVar1 = piVar1 + 2; - - } while ((int)piVar1 < 0xb425ec); - - _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxEngineers; + int attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; + int aicIndex = aiType - 1; + int requiredCount = 0; - _engineersCount = DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; - - if ((int)_maxEngineers < (int)_engineersCount) { - - _engineersCount = _maxEngineers; + // clear out flags + for (int i = 0; i < 11; i++) { + DAT_SkirmishDefinedData::instance.attackUnitRequired[i].required = 0; } - if ((_maxEngineers != 0) - && (DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops - < (int)_engineersCount)) { - - _index = 1; - + int engineersCount = DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 4; + if (engineersCount > (int)this->aics[aicIndex].AttMaxEngineers) { + engineersCount = this->aics[aicIndex].AttMaxEngineers; + } + if (this->aics[aicIndex].AttMaxEngineers != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops < engineersCount) { + requiredCount = 1; DAT_SkirmishDefinedData::instance.attackUnitRequired[0].required = 1; } - _maxDiggingUnits = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttDiggingUnitMax; - - if (((_maxDiggingUnits != 0) - && (DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops < (int)_maxDiggingUnits)) - && (5 < DAT_GameState::instance.playerDataArray[_attackedPlayerID].moatsOwned)) { - - _index = _index + 1; - + if (this->aics[aicIndex].AttDiggingUnitMax != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops + < (int)this->aics[aicIndex].AttDiggingUnitMax + && DAT_GameState::instance.playerDataArray[attackedPlayerID].moatsOwned > 5) { + requiredCount++; DAT_SkirmishDefinedData::instance.attackUnitRequired[1].required = 1; } - _maxAssassins = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxAssassins; - - if ((_maxAssassins != 0) - && (DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops < (int)_maxAssassins)) { - - _index = _index + 1; - + if (this->aics[aicIndex].AttMaxAssassins != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops + < (int)this->aics[aicIndex].AttMaxAssassins) { + requiredCount++; DAT_SkirmishDefinedData::instance.attackUnitRequired[2].required = 1; } - _maxUnit2 = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnit2Max; - - if ((_maxUnit2 != 0) && (DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops < (int)_maxUnit2)) { - - _index = _index + 1; - + if (this->aics[aicIndex].AttUnit2Max != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + < (int)this->aics[aicIndex].AttUnit2Max) { + requiredCount++; DAT_SkirmishDefinedData::instance.attackUnitRequired[3].required = 1; } - _maxLaddermen = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxLaddermen; - - if ((_maxLaddermen != 0) - && (DAT_GameState::instance.playerDataArray[playerID].totalLaddermenTroops < (int)_maxLaddermen)) { - - _index = _index + 1; - + if (this->aics[aicIndex].AttMaxLaddermen != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalLaddermenTroops + < (int)this->aics[aicIndex].AttMaxLaddermen) { + requiredCount++; DAT_SkirmishDefinedData::instance.attackUnitRequired[4].required = 1; } - _maxTunnelers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxTunnelers; - - if ((_maxTunnelers != 0) - && (DAT_GameState::instance.playerDataArray[playerID].totalTunnelerTroops < (int)_maxTunnelers)) { - - _index = _index + 1; - + if (this->aics[aicIndex].AttMaxTunnelers != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalTunnelerTroops + < (int)this->aics[aicIndex].AttMaxTunnelers) { + requiredCount++; DAT_SkirmishDefinedData::instance.attackUnitRequired[5].required = 1; } - _maxUnitPatrol = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitPatrolMax; - - if ((_maxUnitPatrol != 0) - && (DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops < (int)_maxUnitPatrol)) { - - _index = _index + 1; - + if (this->aics[aicIndex].AttUnitPatrolMax != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops + < (int)this->aics[aicIndex].AttUnitPatrolMax) { + requiredCount++; DAT_SkirmishDefinedData::instance.attackUnitRequired[6].required = 1; } - _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitBackupMax; - - if ((_maxEngineers != 0) - && (DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops < (int)_maxEngineers)) { - - _index = _index + 1; - + if (this->aics[aicIndex].AttUnitBackupMax != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops + < (int)this->aics[aicIndex].AttUnitBackupMax) { + requiredCount++; DAT_SkirmishDefinedData::instance.attackUnitRequired[7].required = 1; } - _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitEngageMax; - - if ((_maxEngineers != 0) - && (DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops < (int)_maxEngineers)) { - - _index = _index + 1; - + if (this->aics[aicIndex].AttUnitEngageMax != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops + < (int)this->aics[aicIndex].AttUnitEngageMax) { + requiredCount++; DAT_SkirmishDefinedData::instance.attackUnitRequired[8].required = 1; } - _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttUnitSiegeDefMax; - - if ((_maxEngineers != 0) - && (DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops < (int)_maxEngineers)) { - - _index = _index + 1; - + if (this->aics[aicIndex].AttUnitSiegeDefMax != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + < (int)this->aics[aicIndex].AttUnitSiegeDefMax) { + requiredCount++; DAT_SkirmishDefinedData::instance.attackUnitRequired[9].required = 1; } - _maxEngineers = this->aics[_aiType + ~OpenSHC::AI::AIT_NULL].AttMaxDefault; - - if ((_maxEngineers != 0) - && (DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops < (int)_maxEngineers)) { - - _index = _index + 1; - + if (this->aics[aicIndex].AttMaxDefault != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops + < (int)this->aics[aicIndex].AttMaxDefault) { + requiredCount++; DAT_SkirmishDefinedData::instance.attackUnitRequired[10].required = 1; } - if (_index != 0) { - - _rng = (int)SEC_RNG::instance.currentNumber2 % _index; - - MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - - _index2 = 0; - - do { - - if (DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2].required != 0) { - - if (_rng == 0) { - - return (AIUnitBehaviourType)(DAT_SkirmishDefinedData::instance.attackUnitRequired[_index2] - .unitBehaviourType); - } - - _rng = _rng + -1; - } - - _index2 = _index2 + 1; + if (requiredCount <= 0) { + return OpenSHC::AI::AIUBT_ATTUNITMAIN; + } - } while (_index2 < 0xb); + int selection = (int)SEC_RNG::instance.currentNumber2 % requiredCount; + MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); + + for (int i = 0; i < 11; i++) { + if (DAT_SkirmishDefinedData::instance.attackUnitRequired[i].required == 0) { + continue; + } + if (selection == 0) { + return (AIUnitBehaviourType)DAT_SkirmishDefinedData::instance.attackUnitRequired[i].unitBehaviourType; + } + selection--; } return OpenSHC::AI::AIUBT_ATTUNITMAIN; diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 08eb853cf..9b5760112 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34861,7 +34861,7 @@ SHC_3BB0A8C1_0x004CBFA0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CC000 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CC070 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC070 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CC250 | 0.0% | Pending From 6ad9b60bdebb3058840a5c35e238da62ad5c4b0e Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 09:49:44 +0200 Subject: [PATCH 104/242] reimplement: SHC_3BB0A8C1_0x004CEEA0 100% --- .../processAttForceRallyPercentage.cpp | 80 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 35 insertions(+), 47 deletions(-) diff --git a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp index 54eb917c0..302c38a63 100644 --- a/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/processAttForceRallyPercentage.cpp @@ -2,6 +2,7 @@ #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/AI/AITypeInt.hpp" +#include "OpenSHC/AI/Tribes/AITribeIndex.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" @@ -18,62 +19,49 @@ namespace AI { using OpenSHC::WindowsHelper::Enums::BOOLEnum; // FUNCTION: STRONGHOLDCRUSADER 0x004CEEA0 - BOOLEnum AICState ::processAttForceRallyPercentage(int playerID) - + BOOLEnum AICState::processAttForceRallyPercentage(int playerID) { - AITypeInt AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) + AITypeInt aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) { return FALSE; + } - AITypeInt _aiTypeMinus1 = AVar1 - 1; - int _tribeTotal = 0; - int _notReallyMoving = 0; - - int* local_c = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; - - do { - int iVar2 = (*(int (*)[2])(local_c + -1))[0]; - int iVar3 = *local_c; - - if (iVar2 != 0x12 && iVar2 != 0xbe && iVar2 != 0xf) { - int iVar5 = 0; - if (0 < iVar3) { - short* psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + iVar2; - - do { - int _tribeID = (int)*psVar4; - - if (_tribeID != 0 - && DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[iVar5 + iVar2]) { - - _tribeTotal = _tribeTotal + 1; - - if (DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0x14) - _notReallyMoving = _notReallyMoving + 1; - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; - } + int aicIndex = aiType - 1; + int tribeTotal = 0; + int notReallyMoving = 0; + + for (int i = 0; i < 11; i++) { + int tribeIndex = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType; + int tribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeCount; + if (tribeIndex == OpenSHC::AI::Tribes::AITI_BREACH_BASIC_07_01 + || tribeIndex == OpenSHC::AI::Tribes::AITI_BREACH_10_01 + || tribeIndex == OpenSHC::AI::Tribes::AITI_BREACH_BASIC_05_01) { + continue; + } - iVar5 = iVar5 + 1; - psVar4 = psVar4 + 1; + for (int j = 0; j < tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeIndex + j]; + if (tribeID == 0) { + continue; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[tribeIndex + j]) { + continue; + } - } while (iVar5 < iVar3); + tribeTotal++; + if (DAT_TribesState::instance.tribes[tribeID].percentageMovingUnk < 20) { + notReallyMoving++; } + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; } + } - local_c = local_c + 2; - - } while ((int)local_c < 0xb42a2c); - - if (0 < _tribeTotal) { - return ( - BOOLEnum)((_notReallyMoving * 100) / _tribeTotal >= *(int*)((int)this + _aiTypeMinus1 * 0x2a4 + 0x200)); + if (tribeTotal <= 0) { + return FALSE; } - return FALSE; + return (BOOLEnum)(notReallyMoving * 100 / tribeTotal >= this->aics[aicIndex].AttForceRallyPercentage); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9b5760112..22564a558 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35345,7 +35345,7 @@ SHC_3BB0A8C1_0x004CEC80 | 0.0% | Pending SHC_3BB0A8C1_0x004CED90 | 0.0% | Pending -SHC_3BB0A8C1_0x004CEEA0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CEEA0 | 100.0% | Pending SHC_3BB0A8C1_0x004CEFD0 | 100.0% | Reimplemented From 8f428beafff96cf48bc1fc07e84965e23ae769a2 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 09:57:52 +0200 Subject: [PATCH 105/242] reimplement: SHC_3BB0A8C1_0x004D0C70 100% --- .../playVictory2BikFromPlayerToPlayer.cpp | 37 ++++++++++++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp index 97437bc36..0d11e93d4 100644 --- a/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playVictory2BikFromPlayerToPlayer.cpp @@ -14,21 +14,30 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0C70 void AICState::playVictory2BikFromPlayerToPlayer(int playerID, int targetPlayerID) { - int iVar1; - bool bVar2; - if ((((DAT_GameState::instance.playerDataArray[targetPlayerID].aiType != AITA_NULL) - && (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] != -1)) - && (iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( - targetPlayerID), - iVar1 != 0)) - && (((iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( - playerID), - iVar1 != 0 && (DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 == 0)) - && (bVar2 = playerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, - DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 = 0x30, bVar2)))) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - targetPlayerID, (int)DAT_GameState::instance.playerDataArray[targetPlayerID].aiType - 1, 0xb); + if (DAT_GameState::instance.playerDataArray[targetPlayerID].aiType == AITA_NULL) { + return; } + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[playerID] == -1) { + return; + } + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(targetPlayerID) + == 0) { + return; + } + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; + } + if (DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 != 0) { + return; + } + + DAT_GameState::instance.playerDataArray[targetPlayerID].someAiCountdown4 = 48; + if (playerID != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return; + } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + targetPlayerID, DAT_GameState::instance.playerDataArray[targetPlayerID].aiType - 1, 11); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 22564a558..5018cfb2f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35429,7 +35429,7 @@ SHC_3BB0A8C1_0x004D0BB0 | 0.0% | Pending SHC_3BB0A8C1_0x004D0C00 | 0.0% | Pending -SHC_3BB0A8C1_0x004D0C70 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0C70 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0CF0 | 0.0% | Pending From 8a8ac98722cbcee09d6d453bd6baec122e8410ea Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 09:58:29 +0200 Subject: [PATCH 106/242] reimplement: SHC_3BB0A8C1_0x004D0A80 100% --- .../playThanksBikFromPlayerToPlayer.cpp | 39 +++++++++++-------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp index 110bb9381..823e435e9 100644 --- a/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playThanksBikFromPlayerToPlayer.cpp @@ -14,23 +14,30 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0A80 void AICState::playThanksBikFromPlayerToPlayer(int playerID, int targetPlayerID) { - DWORD DVar2; - int iVar1 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (iVar1 != 0) { - iVar1 = (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1; - DAT_GameState::instance.playerDataArray[playerID].aiRequestDelay = this->aics[iVar1].aiRequestDelay; - if (((targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) - && (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] - .lordKilledByPlayerID - == 0)) - && ((DVar2 = timeGetTime(), - DWORD_00eb0b18::instance == 0 || (1199999 < DVar2 - DWORD_00eb0b18::instance)))) { - DWORD_00eb0b18::instance = DVar2; - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, iVar1, 0xf); - } + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + + int aicIndex = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + DAT_GameState::instance.playerDataArray[playerID].aiRequestDelay = this->aics[aicIndex].aiRequestDelay; + + if (targetPlayerID != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return; + } + if (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .lordKilledByPlayerID + != 0) { + return; + } + + DWORD now = timeGetTime(); + if (DWORD_00eb0b18::instance != 0 && now - DWORD_00eb0b18::instance < 1200000) { + return; + } + + DWORD_00eb0b18::instance = now; + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, aicIndex, 15); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5018cfb2f..d6b75e61a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35419,7 +35419,7 @@ SHC_3BB0A8C1_0x004D0910 | 0.0% | Pending SHC_3BB0A8C1_0x004D0A20 | 0.0% | Pending -SHC_3BB0A8C1_0x004D0A80 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0A80 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0B10 | 0.0% | Pending From 9466c0b7a9a6d5adb695e51658e1cdff99bc79ba Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:07:30 +0200 Subject: [PATCH 107/242] reimplement: SHC_3BB0A8C1_0x004D1000 100% Reimplemented --- .../AICState/playTeamWinningBikFromPlayer.cpp | 17 +++++++++++------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp index 02745d879..429518496 100644 --- a/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playTeamWinningBikFromPlayer.cpp @@ -12,13 +12,18 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D1000 void AICState::playTeamWinningBikFromPlayer(int playerID) { - int iVar1 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker == 0)) - && (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker == 0)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1e); + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + if (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker != 0) { + return; + } + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker != 0) { + return; + } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 30); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d6b75e61a..6e26d2da1 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35451,7 +35451,7 @@ SHC_3BB0A8C1_0x004D0F90 | 0.0% | Pending SHC_3BB0A8C1_0x004D0FC0 | 0.0% | Pending -SHC_3BB0A8C1_0x004D1000 | 0.0% | Pending +SHC_3BB0A8C1_0x004D1000 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D1050 | 0.0% | Pending From 2f469f2c43dd3d0906b1a7798074d2d5d7ae8d60 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:08:12 +0200 Subject: [PATCH 108/242] reimplement: SHC_3BB0A8C1_0x004D07C0 100% Reimplemented --- ...playTauntToAttackedPlayerBikFromPlayer.cpp | 39 ++++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp index cc48af4ee..f49839574 100644 --- a/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playTauntToAttackedPlayerBikFromPlayer.cpp @@ -14,25 +14,28 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D07C0 void AICState::playTauntToAttackedPlayerBikFromPlayer(int playerID) { - int iVar1 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (iVar1 != 0) { - int _aiTypeMinusOne = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; - int _myTeam = DAT_GameState::instance.mapAndTime.playerTeams[playerID]; - int _curPlayer = DAT_GameSynchronyState::instance.currentPlayerSlotID; - int _bik = 0; - if (_myTeam == DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer]) { - _bik = 0x17; - } - int _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; - if (_bik == 0) { - _bik = ((byte)SEC_RNG::instance.currentNumber2 & 3) + 1; - } - if (_attackedPlayerID == _curPlayer) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, _aiTypeMinusOne, _bik); - } + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + + int bik = 0; + int aicIndex = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] + == DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { + bik = 23; + } + + if (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return; + } + + if (bik == 0) { + bik = (SEC_RNG::instance.currentNumber2 & 3) + 1; + } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, aicIndex, bik); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 6e26d2da1..92610a3f2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35409,7 +35409,7 @@ SHC_3BB0A8C1_0x004D05D0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0720 | 0.0% | Pending -SHC_3BB0A8C1_0x004D07C0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D07C0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0830 | 0.0% | Pending From 18d81a7e67a8d36b579b6f357c6db17e0b243d6d Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:15:32 +0200 Subject: [PATCH 109/242] reimplement: SHC_3BB0A8C1_0x004D0D40 100% Reimplemented --- status/addresses-SHC-3BB0A8C1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 92610a3f2..d20d166f0 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35433,7 +35433,7 @@ SHC_3BB0A8C1_0x004D0C70 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0CF0 | 0.0% | Pending -SHC_3BB0A8C1_0x004D0D40 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0D40 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0DB0 | 0.0% | Pending From 79aedd02008aa4a42fab85913e5c0ce15bbecf1e Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:15:47 +0200 Subject: [PATCH 110/242] reimplement: SHC_3BB0A8C1_0x004D1050 100% Reimplemented --- status/addresses-SHC-3BB0A8C1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d20d166f0..66023f14f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35453,7 +35453,7 @@ SHC_3BB0A8C1_0x004D0FC0 | 0.0% | Pending SHC_3BB0A8C1_0x004D1000 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D1050 | 0.0% | Pending +SHC_3BB0A8C1_0x004D1050 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D1090 | 0.0% | Pending From d6f29536e26ee2a685bd87a3284ebb585186a948 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:16:31 +0200 Subject: [PATCH 111/242] reimplement: SHC_3BB0A8C1_0x004D0B10 68% Reimplemented functionally, but aiType substraction is an issue --- .../AI/AICState/playNervous2BikFromPlayer.cpp | 13 ++++++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp index a2b044f24..54b30ae90 100644 --- a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp @@ -13,16 +13,15 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0B10 void AICState::playNervous2BikFromPlayer(int playerID) { - int iVar3 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - int iVar2 = DAT_GameSynchronyState::instance.currentPlayerSlotID; - if ((iVar3 != 0) && (DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown == 0)) { - int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; + int lord = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); + if ((lord != 0) && (DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown == 0)) { + int aiIndex = (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + int curPlayer = DAT_GameSynchronyState::instance.currentPlayerSlotID; DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown = 48; if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] - != DAT_GameState::instance.mapAndTime.playerTeams[iVar2]) { + != DAT_GameState::instance.mapAndTime.playerTeams[curPlayer]) { MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, AVar1 - 1, 9); + playerID, aiIndex, 9); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 66023f14f..70a9505f4 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35421,7 +35421,7 @@ SHC_3BB0A8C1_0x004D0A20 | 0.0% | Pending SHC_3BB0A8C1_0x004D0A80 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D0B10 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0B10 | 68.0% | Reimplemented functionally, but aiType substraction is an issue SHC_3BB0A8C1_0x004D0B70 | 0.0% | Pending From a2f086c7fd2ef05332dbc1c55dbcf281aaf48afb Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:20:37 +0200 Subject: [PATCH 112/242] reimplement: SHC_3BB0A8C1_0x004D0D40 100% Reimplemented --- .../AICState/playRequestHelpBikFromPlayer.cpp | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp index 3be00819a..5f1cee729 100644 --- a/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playRequestHelpBikFromPlayer.cpp @@ -13,18 +13,27 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0D40 void AICState::playRequestHelpBikFromPlayer(int playerID) { - int iVar2 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if ((iVar2 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 == 0)) { - DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 = 0x30; - int iVar1 = DAT_GameSynchronyState::instance.currentPlayerSlotID; - if ((DAT_GameState::instance.mapAndTime.playerTeams[playerID] - == DAT_GameState::instance.mapAndTime.playerTeams[iVar1]) - && (DAT_GameState::instance.playerDataArray[iVar1].lordKilledByPlayerID == 0)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x13); - } + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + if (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 != 0) { + return; + } + + DAT_GameState::instance.playerDataArray[playerID].someAiCountdown6 = 48; + + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] + != DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { + return; + } + if (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .lordKilledByPlayerID + != 0) { + return; + } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 19); } } } From 2667f905840ed10dd1d32f1b51c8e1224754435c Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:20:58 +0200 Subject: [PATCH 113/242] reimplement: SHC_3BB0A8C1_0x004D08B0 100% Reimplemented --- ...yerKilledBiksFromKilledAndKillerPlayer.cpp | 88 ++++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 47 insertions(+), 43 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp index b520df926..93e437633 100644 --- a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp @@ -14,54 +14,58 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D08B0 void AICState::playPlayerKilledBiksFromKilledAndKillerPlayer(int killerPlayerID, int killedPlayerID) { - int iVar1 = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( - killerPlayerID); - if (iVar1 != 0) { - int _curPlayer = DAT_GameSynchronyState::instance.currentPlayerSlotID; - if (killedPlayerID == _curPlayer) { - iVar1 = 0xc; - } else { - if (killerPlayerID == _curPlayer) { - MACRO_CALL_MEMBER( - Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); - int i = 1; - do { - if ((DAT_GameState::instance.playerDataArray[i].aiType != AITA_NULL) - && (DAT_GameState::instance.mapAndTime.playerTeams[i] - == DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer])) { - int iVar2 = MACRO_CALL_MEMBER( - Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i); - if (iVar2 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, - DAT_VideoBikQueue::ptr)( - i, (int)DAT_GameState::instance.playerDataArray[i].aiType - 1, 0x11); - } - } - i = i + 1; - } while (i < 9); - return; + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(killerPlayerID) + == 0) { + return; + } + + if (killedPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killerPlayerID, DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 12); + return; + } + + if (killerPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + + for (int i = 1; i < 9; i++) { + if (DAT_GameState::instance.playerDataArray[i].aiType == AITA_NULL) { + continue; } - int _curTeam = DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer]; - if (_curTeam == DAT_GameState::instance.mapAndTime.playerTeams[killedPlayerID]) { - MACRO_CALL_MEMBER( - Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 0x10); - return; + if (DAT_GameState::instance.mapAndTime.playerTeams[i] + != DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { + continue; } - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - killedPlayerID, (int)DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); - if (DAT_GameState::instance.mapAndTime.playerTeams[killerPlayerID] == _curTeam) { - MACRO_CALL_MEMBER( - Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 0x12); - return; + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i) == 0) { + continue; } - iVar1 = 0xd; + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + i, DAT_GameState::instance.playerDataArray[i].aiType - 1, 17); } + return; + } + + if (DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID] + == DAT_GameState::instance.mapAndTime.playerTeams[killedPlayerID]) { + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 16); + return; + } + + if (DAT_GameState::instance.mapAndTime.playerTeams[killerPlayerID] + == DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - killerPlayerID, (int)DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, iVar1); + killedPlayerID, DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killerPlayerID, DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 18); + return; } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killedPlayerID, DAT_GameState::instance.playerDataArray[killedPlayerID].aiType - 1, 7); + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + killerPlayerID, DAT_GameState::instance.playerDataArray[killerPlayerID].aiType - 1, 13); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 70a9505f4..7bad6cf5b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35413,7 +35413,7 @@ SHC_3BB0A8C1_0x004D07C0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0830 | 0.0% | Pending -SHC_3BB0A8C1_0x004D08B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D08B0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0910 | 0.0% | Pending From c1e6390235097cb24a6fbeb6e5259ea76ccdd871 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:21:36 +0200 Subject: [PATCH 114/242] reimplement: SHC_3BB0A8C1_0x004D1050 100% Reimplemented --- src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp index 2a4c11018..07b38053e 100644 --- a/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playNoHelpBikFromPlayer.cpp @@ -12,12 +12,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D1050 void AICState::playNoHelpBikFromPlayer(int playerID) { - int iVar1 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1f); + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 31); } } } From 9b79e34f1ae1d759b989330fd9672234e39b610d Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:30:57 +0200 Subject: [PATCH 115/242] reimplement: SHC_3BB0A8C1_0x004D0830 100% Reimplemented --- .../AI/AICState/playAnger1BikFromPlayer.cpp | 37 +++++++++++-------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp index fed855c23..c2f18af59 100644 --- a/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playAnger1BikFromPlayer.cpp @@ -14,23 +14,28 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0830 void AICState::playAnger1BikFromPlayer(int playerID) { - int iVar2 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (iVar2 != 0) { - int _playerTeam = DAT_GameState::instance.mapAndTime.playerTeams[playerID]; - int AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; - int _curPlayer = DAT_GameSynchronyState::instance.currentPlayerSlotID; - if ((_playerTeam != DAT_GameState::instance.mapAndTime.playerTeams[_curPlayer]) - && (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID == _curPlayer)) { - DWORD DVar3 = timeGetTime(); - if ((INT_ARRAY_00eb0af0::instance[playerID] == 0) - || (DVar3 - INT_ARRAY_00eb0af0::instance[playerID] >= 0x927c0)) { - INT_ARRAY_00eb0af0::instance[playerID] = DVar3; - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, - DAT_VideoBikQueue::ptr)(playerID, AVar1, 5); - } - } + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + + int aicIndex = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] + == DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { + return; + } + if (DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID + != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return; + } + + DWORD now = timeGetTime(); + if (INT_ARRAY_00eb0af0::instance[playerID] != 0 && now - INT_ARRAY_00eb0af0::instance[playerID] < 600000) { + return; + } + + INT_ARRAY_00eb0af0::instance[playerID] = now; + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, aicIndex, 5); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 7bad6cf5b..a27673088 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35411,7 +35411,7 @@ SHC_3BB0A8C1_0x004D0720 | 0.0% | Pending SHC_3BB0A8C1_0x004D07C0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D0830 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0830 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D08B0 | 100.0% | Reimplemented From 0e6631eda6544f0ec855f471ed481d214ed880bc Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:31:08 +0200 Subject: [PATCH 116/242] reimplement: SHC_3BB0A8C1_0x004D0C00 100% Reimplemented --- .../playAnger2BikFromPlayerToPlayer.cpp | 26 ++++++++++++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp index dbef793fc..df0b308ad 100644 --- a/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playAnger2BikFromPlayerToPlayer.cpp @@ -14,17 +14,23 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0C00 void AICState::playAnger2BikFromPlayerToPlayer(int playerID, int targetPlayerID) { - if (DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) { - int iVar1 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - bool bVar2; - if (((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 == 0)) - && (bVar2 = targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID, - DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 = 0x60, bVar2)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 6); - } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + return; } + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; + } + if (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 != 0) { + return; + } + + DAT_GameState::instance.playerDataArray[playerID].someAiCountdown3 = 96; + if (targetPlayerID != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return; + } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 6); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a27673088..98989adf7 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35427,7 +35427,7 @@ SHC_3BB0A8C1_0x004D0B70 | 0.0% | Pending SHC_3BB0A8C1_0x004D0BB0 | 0.0% | Pending -SHC_3BB0A8C1_0x004D0C00 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0C00 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0C70 | 100.0% | Reimplemented From 1619d51320ada834d0f3ed1a299b9a75aaac9487 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:31:18 +0200 Subject: [PATCH 117/242] reimplement: SHC_3BB0A8C1_0x004D0FC0 100% Reimplemented --- .../AI/AICState/playFriendlyVictoryBikFromPlayer.cpp | 10 +++++----- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp index ea8497a85..64249dc9c 100644 --- a/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playFriendlyVictoryBikFromPlayer.cpp @@ -12,12 +12,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0FC0 void AICState::playFriendlyVictoryBikFromPlayer(int playerID) { - int iVar1 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 10); + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 10); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 98989adf7..319d006b8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35449,7 +35449,7 @@ SHC_3BB0A8C1_0x004D0F40 | 0.0% | Pending SHC_3BB0A8C1_0x004D0F90 | 0.0% | Pending -SHC_3BB0A8C1_0x004D0FC0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0FC0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D1000 | 100.0% | Reimplemented From 4bf4be4036ce94e70ab13f235b80a5e3e4d8444a Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:31:29 +0200 Subject: [PATCH 118/242] reimplement: SHC_3BB0A8C1_0x004D0B70 100% Reimplemented --- .../AI/AICState/playGoodsNotSentBikFromPlayer.cpp | 10 +++++----- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp index 62fd7fb60..ca55ee528 100644 --- a/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playGoodsNotSentBikFromPlayer.cpp @@ -12,12 +12,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0B70 void AICState::playGoodsNotSentBikFromPlayer(int playerID) { - int iVar1 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1c); + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 28); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 319d006b8..f0c786102 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35423,7 +35423,7 @@ SHC_3BB0A8C1_0x004D0A80 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0B10 | 68.0% | Reimplemented functionally, but aiType substraction is an issue -SHC_3BB0A8C1_0x004D0B70 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0B70 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0BB0 | 0.0% | Pending From 8a90902eb76363dddb93b9792c75405fdafd9570 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:31:41 +0200 Subject: [PATCH 119/242] reimplement: SHC_3BB0A8C1_0x004D0A20 100% Reimplemented --- .../playGoodsRequestBikFromPlayerToPlayer.cpp | 21 ++++++++++++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp index 484a7fbbb..acb064856 100644 --- a/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playGoodsRequestBikFromPlayerToPlayer.cpp @@ -13,15 +13,20 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0A20 void AICState::playGoodsRequestBikFromPlayerToPlayer(int playerID, int targetPlayerID) { - int iVar1 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) - && (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] - .lordKilledByPlayerID - == 0)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0xe); + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + if (targetPlayerID != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return; + } + if (DAT_GameState::instance.playerDataArray[DAT_GameSynchronyState::instance.currentPlayerSlotID] + .lordKilledByPlayerID + != 0) { + return; + } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 14); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f0c786102..ba2003a9c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35417,7 +35417,7 @@ SHC_3BB0A8C1_0x004D08B0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0910 | 0.0% | Pending -SHC_3BB0A8C1_0x004D0A20 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0A20 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0A80 | 100.0% | Reimplemented From 56a08df0de94368b2acd3d6bbcd9b7ce75a2fffd Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:31:52 +0200 Subject: [PATCH 120/242] reimplement: SHC_3BB0A8C1_0x004D0BB0 100% Reimplemented --- .../AICState/playGoodsSentBikFromPlayerToPlayer.cpp | 13 ++++++++----- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp b/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp index b9afb8833..7b807ddfc 100644 --- a/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playGoodsSentBikFromPlayerToPlayer.cpp @@ -13,12 +13,15 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0BB0 void AICState::playGoodsSentBikFromPlayerToPlayer(int playerID, int targetPlayerID) { - int iVar1 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if ((iVar1 != 0) && (targetPlayerID == DAT_GameSynchronyState::instance.currentPlayerSlotID)) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 0x1d); + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + if (targetPlayerID != DAT_GameSynchronyState::instance.currentPlayerSlotID) { + return; + } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 29); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index ba2003a9c..596614baa 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35425,7 +35425,7 @@ SHC_3BB0A8C1_0x004D0B10 | 68.0% | Reimplemented functionally, but aiType substra SHC_3BB0A8C1_0x004D0B70 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D0BB0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0BB0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0C00 | 100.0% | Reimplemented From 3fa8fb68fabd53cf7fd9a6b7ac02d301425367a5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:32:02 +0200 Subject: [PATCH 121/242] reimplement: SHC_3BB0A8C1_0x004D0F90 100% Reimplemented --- src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp | 10 +++++----- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp b/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp index e6528e25b..639186e16 100644 --- a/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp +++ b/src/OpenSHC/AI/AICState/playJokeBikFromAIToHuman.cpp @@ -11,12 +11,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0F90 void AICState::playJokeBikFromAIToHuman(int playerID, int aiType) { - int iVar1 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if (iVar1 != 0) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, aiType, 0x14); + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, aiType, 20); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 596614baa..8ac10096a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35447,7 +35447,7 @@ SHC_3BB0A8C1_0x004D0EF0 | 0.0% | Pending SHC_3BB0A8C1_0x004D0F40 | 0.0% | Pending -SHC_3BB0A8C1_0x004D0F90 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0F90 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0FC0 | 100.0% | Reimplemented From 241a028e4d1262a32e394f97d16b8b4be489f92e Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:32:11 +0200 Subject: [PATCH 122/242] reimplement: SHC_3BB0A8C1_0x004D0CF0 100% Reimplemented --- .../AI/AICState/playNervous1BikFromPlayer.cpp | 15 +++++++++------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp index 93c274c9b..0bdd24ea6 100644 --- a/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playNervous1BikFromPlayer.cpp @@ -12,13 +12,16 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0CF0 void AICState::playNervous1BikFromPlayer(int playerID) { - int iVar1 - = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if ((iVar1 != 0) && (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 == 0)) { - DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 = 0x30; - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 8); + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + if (DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 != 0) { + return; + } + + DAT_GameState::instance.playerDataArray[playerID].someAiCountdown5 = 48; + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, DAT_GameState::instance.playerDataArray[playerID].aiType - 1, 8); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8ac10096a..733503862 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35431,7 +35431,7 @@ SHC_3BB0A8C1_0x004D0C00 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0C70 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D0CF0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0CF0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0D40 | 100.0% | Reimplemented From 46e2a9ea6e3000a151bea4eb8db06605120544d7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:32:31 +0200 Subject: [PATCH 123/242] reimplement: SHC_3BB0A8C1_0x004D0B10 68% Register scheduling issued --- .../AI/AICState/playNervous2BikFromPlayer.cpp | 26 ++++++++++++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp index 54b30ae90..3f9d7334b 100644 --- a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp @@ -13,17 +13,23 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D0B10 void AICState::playNervous2BikFromPlayer(int playerID) { - int lord = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID); - if ((lord != 0) && (DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown == 0)) { - int aiIndex = (int)DAT_GameState::instance.playerDataArray[playerID].aiType - 1; - int curPlayer = DAT_GameSynchronyState::instance.currentPlayerSlotID; - DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown = 48; - if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] - != DAT_GameState::instance.mapAndTime.playerTeams[curPlayer]) { - MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, aiIndex, 9); - } + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(playerID) == 0) { + return; } + if (DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown != 0) { + return; + } + + int aicIndex = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + int currentPlayerID = DAT_GameSynchronyState::instance.currentPlayerSlotID; + DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown = 48; + if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] + == DAT_GameState::instance.mapAndTime.playerTeams[currentPlayerID]) { + return; + } + + MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( + playerID, aicIndex, 9); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 733503862..f721f84a1 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35421,7 +35421,7 @@ SHC_3BB0A8C1_0x004D0A20 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0A80 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D0B10 | 68.0% | Reimplemented functionally, but aiType substraction is an issue +SHC_3BB0A8C1_0x004D0B10 | 68.0% | Register scheduling issued SHC_3BB0A8C1_0x004D0B70 | 100.0% | Reimplemented From e7c49bc37f43f4e43ca807868c0db8da84e5dfc2 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:55:25 +0200 Subject: [PATCH 124/242] reimplement: SHC_3BB0A8C1_0x004CBA50 85.1% Reimplemented functionally, stack and cached load differencesd --- ...BuyWhenLowOnResourceAndSnoozeBuildings.cpp | 493 +++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 195 insertions(+), 300 deletions(-) diff --git a/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp index af9196afb..4db7857fd 100644 --- a/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp +++ b/src/OpenSHC/AI/AICState/planToBuyWhenLowOnResourceAndSnoozeBuildings.cpp @@ -2,6 +2,8 @@ #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" #include "OpenSHC/AI/AIType.hpp" +#include "OpenSHC/Game/Resources/ResourceType.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -10,321 +12,214 @@ namespace OpenSHC { namespace AI { using OpenSHC::AI::AIType; + using namespace OpenSHC::Game::Resources; + using namespace OpenSHC::Map::Buildings; // FUNCTION: STRONGHOLDCRUSADER 0x004CBA50 - void AICState ::planToBuyWhenLowOnResourceAndSnoozeBuildings(int playerID) - + void AICState::planToBuyWhenLowOnResourceAndSnoozeBuildings(int playerID) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) { + return; + } - int _buildingBurning; - - int _offset; - - int _currentWood; - - int _noWood; - - int _currentPopulation; - - int* _pResourceCounter; - - int _hasArmoyUnk; - - int* _pNoBeerCounter; - - int* _pNoHopsTracker; - - int* _pNoFlourTracker; - - int* _pNoIronTracker; - - bool _enoughFood; - - bool _enoughGold; - - bool _enoughPeopleUnk; - - int _nerves; - - int _noBeerCounterUnk; - - int _noFlourCounterUnk; - - int _noHopsCounterUnk; - - int _noIronCounterUnk; - - bool _noNerves; - - int* _pNoWoodTracker; - - int _resourceCounter; - - _offset = playerID * 0x39f4; - - if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { - - _enoughPeopleUnk = true; - - _enoughFood = true; - - _enoughGold = true; - - _buildingBurning = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::playerHasBurningBuilding, - DAT_BuildingsState::ptr)(playerID); - - _currentWood = DAT_GameState::instance.playerDataArray[playerID].currentResources[2]; - - if (_currentWood < 1) { - - _pNoWoodTracker = &DAT_GameState::instance.playerDataArray[playerID].noWoodTracker; - - *_pNoWoodTracker = *_pNoWoodTracker + 1; - - } - - else { - - DAT_GameState::instance.playerDataArray[playerID].noWoodTracker = 0; - } - - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[6] < 1) { - - _pNoIronTracker = &DAT_GameState::instance.playerDataArray[playerID].noIronTracker; - - *_pNoIronTracker = *_pNoIronTracker + 1; - - } - - else { - - DAT_GameState::instance.playerDataArray[playerID].noIronTracker = 0; - } - - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0x10] < 1) { - - _pNoFlourTracker = &DAT_GameState::instance.playerDataArray[playerID].noFlourTracker; - - *_pNoFlourTracker = *_pNoFlourTracker + 1; - - } - - else { - - DAT_GameState::instance.playerDataArray[playerID].noFlourTracker = 0; - } - - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[3] < 1) { - - _pNoHopsTracker = &DAT_GameState::instance.playerDataArray[playerID].noHopsTracker; - - *_pNoHopsTracker = *_pNoHopsTracker + 1; - - } - - else { - - DAT_GameState::instance.playerDataArray[playerID].noHopsTracker = 0; - } - - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xe] < 1) { - - _pNoBeerCounter = &DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk; - - *_pNoBeerCounter = *_pNoBeerCounter + 1; - - } - - else { - - DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk = 0; - } - - _pResourceCounter = &DAT_GameState::instance.playerDataArray[playerID].someResourceCounter; - - *_pResourceCounter = *_pResourceCounter + 1; - - if (DAT_GameState::instance.playerDataArray[playerID].countFletchersPoleturners < 1) { - - DAT_GameState::instance.playerDataArray[playerID].noWoodTracker = 0; - } - - if (DAT_GameState::instance.playerDataArray[playerID].countArmorersAndBlacksmiths < 1) { - - DAT_GameState::instance.playerDataArray[playerID].noIronTracker = 0; - } - - if (DAT_GameState::instance.playerDataArray[playerID].countBakers < 1) { - - DAT_GameState::instance.playerDataArray[playerID].noFlourTracker = 0; - } - - if (DAT_GameState::instance.playerDataArray[playerID].countBrewers < 1) { - - DAT_GameState::instance.playerDataArray[playerID].noHopsTracker = 0; - } - - _currentPopulation = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; - - if ((_currentPopulation < 10) - && ((DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers != 0 - || (2 < DAT_GameState::instance.playerDataArray[playerID].countWoodcutters)))) { - - _enoughPeopleUnk = false; - } - - if ((((20 < _currentWood) && (_currentPopulation < 10)) - && (DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers != 0)) - && (DAT_GameState::instance.playerDataArray[playerID].totalFood < 8)) { - - _enoughFood = false; - } - - if (((_buildingBurning == 0) - && (DAT_GameState::instance.playerDataArray[playerID].countFarms - <= DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers)) - && (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < 500)) { - - _enoughGold = false; - } - - _hasArmoyUnk = DAT_GameState::instance.playerDataArray[playerID].armory.id; - - _noWood = DAT_GameState::instance.playerDataArray[playerID].noWoodTracker; - - _noIronCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noIronTracker; - - _resourceCounter = DAT_GameState::instance.playerDataArray[playerID].someResourceCounter; - - _noFlourCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noFlourTracker; - - _noHopsCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noHopsTracker; - - _noBeerCounterUnk = DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk; - - _nerves = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; - - _noNerves = _nerves < 1; - - if (!_noNerves) { - - _enoughPeopleUnk = false; - - _enoughFood = false; - } - - if (_enoughGold) { - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[27] = false; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x46] = false; - - } - - else { - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1b] = true; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x46] = true; - } - - if (_enoughPeopleUnk) { - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[20] = false; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[4] = false; - - } - - else { - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x14] = true; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[4] = true; - } - - *(bool*)(_offset + 0x115df8f) = !_enoughFood; - - *(bool*)(_offset + 0x115df91) = !_noNerves; - - *(bool*)(_offset + 0x115df92) = !_noNerves; - - *(bool*)(_offset + 0x115df98) = _nerves < 1 && (36 < _noWood || _hasArmoyUnk == 0); - - *(bool*)(_offset + 0x115df9a) = _nerves < 1 && (36 < _noWood || _hasArmoyUnk == 0); - - *(bool*)(_offset + 0x115df99) = _noNerves && (0x24 < _noIronCounterUnk || _hasArmoyUnk == 0); - - *(bool*)(_offset + 0x115df9b) = _noNerves && (0x24 < _noIronCounterUnk || _hasArmoyUnk == 0); - - *(bool*)(_offset + 0x115df9c) = _noNerves && (0x24 < _resourceCounter || _hasArmoyUnk == 0); - - *(bool*)(_offset + 0x115df9d) = !_noNerves || 0x24 < _noFlourCounterUnk; - - *(bool*)(_offset + 0x115df9e) = !_noNerves || 0x48 < _noHopsCounterUnk; - - *(bool*)(_offset + 0x115dfa2) = !_noNerves || 0x48 < _noBeerCounterUnk; - - if (_noNerves) { - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1e] = false; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1f] = false; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x20] = false; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x21] = false; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[7] = false; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[34] = false; - - } - - else { - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1e] = true; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x1f] = true; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x20] = true; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x21] = true; - - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[7] = true; + int allowFletchers = 1; + int allowIronMines = 1; + int allowFarms = 1; + int allowPitchRigs = 1; + int allowWoodcutters = 1; + int allowPoleturners = 1; + int allowQuarries = 1; + int allowBlacksmiths = 1; + int allowArmourers = 1; + int allowTanners = 1; + int allowBakeries = 1; + int allowBreweries = 1; + int allowInns = 1; + int allowWells = 1; + + int buildingBurning = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::playerHasBurningBuilding, DAT_BuildingsState::ptr)(playerID); + int wood = DAT_GameState::instance.playerDataArray[playerID].currentResources[RT_WOOD]; + + if (wood <= 0) { + DAT_GameState::instance.playerDataArray[playerID].noWoodTracker++; + } else { + DAT_GameState::instance.playerDataArray[playerID].noWoodTracker = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[RT_IRON] <= 0) { + DAT_GameState::instance.playerDataArray[playerID].noIronTracker++; + } else { + DAT_GameState::instance.playerDataArray[playerID].noIronTracker = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[RT_FLOUR] <= 0) { + DAT_GameState::instance.playerDataArray[playerID].noFlourTracker++; + } else { + DAT_GameState::instance.playerDataArray[playerID].noFlourTracker = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[RT_HOPS] <= 0) { + DAT_GameState::instance.playerDataArray[playerID].noHopsTracker++; + } else { + DAT_GameState::instance.playerDataArray[playerID].noHopsTracker = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[RT_ALE] <= 0) { + DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk++; + } else { + DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk = 0; + } + DAT_GameState::instance.playerDataArray[playerID].someResourceCounter++; - DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[0x22] = true; - } + if (DAT_GameState::instance.playerDataArray[playerID].countFletchersPoleturners <= 0) { + DAT_GameState::instance.playerDataArray[playerID].noWoodTracker = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].countArmorersAndBlacksmiths <= 0) { + DAT_GameState::instance.playerDataArray[playerID].noIronTracker = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].countBakers <= 0) { + DAT_GameState::instance.playerDataArray[playerID].noFlourTracker = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].countBrewers <= 0) { + DAT_GameState::instance.playerDataArray[playerID].noHopsTracker = 0; + } - if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0) { + int population = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; + if (population < 10 + && (DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers != 0 + || DAT_GameState::instance.playerDataArray[playerID].countWoodcutters > 2)) { + allowQuarries = 0; + } - if ((36 < DAT_GameState::instance.playerDataArray[playerID].noWoodTracker) - && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] == 0)) { + if (wood >= 20 && population < 10 && DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalFood < 8) { + allowWoodcutters = 0; + } - DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[2] = 5; - } + if (buildingBurning == 0 + && DAT_GameState::instance.playerDataArray[playerID].farmsWithoutWorkers + >= DAT_GameState::instance.playerDataArray[playerID].countFarms + && DAT_GameState::instance.playerDataArray[playerID].currentResources[RT_GOLD] < 500) { + allowWells = 0; + } - if ((36 < DAT_GameState::instance.playerDataArray[playerID].noIronTracker) - && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[6] == 0)) { + if (DAT_GameState::instance.playerDataArray[playerID].armory.id == 0) { + allowFletchers = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].noWoodTracker > 36) { + allowFletchers = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].armory.id == 0) { + allowPoleturners = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].noWoodTracker > 36) { + allowPoleturners = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].armory.id == 0) { + allowBlacksmiths = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].noIronTracker > 36) { + allowBlacksmiths = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].armory.id == 0) { + allowArmourers = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].noIronTracker > 36) { + allowArmourers = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].armory.id == 0) { + allowTanners = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].someResourceCounter > 36) { + allowTanners = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].noFlourTracker > 36) { + allowBakeries = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].noHopsTracker > 72) { + allowBreweries = 0; + } + if (DAT_GameState::instance.playerDataArray[playerID].noBeerCounterUnk > 72) { + allowInns = 0; + } - DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[6] = 2; - } + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { + allowFletchers = 1; + allowIronMines = 0; + allowQuarries = 0; + allowFarms = 0; + allowPitchRigs = 0; + allowWoodcutters = 0; + allowPoleturners = 1; + allowBlacksmiths = 1; + allowArmourers = 1; + allowTanners = 1; + allowBakeries = 0; + allowBreweries = 0; + allowInns = 0; + } - if ((36 < DAT_GameState::instance.playerDataArray[playerID].noFlourTracker) - && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[0x10] == 0)) { + if (allowWells) { + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_WELL] = false; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_WATERPOT] = false; + } else { + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_WELL] = true; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_WATERPOT] = true; + } - DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[0x10] = 2; - } + if (allowQuarries) { + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_QUARRY] = false; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_OXTETHER] = false; + } else { + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_QUARRY] = true; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_OXTETHER] = true; + } - if ((72 < DAT_GameState::instance.playerDataArray[playerID].noHopsTracker) - && (DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[3] == 0)) { + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_WOODCUTTERSHUT] = !allowWoodcutters; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_IRONMINE] = !allowIronMines; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_PITCHRIG] = !allowPitchRigs; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_FLETCHER] = !allowFletchers; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_POLETURNER] = !allowPoleturners; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_BLACKSMITH] = !allowBlacksmiths; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_ARMOURER] = !allowArmourers; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_TANNER] = !allowTanners; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_BAKERY] = !allowBakeries; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_BREWERY] = !allowBreweries; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_INN] = !allowInns; + + if (allowFarms) { + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_WHEATFARM] = false; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_HOPFARM] = false; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_APPLEFARM] = false; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_DAIRYFARM] = false; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_HUNTERSHUT] = false; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_MILL] = false; + } else { + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_WHEATFARM] = true; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_HOPFARM] = true; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_APPLEFARM] = true; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_DAIRYFARM] = true; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_HUNTERSHUT] = true; + DAT_GameState::instance.playerDataArray[playerID].snoozedBuildings[BT_MILL] = true; + } - DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[3] = 2; - } - } + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) { + return; } - return; + if (DAT_GameState::instance.playerDataArray[playerID].noWoodTracker > 36 + && DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[RT_WOOD] == 0) { + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[RT_WOOD] = 5; + } + if (DAT_GameState::instance.playerDataArray[playerID].noIronTracker > 36 + && DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[RT_IRON] == 0) { + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[RT_IRON] = 2; + } + if (DAT_GameState::instance.playerDataArray[playerID].noFlourTracker > 36 + && DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[RT_FLOUR] == 0) { + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[RT_FLOUR] = 2; + } + if (DAT_GameState::instance.playerDataArray[playerID].noHopsTracker > 72 + && DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[RT_HOPS] == 0) { + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[RT_HOPS] = 2; + } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f721f84a1..e9e37c748 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34853,7 +34853,7 @@ SHC_3BB0A8C1_0x004CB940 | 0.0% | Pending SHC_3BB0A8C1_0x004CB9F0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CBA50 | 0.0% | Pending +SHC_3BB0A8C1_0x004CBA50 | 85.1% | Reimplemented functionally, stack and cached load differencesd SHC_3BB0A8C1_0x004CBE30 | 100.0% | Reimplemented From f5d8aad7cc93f78305919ea9139754b7da602ec3 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 10:57:25 +0200 Subject: [PATCH 125/242] reimplement: SHC_3BB0A8C1_0x004CED90 100% Reimplemented --- ...rcentageNonMovingTribesGTEAICSpecified.cpp | 96 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 30 insertions(+), 68 deletions(-) diff --git a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp index 990c9b55e..c3816ae7b 100644 --- a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp +++ b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp @@ -15,82 +15,44 @@ namespace AI { using OpenSHC::AI::AITypeInt; using OpenSHC::WindowsHelper::Enums::BOOLEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CED90 - BOOLEnum AICState ::percentageNonMovingTribesGTEAICSpecified(int playerID) - + BOOLEnum AICState::percentageNonMovingTribesGTEAICSpecified(int playerID) { - - int _tribe; - - int _index; - - short* _ptrTribeNumber; - - int _tribesCount; - - int _movingFewerThan20Percent; - - int* _ptrSize; - - AITypeInt _aiType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType == OpenSHC::AI::AIT_NULL) { - + AITypeInt aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) { return FALSE; } - _tribesCount = 0; - - _movingFewerThan20Percent = 0; - - _ptrSize = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; - - do { - - _index = 0; - - if (0 < *_ptrSize) { - - _ptrTribeNumber - = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + (*(int (*)[2])(_ptrSize + -1))[0]; - - do { - - _tribe = (int)*_ptrTribeNumber; - - if (((_tribe != 0) - && (DAT_TribesState::instance.tribes[_tribe].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[_index + (*(int (*)[2])(_ptrSize + -1))[0]])) - && (_tribesCount = _tribesCount + 1, - DAT_TribesState::instance.tribes[_tribe].percentageMovingUnk < 20)) { - - _movingFewerThan20Percent = _movingFewerThan20Percent + 1; - } - - _index = _index + 1; - - _ptrTribeNumber = _ptrTribeNumber + 1; - - } while (_index < *_ptrSize); + int aicIndex = aiType - 1; + int tribeTotal = 0; + int notReallyMoving = 0; + + for (int i = 0; i < 11; i++) { + int tribeIndex = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType; + int tribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeCount; + + for (int j = 0; j < tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeIndex + j]; + if (tribeID == 0) { + continue; + } + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[tribeIndex + j]) { + continue; + } + + tribeTotal++; + if (DAT_TribesState::instance.tribes[tribeID].percentageMovingUnk < 20) { + notReallyMoving++; + } } + } - _ptrSize = _ptrSize + 2; - - } while ((int)_ptrSize < 0xb42a2c); - - if (0 < _tribesCount) { - - return (uint)(*(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x204) - <= (_movingFewerThan20Percent * 100) / _tribesCount); + if (tribeTotal <= 0) { + return FALSE; } - return FALSE; + return (BOOLEnum)(notReallyMoving * 100 / tribeTotal >= this->aics[aicIndex].AttMovingTribesThreshold); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e9e37c748..f9d1dcab0 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35343,7 +35343,7 @@ SHC_3BB0A8C1_0x004CEB80 | 0.0% | Pending SHC_3BB0A8C1_0x004CEC80 | 0.0% | Pending -SHC_3BB0A8C1_0x004CED90 | 0.0% | Pending +SHC_3BB0A8C1_0x004CED90 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CEEA0 | 100.0% | Pending From 2b1d46d7b87c5f67669465c0b7267993f314b035 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 13:50:00 +0200 Subject: [PATCH 126/242] reimplement: SHC_3BB0A8C1_0x004CE830 100% Reimplemented --- .../AICState/moveAttackTribesToLocations.cpp | 55 +++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 20 insertions(+), 37 deletions(-) diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp index e0e022eb8..6801cfdf0 100644 --- a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -12,48 +12,31 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - // FUNCTION: STRONGHOLDCRUSADER 0x004CE830 void AICState::moveAttackTribesToLocations(int playerID) { if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) return; - int _destIndex = 0; - - for (int _index = 0; _index < 11; _index++) { - int const _tribeTypeStart = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; - int _tribeIndex = 0; - int const _maxTribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - - for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { - - int const _tribeID - = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) { - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] - .xOffset)), - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[playerID * 5][_destIndex] - .yOffset)), - 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - - _destIndex = _destIndex + 1; - } + int destIndex = 0; + for (int i = 0; i < 11; i++) { + int tribeType = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType; + int tribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeCount; + for (int j = 0; j < tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeType + j]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[j + tribeType]) + continue; + + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, + DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex].xOffset, + DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex].yOffset, + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + destIndex++; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f9d1dcab0..2ec41a772 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35327,7 +35327,7 @@ SHC_3BB0A8C1_0x004CE6B0 | 0.0% | Pending SHC_3BB0A8C1_0x004CE790 | 0.0% | Pending -SHC_3BB0A8C1_0x004CE830 | 0.0% | Pending +SHC_3BB0A8C1_0x004CE830 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE860 | 0.0% | Pending From 2e8fdd55dd79d1e27ab14d19871a8842bdd23346 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 13:58:39 +0200 Subject: [PATCH 127/242] reimplement: SHC_3BB0A8C1_0x004D3960 100% Reimplemented --- .../AI/AICState/makeOutpostTribesAttack.cpp | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp index 3b53ff92a..243d4828c 100644 --- a/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp +++ b/src/OpenSHC/AI/AICState/makeOutpostTribesAttack.cpp @@ -8,18 +8,15 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D3960 void AICState::makeOutpostTribesAttack() { - int* _tribeUIDs = this->tribeUIDArray; - short* _tribeIDs = this->tribeIDArray; - int _countDown = 1000; - do { - unsigned int _tribeID = (uint)*_tribeIDs; - if ((_tribeID != 0) && (DAT_TribesState::instance.tribes[_tribeID].uid == *_tribeUIDs)) { - MACRO_CALL_MEMBER(AICState_Func::decideOnTribeAttackLocation, this)(_tribeID); - } - _tribeIDs = _tribeIDs + 1; - _tribeUIDs = _tribeUIDs + 1; - _countDown = _countDown + -1; - } while (_countDown != 0); + for (int i = 0; i < 1000; i++) { + int tribeID = this->tribeIDArray[i]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid != this->tribeUIDArray[i]) + continue; + + MACRO_CALL_MEMBER(AICState_Func::decideOnTribeAttackLocation, this)(tribeID); + } } } } From 8a4f23007e9d3efbf0d125b29ce6280ebc569a5f Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 13:59:22 +0200 Subject: [PATCH 128/242] reimplement: SHC_3BB0A8C1_0x004CEA50 92.7% Reimplemented functionally, stack ordering problem --- ...eUnitsGoDefensiveAndBackToSomeLocation.cpp | 107 +++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 28 insertions(+), 81 deletions(-) diff --git a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp index fc5f66990..a6e4bac6f 100644 --- a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp +++ b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp @@ -12,89 +12,36 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CEA50 - void AICState ::makeUnitsGoDefensiveAndBackToSomeLocation(int param_1) - + void AICState::makeUnitsGoDefensiveAndBackToSomeLocation(int playerID) { - - int iVar1; - - int iVar2; - - int _commandResult; - - short* psVar3; - - int tribeID; - - int iVar4; - - int* local_c; - - uint _x; - - if ((DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) - && (DAT_GameState::instance.playerDataArray[param_1].someTile != 0)) { - - local_c = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; - - do { - - iVar1 = *local_c; - - iVar2 = (*(int (*)[2])(local_c + -1))[0]; - - iVar4 = 0; - - if (0 < iVar1) { - - psVar3 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + iVar2; - - do { - - tribeID = (int)*psVar3; - - if ((tribeID != 0) - && (DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar4 + iVar2])) { - - _x = DAT_GameState::instance.playerDataArray[param_1].someX; - - DAT_TribesState::instance.tribes[tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - - _commandResult = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - tribeID, _x, (uint)((int)(DAT_GameState::instance.playerDataArray[param_1].someY)), 0, - 0, OpenSHC::Map::Units::Instructions::UMSE_0); - - if (_commandResult == 0) { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::removeAllTribeUnits, - DAT_TribesState::ptr)(tribeID); - } - } - - iVar4 = iVar4 + 1; - - psVar3 = psVar3 + 1; - - } while (iVar4 < iVar1); - } - - local_c = local_c + 2; - - } while ((int)local_c < 0xb42a2c); + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; + if (DAT_GameState::instance.playerDataArray[playerID].someTile == 0) + return; + + for (int i = 0; i < 11; i++) { + int tribeType = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType; + int tribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeCount; + for (int j = 0; j < tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeType + j]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[j + tribeType]) + continue; + + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + uint result = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(tribeID, + DAT_GameState::instance.playerDataArray[playerID].someX, + DAT_GameState::instance.playerDataArray[playerID].someY, 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + if (result == 0) + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::removeAllTribeUnits, DAT_TribesState::ptr)( + tribeID); + } } - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 2ec41a772..83f018ed9 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35335,7 +35335,7 @@ SHC_3BB0A8C1_0x004CE890 | 0.0% | Pending SHC_3BB0A8C1_0x004CE930 | 0.0% | Pending -SHC_3BB0A8C1_0x004CEA50 | 0.0% | Pending +SHC_3BB0A8C1_0x004CEA50 | 92.7% | Reimplemented functionally, stack ordering problem SHC_3BB0A8C1_0x004CEB50 | 0.0% | Pending From a0b5d270eac773bde9d14294d33d7cb3a8bb7959 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 13:59:34 +0200 Subject: [PATCH 129/242] reimplement: SHC_3BB0A8C1_0x004ECAB0 100% Reimplemented --- .../AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp b/src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp index 09d8f6571..41ac2d515 100644 --- a/src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp +++ b/src/OpenSHC/AI/AICState/mapperIsWoodCuttersHutWhileNoWoodAvailable.cpp @@ -10,8 +10,10 @@ namespace AI { BOOLEnum AICState::mapperIsWoodCuttersHutWhileNoWoodAvailable( undefined4 playerID, Commands::MappersEnum commandBuildingType) { - return ((commandBuildingType == Commands::M_MAPPER_WOODSMAN) - && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0)); + if (commandBuildingType == Commands::M_MAPPER_WOODSMAN + && DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0) + return TRUE; + return FALSE; } } } From 6b7d7dfe91ffad063888a825f067f01fc6ffe6f3 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 13:59:48 +0200 Subject: [PATCH 130/242] reimplement: SHC_3BB0A8C1_0x004D2F80 100% Reimplemented --- .../moveAttackingUnitsToNextRallyPoint.cpp | 175 +++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 48 insertions(+), 129 deletions(-) diff --git a/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp b/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp index 1f483f35a..04aa9c19d 100644 --- a/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackingUnitsToNextRallyPoint.cpp @@ -15,137 +15,56 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D2F80 - void AICState ::moveAttackingUnitsToNextRallyPoint(int playerID) - + void AICState::moveAttackingUnitsToNextRallyPoint(int playerID) { - - short sVar1; - - short* _ptrAttackingUnitsTribeID; - - BOOLEnum _allArrived; - - int _rallyPointIndex; - - uint _x; - - uint _y; - - int _tribeID; - - bool bVar2; - - bool bVar3; - - bool bVar4; - - int _counter; - - short _totalRallyPointSteps; - - short _targetUnitID; - - if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { - - _ptrAttackingUnitsTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xbe; - - _counter = 0; - - do { - - _tribeID = (int)*_ptrAttackingUnitsTribeID; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_counter + 0xbe])) { - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - _allArrived - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::allUnitsReachedTheirDestination, - DAT_TribesState::ptr)(_tribeID); - - if (_allArrived != FALSE) { - - DAT_TribesState::instance.tribes[_tribeID].unknownAttackRelatedUpdateCounter = 0; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addRallyPointForTribe, this)(_tribeID); - - _totalRallyPointSteps = DAT_TribesState::instance.tribes[_tribeID].rallyPointCount; - - _rallyPointIndex = DAT_TribesState::instance.tribes[_tribeID].currentRallyPointIndex + 1; - - if (_totalRallyPointSteps <= _rallyPointIndex) { - - _rallyPointIndex = 0; - } - - _x = (uint)DAT_TribesState::instance.tribes[_tribeID].rallyPointArray[_rallyPointIndex][0]; - - _y = (uint)DAT_TribesState::instance.tribes[_tribeID].rallyPointArray[_rallyPointIndex][1]; - - _targetUnitID = DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; - - DAT_TribesState::instance.tribes[_tribeID].currentRallyPointIndex = (short)_rallyPointIndex; - - if (0 < _totalRallyPointSteps) { - - if (_totalRallyPointSteps < 2) { - - MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, - DAT_DirectionAlgorithmState::ptr)( - (int)DAT_UnitsState::instance.units[_targetUnitID].x, - (int)((int)(DAT_UnitsState::instance.units[_targetUnitID].y)), (int)((int)(_x)), - (int)((int)(_y))); - - bVar4 = (DAT_DirectionAlgorithmState::instance.distanceHigh < 5); - - bVar3 = DAT_DirectionAlgorithmState::instance.distanceHigh + -5 < 0; - - bVar2 = DAT_DirectionAlgorithmState::instance.distanceHigh == 5; - - } - - else { - - sVar1 = DAT_UnitsState::instance.units[_targetUnitID].closestEnemyMicroDistance; - - bVar4 = (sVar1 < 96); - - bVar3 = (short)(sVar1 + 96) < 0; - - bVar2 = sVar1 == 96; - } - - if (!bVar2 && bVar4 == bVar3) { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)( - _tribeID, _x, _y, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - } - } - } - } - - _counter = _counter + 1; - - _ptrAttackingUnitsTribeID = _ptrAttackingUnitsTribeID + 1; - - } while (_counter < 2); + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; + + for (int i = 0; i < 2; i++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[190 + i]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[i + 190]) + continue; + + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::allUnitsReachedTheirDestination, + DAT_TribesState::ptr)(tribeID) + == FALSE) + continue; + + DAT_TribesState::instance.tribes[tribeID].unknownAttackRelatedUpdateCounter = 0; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addRallyPointForTribe, this)(tribeID); + + short rallyPointCount = DAT_TribesState::instance.tribes[tribeID].rallyPointCount; + int rallyPointIndex = DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex + 1; + if (rallyPointIndex >= rallyPointCount) + rallyPointIndex = 0; + + int x = DAT_TribesState::instance.tribes[tribeID].rallyPointArray[rallyPointIndex][0]; + int y = DAT_TribesState::instance.tribes[tribeID].rallyPointArray[rallyPointIndex][1]; + int targetUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex = rallyPointIndex; + + if (rallyPointCount <= 0) + continue; + + if (rallyPointCount <= 1) { + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(DAT_UnitsState::instance.units[targetUnitID].x, + DAT_UnitsState::instance.units[targetUnitID].y, x, y); + if (DAT_DirectionAlgorithmState::instance.distanceHigh <= 5) + continue; + } else { + if (DAT_UnitsState::instance.units[targetUnitID].closestEnemyMicroDistance <= 96) + continue; + } + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, x, y, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); } - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 83f018ed9..9f044fffc 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35507,7 +35507,7 @@ SHC_3BB0A8C1_0x004D2E00 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D2EC0 | 0.0% | Pending -SHC_3BB0A8C1_0x004D2F80 | 0.0% | Pending +SHC_3BB0A8C1_0x004D2F80 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D30E0 | 100.0% | Reimplemented, barring one register usage difference From 5ee02e896037aeedff78c11195261847ca32b6ef Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:12:16 +0200 Subject: [PATCH 131/242] reimplement: SHC_3BB0A8C1_0x004D00A0 100% Reimplemented --- .../AI/AICState/hasNotEnoughSupplies.cpp | 27 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp index 28dffd267..96e8e3c36 100644 --- a/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp +++ b/src/OpenSHC/AI/AICState/hasNotEnoughSupplies.cpp @@ -1,4 +1,5 @@ #include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -9,24 +10,20 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D00A0 BOOLEnum AICState::hasNotEnoughSupplies(int playerID) { - BOOLEnum BVar1 = TRUE; if (DAT_GameState::instance.playerDataArray[playerID].marketplace.id == 0 - && DAT_GameState::instance.playerDataArray[playerID].currentResources[2] - < DAT_BuildingsState::instance.buildingCosts[0x1a].requiredWood - && DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 1) { - return BVar1; - } + && DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_WOOD] + < DAT_BuildingsState::instance.buildingCosts[Map::Buildings::BT_MARKETPLACE].requiredWood + && DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount < 1) + return TRUE; if (DAT_GameState::instance.playerDataArray[playerID].granary.id == 0 - && DAT_GameState::instance.playerDataArray[playerID].currentResources[2] - < DAT_BuildingsState::instance.buildingCosts[0x13].requiredWood - && DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount <= 1) { - return BVar1; - } - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] <= 0 + && DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_WOOD] + < DAT_BuildingsState::instance.buildingCosts[Map::Buildings::BT_GRANARY].requiredWood + && DAT_GameState::instance.playerDataArray[playerID].noLabourerBuildingCount <= 1) + return TRUE; + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] <= 0 && DAT_GameState::instance.playerDataArray[playerID].popularity <= 25 - && DAT_GameState::instance.playerDataArray[playerID].totalFood <= 0) { - return BVar1; - } + && DAT_GameState::instance.playerDataArray[playerID].totalFood <= 0) + return TRUE; return FALSE; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9f044fffc..d4ad207a4 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35393,7 +35393,7 @@ SHC_3BB0A8C1_0x004CFF60 | 0.0% | Pending SHC_3BB0A8C1_0x004CFFD0 | 0.0% | Pending -SHC_3BB0A8C1_0x004D00A0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D00A0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0110 | 100.0% | Reimplemented From 21d7e03ee29dcc21568c9aaa08b53cb6bc8ef13f Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:12:32 +0200 Subject: [PATCH 132/242] reimplement: SHC_3BB0A8C1_0x004CFFD0 100% Reimplemented --- .../AICState/hasNoTroopsOrAllAreDiggers.cpp | 53 +++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 20 insertions(+), 35 deletions(-) diff --git a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp index fe3050b27..b009cbc8a 100644 --- a/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp +++ b/src/OpenSHC/AI/AICState/hasNoTroopsOrAllAreDiggers.cpp @@ -8,51 +8,36 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CFFD0 BOOLEnum AICState::hasNoTroopsOrAllAreDiggers(int playerID) { - int _totalMisc = DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops + int totalTroops = DAT_GameState::instance.playerDataArray[playerID].totalAssassinTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnit2Troops + DAT_GameState::instance.playerDataArray[playerID].totalUnitPatrolTroops; - int _halfOfDiggingTroops = 0; - int _totalTroops; + int halfOfDiggingTroops = 0; if (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState == 6) { - _totalMisc += DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops; - int _attackTicker = DAT_GameState::instance.playerDataArray[playerID].attackTicker; - int _backup; - if (_attackTicker > 0x10) { - int _bp = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - _backup = (_bp + (_bp >> 0x1f & 7)) >> 3; - } else { - _backup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - } - _totalMisc += _backup; - _totalTroops = _totalMisc - + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops + totalTroops += DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops; + if (DAT_GameState::instance.playerDataArray[playerID].attackTicker > 16) + totalTroops += DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops / 8; + else + totalTroops += DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + totalTroops += DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops; } else { - int _digging = DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops; - _halfOfDiggingTroops = _digging / 2; - int _attackTicker = DAT_GameState::instance.playerDataArray[playerID].attackTicker; - int _backup; - if (_attackTicker > 0xc) { - int _bp2 = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - _backup = (_bp2 + (_bp2 >> 0x1f & 7)) >> 3; - } else { - _backup = DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; - } - _totalMisc += _backup; - _totalTroops = _totalMisc - + DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops + halfOfDiggingTroops = DAT_GameState::instance.playerDataArray[playerID].totalDiggingUnitTroops / 2; + if (DAT_GameState::instance.playerDataArray[playerID].attackTicker > 12) + totalTroops += DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops / 8; + else + totalTroops += DAT_GameState::instance.playerDataArray[playerID].totalUnitBackupTroops; + totalTroops += DAT_GameState::instance.playerDataArray[playerID].totalUnitEngageTroops + DAT_GameState::instance.playerDataArray[playerID].totalUnitSiegeDefTroops + DAT_GameState::instance.playerDataArray[playerID].totalMaxDefaultTroops; } - if (1 < _totalTroops) { - if (4 < _totalTroops || _halfOfDiggingTroops <= _totalTroops + _totalTroops) { - return FALSE; - } - } - return TRUE; + if (totalTroops <= 1) + return TRUE; + if (totalTroops <= 4 && halfOfDiggingTroops > totalTroops * 2) + return TRUE; + return FALSE; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d4ad207a4..afc130e6c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35391,7 +35391,7 @@ SHC_3BB0A8C1_0x004CFCD0 | 0.0% | Pending SHC_3BB0A8C1_0x004CFF60 | 0.0% | Pending -SHC_3BB0A8C1_0x004CFFD0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CFFD0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D00A0 | 100.0% | Reimplemented From 2fe05a4ef34645c62d10999cd358e8021355ffaa Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:12:49 +0200 Subject: [PATCH 133/242] reimplement: SHC_3BB0A8C1_0x004D2830 100% Reimplemented --- .../AI/AICState/ifHasTribe0SendUnitsToKeep.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp index db603d327..8c8d55360 100644 --- a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp +++ b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp @@ -9,12 +9,13 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D2830 void AICState::ifHasTribe0SendUnitsToKeep(int playerID) { - int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0]; - if ((0 < tribeID) - && (DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0])) { - MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); - } + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0]; + if (tribeID <= 0) + return; + if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0]) + return; + + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); } } } From c416ee57988e838d17f1615ef942f45b10a3744f Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:13:02 +0200 Subject: [PATCH 134/242] reimplement: SHC_3BB0A8C1_0x004D0520 100% Reimplemented --- ...erOrEqualThanMinimumGoodsRequiredAfterTrade.cpp | 14 +++++++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp b/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp index 9b2058928..d4224026c 100644 --- a/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp +++ b/src/OpenSHC/AI/AICState/isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade.cpp @@ -11,15 +11,15 @@ namespace AI { BOOLEnum AICState::isResourceLargerOrEqualThanMinimumGoodsRequiredAfterTrade( int playerID, ResourceType resourceType, int buffer) { - int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType == AITA_NULL) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) return TRUE; - } - if (resourceType == Game::Resources::RT_GOLD) { + if (resourceType == Game::Resources::RT_GOLD) return FALSE; - } - return (int)this->aics[_aiType - 1].minimumGoodsRequiredAfterTrade + buffer - <= DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType]; + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType] + < this->aics[DAT_GameState::instance.playerDataArray[playerID].aiType - 1].minimumGoodsRequiredAfterTrade + + buffer) + return FALSE; + return TRUE; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index afc130e6c..9abd77133 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35401,7 +35401,7 @@ SHC_3BB0A8C1_0x004D0190 | 100.0% | Reimplemented, compiler didn't optimize one t SHC_3BB0A8C1_0x004D0280 | 0.0% | Pending -SHC_3BB0A8C1_0x004D0520 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0520 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0580 | 0.0% | Pending From e1bacb215367c518a3f569d90da7819decd6128b Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:35:33 +0200 Subject: [PATCH 135/242] reimplement: SHC_3BB0A8C1_0x004CEB50 98.80% Reimplemented --- .../giveMoveCommandToAttackTribes.cpp | 112 +++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 28 insertions(+), 86 deletions(-) diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp index 198397d4e..72b1efc80 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp @@ -12,94 +12,36 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CEB50 - void AICState ::giveMoveCommandToAttackTribes(int playerID) - + void AICState::giveMoveCommandToAttackTribes(int playerID) { - - int _aiTribeID; - - int _counter; - - int _groupCounter; - - int* _ptrGroupCount; - - int _groupCount; - - int _playerID; - - int _tribeType; - - _playerID = playerID; - - if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { - - _counter = 0; - - _ptrGroupCount = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; - - do { - - _tribeType = (*(int (*)[2])(_ptrGroupCount + -1))[0]; - - _groupCount = *_ptrGroupCount; - - if ((((_tribeType != 18) && (_tribeType != 190)) && (_tribeType != 15)) - && (_groupCounter = 0, 0 < _groupCount)) { - - /* - fixme: param reusage */ - - playerID = (_playerID * 0x1cfa + _tribeType) * 2 + 0x115ef04; - - do { - - _aiTribeID = (int)*(short*)playerID; - - if ((_aiTribeID != 0) - && (DAT_TribesState::instance.tribes[_aiTribeID].uid - == DAT_GameState::instance.playerDataArray[_playerID] - .aiTribeUIDs[_groupCounter + _tribeType])) { - - /* - bug: why give a random unit stance? */ - - DAT_TribesState::instance.tribes[_aiTribeID].unitStance - = (short)(char)((byte)SEC_RNG::instance.currentNumber2 & 1); - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, - DAT_TribesState::ptr)(_aiTribeID, - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[_playerID * 5][_counter] - .xOffset)), - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[_playerID * 5][_counter] - .yOffset)), - 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - - _counter = _counter + 1; - } - - playerID = playerID + 2; - - _groupCounter = _groupCounter + 1; - - } while (_groupCounter < _groupCount); - } - - _ptrGroupCount = _ptrGroupCount + 2; - - } while ((int)_ptrGroupCount < 0xb42a2c); + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; + + int destIndex = 0; + for (int i = 0; i < 11; i++) { + int tribeType = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType; + int tribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeCount; + if (tribeType == 18 || tribeType == 190 || tribeType == 15) + continue; + + for (int j = 0; j < tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeType + j]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[j + tribeType]) + continue; + + DAT_TribesState::instance.tribes[tribeID].unitStance = (char)(SEC_RNG::instance.currentNumber2 & 1); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, + DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex].xOffset, + DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex].yOffset, + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + destIndex++; + } } - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9abd77133..8c67d19ee 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35337,7 +35337,7 @@ SHC_3BB0A8C1_0x004CE930 | 0.0% | Pending SHC_3BB0A8C1_0x004CEA50 | 92.7% | Reimplemented functionally, stack ordering problem -SHC_3BB0A8C1_0x004CEB50 | 0.0% | Pending +SHC_3BB0A8C1_0x004CEB50 | 98.8% | Reimplemented SHC_3BB0A8C1_0x004CEB80 | 0.0% | Pending From 012735a3dcdd3546a15144d6e1b414fc0dffe497 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:35:33 +0200 Subject: [PATCH 136/242] reimplement: SHC_3BB0A8C1_0x004CF920 96.88% Reimplemented --- .../AI/AICState/giveSomeRaidCommand.cpp | 67 +++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 25 insertions(+), 44 deletions(-) diff --git a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp index 7cd54fd27..71c020461 100644 --- a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp +++ b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp @@ -11,51 +11,32 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - // FUNCTION: STRONGHOLDCRUSADER 0x004CF920 - undefined4 AICState ::giveSomeRaidCommand(int tribeIndex, int tribeType) - + undefined4 AICState::giveSomeRaidCommand(int tribeIndex, int tribeType) { - int _tribeOffset = tribeIndex * 0x334; - int _attacked = DAT_TribesState::instance.tribes[tribeIndex].owner; - int _targetBuildingID = (int)DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID; - - if (tribeType != 0xba && tribeType != 0x12 && tribeType != 0xe && tribeType != 0xd) { - - if (_targetBuildingID != 0 - && DAT_BuildingsState::instance.buildings[_targetBuildingID].uid - == DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID - && DAT_BuildingsState::instance.buildings[_targetBuildingID].fireDuration == 0) { - return (undefined4)(1); - } - - int _attackedPlayerID = DAT_GameState::instance.playerDataArray[_attacked].attackedPlayerID; - - DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = 0; - - int _chosenBuildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)(_attackedPlayerID); - - if (_chosenBuildingID != 0) { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::queueDisbandAndAttackCommand4Params, - DAT_UnitsState::ptr)(tribeIndex, 9, (undefined4)((int)(_chosenBuildingID)), - (undefined4)((int)(DAT_BuildingsState::instance.buildings[_chosenBuildingID].uid))); - - // Store UID before targetBuildingID (matching orig order) - DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID - = DAT_BuildingsState::instance.buildings[_chosenBuildingID].uid; - - DAT_TribesState::instance.tribes[tribeIndex].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - - DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = (short)_chosenBuildingID; - - return (undefined4)(1); - } - } - - return (undefined4)(0); + int owner = DAT_TribesState::instance.tribes[tribeIndex].owner; + int targetBuildingID = DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID; + if (tribeType == 186 || tribeType == 18 || tribeType == 14 || tribeType == 13) + return 0; + + if (targetBuildingID != 0 + && DAT_BuildingsState::instance.buildings[targetBuildingID].uid + == DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID + && DAT_BuildingsState::instance.buildings[targetBuildingID].fireDuration == 0) + return 1; + + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = 0; + int buildingID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, + this)(DAT_GameState::instance.playerDataArray[owner].attackedPlayerID); + if (buildingID == 0) + return 0; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::queueDisbandAndAttackCommand4Params, DAT_UnitsState::ptr)( + tribeIndex, 9, buildingID, DAT_BuildingsState::instance.buildings[buildingID].uid); + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID = DAT_BuildingsState::instance.buildings[buildingID].uid; + DAT_TribesState::instance.tribes[tribeIndex].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = buildingID; + return 1; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8c67d19ee..3e2b6cbe6 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35379,7 +35379,7 @@ SHC_3BB0A8C1_0x004CF7F0 | 0.0% | Pending SHC_3BB0A8C1_0x004CF870 | 100.0% | Reimplemented, for-loop didn't work -SHC_3BB0A8C1_0x004CF920 | 0.0% | Pending +SHC_3BB0A8C1_0x004CF920 | 96.9% | Reimplemented SHC_3BB0A8C1_0x004CFA10 | 0.0% | Pending From c9a7aa873b3d546a7a0e3f537d31b1cf14fdae3a Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:35:34 +0200 Subject: [PATCH 137/242] reimplement: SHC_3BB0A8C1_0x004CD8F0 74.19% Register allocation differs --- .../AICState/giveMoveCommandToSortieUnits.cpp | 89 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 40 insertions(+), 51 deletions(-) diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp index 06017cd79..0c4613340 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp @@ -2,6 +2,7 @@ #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" +#include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" @@ -14,68 +15,56 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - // FUNCTION: STRONGHOLDCRUSADER 0x004CD8F0 - void AICState ::giveMoveCommandToSortieUnits(int playerID) + void AICState::giveMoveCommandToSortieUnits(int playerID) { - int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType == 0) + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) return; - int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xa7]; - if (_tribeID == 0) + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[167]; + int aicIndex = aiType - 1; + if (tribeID == 0) return; - if (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa7]) + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[167]) return; - if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 + -1) + if (DAT_TribesState::instance.tribes[tribeID].size + < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 - 1) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::syncBehaviourType7UnitTribes, this)(playerID); - if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { - // nervous: send to keep then set stance - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); - DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - return; - } + int targetUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0) { + if (DAT_TribesState::instance.tribes[tribeID].size < this->aics[aicIndex].SortieUnitMeleeMin) { + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + return; + } - if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x154)) { - // tribe too small: just set stance - DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - return; - } - - int _unitID = DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitID; - int iVar1; - if (((_unitID != 0) - && (DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitUID - == DAT_UnitsState::instance.units[_unitID].uid)) - && (iVar1 = MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, - DAT_PathFindingState::ptr)(playerID, - (dword)((int)((int)(short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance - .units[DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID] - .tile])), - (dword)((int)((int)(short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_UnitsState::instance.units[_unitID].tile])), - 0), - iVar1 != 0)) { - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)(_tribeID); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - _tribeID, (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), - (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), 0, 0, - OpenSHC::Map::Units::Instructions::UMSE_0); - DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - return; + int unitID = DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitID; + if (unitID != 0 + && DAT_GameState::instance.playerDataArray[playerID].lastEncounteredTroopUnitUID + == DAT_UnitsState::instance.units[unitID].uid + && MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, + (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[targetUnitID] + .tile], + (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[unitID].tile], + 0) + != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, + DAT_TribesState::ptr)(tribeID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, DAT_UnitsState::instance.units[unitID].x, DAT_UnitsState::instance.units[unitID].y, 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + return; + } } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); - DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3e2b6cbe6..4c7f4f561 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35281,7 +35281,7 @@ SHC_3BB0A8C1_0x004CD690 | 0.0% | Pending SHC_3BB0A8C1_0x004CD7B0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CD8F0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CD8F0 | 74.2% | Register allocation differs SHC_3BB0A8C1_0x004CDA50 | 0.0% | Pending From 98a44a0c14f7e843a8470b52814fa661ddc90c96 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:42:06 +0200 Subject: [PATCH 138/242] reimplement: SHC_3BB0A8C1_0x004CB120 100.00% Reimplemented --- src/OpenSHC/AI/AICState/getAIBuildInterval.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/OpenSHC/AI/AICState/getAIBuildInterval.cpp b/src/OpenSHC/AI/AICState/getAIBuildInterval.cpp index e77ab3b46..de9383a30 100644 --- a/src/OpenSHC/AI/AICState/getAIBuildInterval.cpp +++ b/src/OpenSHC/AI/AICState/getAIBuildInterval.cpp @@ -1,4 +1,4 @@ -#include "../AICState.hpp"" +#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -8,14 +8,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB120 int AICState::getAIBuildInterval(int playerID) - { - int const aiType = DAT_GameState::ptr->playerDataArray[playerID].aiType; - if (aiType == AITA_NULL) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) return 0; - } - - return this->aics[(aiType - 1)].buildInterval; + return this->aics[aiType - 1].buildInterval; } } } From 11ce340d63159195c39ac0b12cd4c9e27bd9ba5a Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:42:06 +0200 Subject: [PATCH 139/242] reimplement: SHC_3BB0A8C1_0x004CB150 100.00% Reimplemented --- src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp | 9 +++------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp b/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp index d20a9e2f9..5ab4f3163 100644 --- a/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp +++ b/src/OpenSHC/AI/AICState/getResourceRebuildDelay.cpp @@ -8,14 +8,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB150 int AICState::getResourceRebuildDelay(int playerID) - { - int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (aiType == AITA_NULL) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) return 0; - } - - return this->aics[(aiType - 1)].resourceRebuildDelay; + return this->aics[aiType - 1].resourceRebuildDelay; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4c7f4f561..243b8cbb1 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34203,7 +34203,7 @@ SHC_3BB0A8C1_0x004CB060 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB120 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CB150 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB150 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB180 | 0.0% | Pending From aaeafcb105212f7ed318843f0c547b9a50c18d41 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:42:07 +0200 Subject: [PATCH 140/242] reimplement: SHC_3BB0A8C1_0x004D12A0 100.00% Reimplemented --- .../getCurrentDesiredAttackRaidUnitCount.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp b/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp index b36972206..c4ad3be31 100644 --- a/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp +++ b/src/OpenSHC/AI/AICState/getCurrentDesiredAttackRaidUnitCount.cpp @@ -11,14 +11,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D12A0 int AICState::getCurrentDesiredAttackRaidUnitCount(int aiType, int playerID) { - if (((DAT_GameCore::instance.gameMode_2 == Game::GM_SKIRMISH_AND_MULTIPLAYER) - && (DAT_GameCore::instance.isSkirmishTrail == TRUE)) - && (DAT_GameCore::instance.currentTrailType == Game::TT_EXTREME)) { - return (int)((DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter - + this->aics[aiType].RaidUnitsBase) - * 4) - / 3; - } + if (DAT_GameCore::instance.gameMode_2 == Game::GM_SKIRMISH_AND_MULTIPLAYER + && DAT_GameCore::instance.isSkirmishTrail == TRUE + && DAT_GameCore::instance.currentTrailType == Game::TT_EXTREME) + return (DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + + this->aics[aiType].RaidUnitsBase) + * 4 / 3; return DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter + this->aics[aiType].RaidUnitsBase; } From d86decda4af02a0e41d965c98f5f64c9c78734e8 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:42:07 +0200 Subject: [PATCH 141/242] reimplement: SHC_3BB0A8C1_0x004CC250 94.25% Register scheduling differs --- .../getUnitTypeForUnitBehaviourType.cpp | 131 +++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 35 insertions(+), 98 deletions(-) diff --git a/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp b/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp index 2314024f7..143bed0a2 100644 --- a/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp +++ b/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp @@ -1,7 +1,6 @@ #include "../AICState.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/AI/AIUnitBehaviourType.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" @@ -10,109 +9,47 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - using OpenSHC::AI::AIUnitBehaviourType; - using OpenSHC::Map::Units::UnitType; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CC250 - UnitType AICState ::getUnitTypeForUnitBehaviourType(int playerID, AIUnitBehaviourType unitBehaviourType) - + UnitType AICState::getUnitTypeForUnitBehaviourType(int playerID, AIUnitBehaviourType unitBehaviourType) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) + return (UnitType)0; + int aicIndex = aiType - 1; - AITypeInt AVar1; - - int iVar2; - - UnitType UVar3; - - AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) { - - return ((UnitType)0); - } - - if (unitBehaviourType == OpenSHC::AI::AIUBT_ENGINEERING) { - + if (unitBehaviourType == OpenSHC::AI::AIUBT_ENGINEERING) return OpenSHC::Map::Units::UT_E_ENGINEER; - } - - if (unitBehaviourType == OpenSHC::AI::AIUBT_DIGGING) { - - return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttDiggingUnit); - } - - if (unitBehaviourType == OpenSHC::AI::AIUBT_ASSASSINATION) { - + if (unitBehaviourType == OpenSHC::AI::AIUBT_DIGGING) + return (UnitType)this->aics[aicIndex].AttDiggingUnit; + if (unitBehaviourType == OpenSHC::AI::AIUBT_ASSASSINATION) return OpenSHC::Map::Units::UT_A_ASSASSIN; - } - - if (unitBehaviourType == OpenSHC::AI::AIUBT_ATTUNIT2) { - - return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnit2); - } - - if (unitBehaviourType == OpenSHC::AI::AIUBT_LADDERING) { - + if (unitBehaviourType == OpenSHC::AI::AIUBT_ATTUNIT2) + return (UnitType)this->aics[aicIndex].AttUnit2; + if (unitBehaviourType == OpenSHC::AI::AIUBT_LADDERING) return OpenSHC::Map::Units::UT_E_LADDER; - } - - if (unitBehaviourType == OpenSHC::AI::AIUBT_TUNNELING) { - + if (unitBehaviourType == OpenSHC::AI::AIUBT_TUNNELING) return OpenSHC::Map::Units::UT_TUNNELER; - } - - if (unitBehaviourType == OpenSHC::AI::AIUBT_PATROLLING) { - - return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitPatrol); - } - - if (unitBehaviourType == OpenSHC::AI::AIUBT_BACKUPING) { - - return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitBackup); - } - - if (unitBehaviourType == OpenSHC::AI::AIUBT_ENGAGING) { - - return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitEngage); - } - - if (unitBehaviourType == OpenSHC::AI::AIUBT_SIEGEDEFENSE) { - - return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitSiegeDef); - } - - if (unitBehaviourType == OpenSHC::AI::AIUBT_ATTUNITMAIN) { - - if (*(int*)((int)this->aics + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex * 4 - + AVar1 * 0x2a4 + -0x1c) - == 0) { - - DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = 0; - } - - if (3 < DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex) { - - DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = 0; - } - - iVar2 = DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex; - - /* - AttUnitMain[] */ - - UVar3 = *(UnitType*)((int)this->aics + AVar1 * 0x2a4 + iVar2 * 4 + -0x1c); - - DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = iVar2 + 1; - - return UVar3; - } - - return (UnitType)(this->aics[AVar1 + ~OpenSHC::AI::AIT_NULL].AttUnitMain1); + if (unitBehaviourType == OpenSHC::AI::AIUBT_PATROLLING) + return (UnitType)this->aics[aicIndex].AttUnitPatrol; + if (unitBehaviourType == OpenSHC::AI::AIUBT_BACKUPING) + return (UnitType)this->aics[aicIndex].AttUnitBackup; + if (unitBehaviourType == OpenSHC::AI::AIUBT_ENGAGING) + return (UnitType)this->aics[aicIndex].AttUnitEngage; + if (unitBehaviourType == OpenSHC::AI::AIUBT_SIEGEDEFENSE) + return (UnitType)this->aics[aicIndex].AttUnitSiegeDef; + if (unitBehaviourType != OpenSHC::AI::AIUBT_ATTUNITMAIN) + return (UnitType)this->aics[aicIndex].AttUnitMain1; + + if ((&this->aics[aicIndex].AttUnitMain1)[DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex] + == 0) + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = 0; + if (DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex >= 4) + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = 0; + + int choice = DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex; + UnitType unitType = (UnitType)(&this->aics[aicIndex].AttUnitMain1)[choice]; + DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = choice + 1; + return unitType; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 243b8cbb1..b04b80fa0 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34863,7 +34863,7 @@ SHC_3BB0A8C1_0x004CC000 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CC070 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CC250 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC250 | 94.2% | Register scheduling differs SHC_3BB0A8C1_0x004CC390 | 0.0% | Pending From acb0b329fbf94046d260456f689472ba6bb044dc Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:42:07 +0200 Subject: [PATCH 142/242] reimplement: SHC_3BB0A8C1_0x004CCAF0 68.12% Register allocation differs --- .../AI/AICState/getSmallestPatrolTribe.cpp | 68 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 30 insertions(+), 40 deletions(-) diff --git a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp index 8412ceff5..6edf8182f 100644 --- a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp +++ b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp @@ -9,48 +9,38 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CCAF0 - int AICState ::getSmallestPatrolTribe(int playerID, int tribeCount) + int AICState::getSmallestPatrolTribe(int playerID, int tribeCount) { - int _selectedTribeID = 0; - int _tribeNumber = 0; - int _selectedTribeNumber = 0; - short _lowestTribeUnitCount = 1000; - - if (0 < tribeCount) { - short* _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; - do { - int _tribeID = (int)*_pTribeID; - if ((_tribeID == 0) - || (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeNumber + 0xaa])) { - _selectedTribeID = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - _selectedTribeNumber = _tribeNumber; - DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_selectedTribeNumber + 0xaa] - = (short)_selectedTribeID; - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_selectedTribeNumber + 0xaa] - = DAT_TribesState::instance.tribes[_selectedTribeID].uid; - return _selectedTribeID; - } - short _tribeSize = DAT_TribesState::instance.tribes[_tribeID].size; - if (_tribeSize < _lowestTribeUnitCount) { - _selectedTribeID = _tribeID; - _selectedTribeNumber = _tribeNumber; - _lowestTribeUnitCount = _tribeSize; - } - _tribeNumber = _tribeNumber + 1; - _pTribeID = _pTribeID + 1; - } while (_tribeNumber < tribeCount); - - if (_selectedTribeID != 0) { - DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_selectedTribeNumber + 0xaa] - = (short)_selectedTribeID; - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_selectedTribeNumber + 0xaa] - = DAT_TribesState::instance.tribes[_selectedTribeID].uid; - return _selectedTribeID; + int selectedTribeID = 0; + int selectedIndex = 0; + int lowestSize = 1000; + + for (int i = 0; i < tribeCount; i++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[170 + i]; + if (tribeID == 0 + || DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[i + 170]) { + selectedTribeID + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)( + playerID); + selectedIndex = i; + break; + } + + if (DAT_TribesState::instance.tribes[tribeID].size < lowestSize) { + lowestSize = DAT_TribesState::instance.tribes[tribeID].size; + selectedTribeID = tribeID; + selectedIndex = i; } } - return 0; + + if (selectedTribeID == 0) + return 0; + + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[selectedIndex + 170] = selectedTribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[selectedIndex + 170] + = DAT_TribesState::instance.tribes[selectedTribeID].uid; + return selectedTribeID; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b04b80fa0..1cb73e76a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34889,7 +34889,7 @@ SHC_3BB0A8C1_0x004CC910 | 0.0% | Pending SHC_3BB0A8C1_0x004CC990 | 40.90% | Reimplemented functionally, different register usage -SHC_3BB0A8C1_0x004CCAF0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CCAF0 | 68.1% | Register allocation differs SHC_3BB0A8C1_0x004CCBE0 | 0.0% | Pending From eb8b1715518b7270f9c4012b58a4d3251d2925f0 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:42:08 +0200 Subject: [PATCH 143/242] reimplement: SHC_3BB0A8C1_0x004CDBC0 65.04% Loop counter spilled in orig --- .../getTargetableBuildingForPlayerID.cpp | 127 ++++-------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 30 insertions(+), 99 deletions(-) diff --git a/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp index b4171cdca..b997e2dee 100644 --- a/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp +++ b/src/OpenSHC/AI/AICState/getTargetableBuildingForPlayerID.cpp @@ -1,8 +1,5 @@ #include "../AICState.func.hpp" -#include "OpenSHC/Game/Player/PlayerData.hpp" -#include "OpenSHC/Map/Buildings/BuildingTypeInt.hpp" - #include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" @@ -10,106 +7,40 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Game::Player::PlayerData; - using OpenSHC::Map::Buildings::BuildingTypeInt; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CDBC0 - int AICState ::getTargetableBuildingForPlayerID(int playerID, int param_2) - + int AICState::getTargetableBuildingForPlayerID(int playerID, int param_2) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == 0) + return 0; + int outerPatrolGroupsCount = this->aics[aiType - 1].OuterPatrolGroupsCount; + if (outerPatrolGroupsCount <= 0) + return 0; + int tracker = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + if (tracker <= 0) + return 0; - int* piVar1; - - PlayerData* pPVar2; - - int iVar3; - - int _candidateBuilding; - - BuildingTypeInt* _pTargets; - - int _index; - - int _aiType; - - int _outerPatrolGroupsCount; - - int _tracker; - - iVar3 = playerID; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if ((_aiType != 0) - && (_outerPatrolGroupsCount = *(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x174), - 0 < _outerPatrolGroupsCount)) { - - _tracker = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; - - if (0 < _tracker) { - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID].someCounter2; - - *piVar1 = *piVar1 + 1; - - if (_tracker <= DAT_GameState::instance.playerDataArray[playerID].someCounter2) { - - DAT_GameState::instance.playerDataArray[playerID].someCounter2 = 0; - } - - pPVar2 = DAT_GameState::instance.playerDataArray + playerID; - - playerID = 0; - - _index = ((_tracker / _outerPatrolGroupsCount) * param_2 + pPVar2->someCounter2) % _tracker; - - if (0 < _tracker) { - - do { - - _candidateBuilding - = (int)DAT_GameState::instance.playerDataArray[iVar3].top100TargetableBuildings[_index]; - - _index = _index + 1; - - if (_tracker <= _index) { - - _index = 0; - } - - if (_candidateBuilding != 0) { - - _pTargets = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1; - - do { - - if ((int)(short)DAT_BuildingsState::instance.buildings[_candidateBuilding].buildingType - == *_pTargets) { - - return _candidateBuilding; - } - - _pTargets = _pTargets + 1; - - /* - Iterates only over resource buildings, so if resource building, return - */ - - } while ((int)_pTargets < 0xb427c8); - } - - playerID = playerID + 1; - - } while (playerID < _tracker); - } + DAT_GameState::instance.playerDataArray[playerID].someCounter2++; + if (DAT_GameState::instance.playerDataArray[playerID].someCounter2 >= tracker) + DAT_GameState::instance.playerDataArray[playerID].someCounter2 = 0; + + int index = (tracker / outerPatrolGroupsCount * param_2 + + DAT_GameState::instance.playerDataArray[playerID].someCounter2) + % tracker; + for (int i = 0; i < tracker; i++) { + int buildingID = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings[index]; + index++; + if (index >= tracker) + index = 0; + if (buildingID == 0) + continue; + + for (int j = 0; j < 8; j++) { + if (DAT_BuildingsState::instance.buildings[buildingID].buildingType + == DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1[j]) + return buildingID; } - - return 0; } - return 0; } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1cb73e76a..2cc9b300e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35289,7 +35289,7 @@ SHC_3BB0A8C1_0x004CDAB0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CDB20 | 0.0% | Pending -SHC_3BB0A8C1_0x004CDBC0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CDBC0 | 65.0% | Loop counter spilled in orig SHC_3BB0A8C1_0x004CDCA0 | 100.0% | Reimplemented From 1dd28062fa11e02766d84a378b240b6052079949 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:50:15 +0200 Subject: [PATCH 144/242] missing function: 0x004CCBF0 --- .../AI/AICState/getDefensiveTribeForUnit.cpp | 81 +++++++------------ 1 file changed, 31 insertions(+), 50 deletions(-) diff --git a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp index 24934a4df..5d2c6f9a5 100644 --- a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp +++ b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp @@ -1,6 +1,5 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AICState.hpp" -#include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" @@ -13,59 +12,41 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CCBF0 int AICState::getDefensiveTribeForUnit(int playerID, int unitID) { - int _index = 0; - int _unitType = (int)(short)DAT_UnitsState::instance.units[unitID].unitType; - int _unitType2; - do { - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index]) - || (_unitType2 = (int)(short)DAT_UnitsState::instance.units[unitID].unitTypeToChangeInto, - _unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index])) + int index; + for (index = 0; index < 20; index++) { + if (DAT_UnitsState::instance.units[unitID].unitType + == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[index] + || DAT_UnitsState::instance.units[unitID].unitTypeToChangeInto + == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[index]) break; - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1]) - || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 1])) { - _index = _index + 1; break; - } - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2]) - || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 2])) { - _index = _index + 2; break; - } - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3]) - || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 3])) { - _index = _index + 3; break; - } - if ((_unitType == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4]) - || (_unitType2 == DAT_SkirmishDefinedData::instance.DefenseTribesUnitTypeArray[_index + 4])) { - _index = _index + 4; break; - } - _index = _index + 5; - } while (_index < 0x14); + } - int _tribeIndex; - if (_index < 1) { - _tribeIndex = 0xb4; - } else if (_index < 2) { - _tribeIndex = 0xb5; - } else if (_index < 7) { - _tribeIndex = 0xb6; - } else if (_index < 0xc) { - _tribeIndex = 0xb7; - } else if (_index < 0xf) { - _tribeIndex = 0xb8; - } else if (_index < 0x14) { - _tribeIndex = 0xb9; - } else { + int tribeIndex; + if (index < 1) + tribeIndex = 180; + else if (index < 2) + tribeIndex = 181; + else if (index < 7) + tribeIndex = 182; + else if (index < 12) + tribeIndex = 183; + else if (index < 15) + tribeIndex = 184; + else if (index < 20) + tribeIndex = 185; + else return 0; - } - short* _pTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeIndex; - int _tribeID = (int)*_pTribeID; - if ((_tribeID == 0) || (DAT_TribesState::instance.tribes[_tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex])) { - _tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; - *_pTribeID = (short)_tribeID; - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_tribeIndex] = _tribeUID; - } - return _tribeID; + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeIndex]; + if (tribeID != 0 + && DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[tribeIndex]) + return tribeID; + + tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeIndex] = tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[tribeIndex] = DAT_TribesState::instance.tribes[tribeID].uid; + return tribeID; } } } From 1c7cdd3c7a5f2d714dd18d38e31e68747f1f67ed Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:55:06 +0200 Subject: [PATCH 145/242] reimplement: SHC_3BB0A8C1_0x004CD160 91.67% Register allocation differs --- src/OpenSHC/AI/AICState/digNearestMoat.cpp | 59 +++++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/OpenSHC/AI/AICState/digNearestMoat.cpp b/src/OpenSHC/AI/AICState/digNearestMoat.cpp index 24e5222f4..da6dac8af 100644 --- a/src/OpenSHC/AI/AICState/digNearestMoat.cpp +++ b/src/OpenSHC/AI/AICState/digNearestMoat.cpp @@ -16,36 +16,37 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CD160 void AICState::digNearestMoat(int playerID) { - int iVar1; - BOOLEnum tile; - int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10]; - if ((((tribeID != 0) - && (DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10])) - && (0 < DAT_TribesState::instance.tribes[tribeID].size)) - && (DAT_TribesState::instance.tribes[tribeID].percentageSomething < 0x51)) { - iVar1 = MACRO_CALL_MEMBER(Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)( - playerID); - if (iVar1 < 1) { - MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); - return; - } - iVar1 = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; - tile = MACRO_CALL_MEMBER(Map::TileMapState_Func::findNearestFriendlyMoatTileForDigging, - DAT_TileMapState::ptr)(playerID, iVar1, 1); - if (-1 < (int)tile) { - MACRO_CALL_MEMBER(Map::TileMapState_Func::setXYBasedOnMoatID, DAT_TileMapState::ptr)(tile, 1, - (int)DAT_UnitsState::instance.units[iVar1].x, (int)DAT_UnitsState::instance.units[iVar1].y); - iVar1 = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::updateTribeRallyFlags, DAT_TribesState::ptr)( - tribeID); - if (iVar1 == 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( - tribeID, Map::Units::UIT_DIG_MOAT, DAT_TileMapState::instance.ALG_MoatXResult, - DAT_TileMapState::instance.ALG_MoatYResult, 0); - DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_STAND_GROUND; - } - } + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10]; + if (tribeID == 0) + return; + if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10]) + return; + if (DAT_TribesState::instance.tribes[tribeID].size <= 0) + return; + if (DAT_TribesState::instance.tribes[tribeID].percentageSomething > 80) + return; + + if (MACRO_CALL_MEMBER(Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)(playerID) + <= 0) { + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); + return; } + + int targetUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + int tile = MACRO_CALL_MEMBER(Map::TileMapState_Func::findNearestFriendlyMoatTileForDigging, DAT_TileMapState::ptr)( + playerID, targetUnitID, 1); + if (tile <= -1) + return; + + MACRO_CALL_MEMBER(Map::TileMapState_Func::setXYBasedOnMoatID, DAT_TileMapState::ptr)( + tile, 1, DAT_UnitsState::instance.units[targetUnitID].x, DAT_UnitsState::instance.units[targetUnitID].y); + if (MACRO_CALL_MEMBER(Map::Units::TribesState_Func::updateTribeRallyFlags, DAT_TribesState::ptr)(tribeID) != 0) + return; + + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(tribeID, + Map::Units::UIT_DIG_MOAT, DAT_TileMapState::instance.ALG_MoatXResult, DAT_TileMapState::instance.ALG_MoatYResult, + 0); + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_STAND_GROUND; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 2cc9b300e..4d93de8de 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35269,7 +35269,7 @@ SHC_3BB0A8C1_0x004CD0C0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CD110 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CD160 | 0.0% | Pending +SHC_3BB0A8C1_0x004CD160 | 91.7% | Register allocation differs SHC_3BB0A8C1_0x004CD250 | 0.0% | Pending From f2c3ddddf58625c49ef6afb1271423d5d2c61d56 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:55:06 +0200 Subject: [PATCH 146/242] reimplement: SHC_3BB0A8C1_0x004CFB20 97.83% Reimplemented --- .../AI/AICState/disbandAIPlayerSiegeUnits.cpp | 76 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 54 deletions(-) diff --git a/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp b/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp index c6619d6dd..19151eaa5 100644 --- a/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/disbandAIPlayerSiegeUnits.cpp @@ -2,11 +2,9 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/States/UnitState.hpp" -#include "OpenSHC/Map/Units/Unit.hpp" #include "OpenSHC/Map/Units/UnitInstructionType.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Map/Units/UnitTypeShort.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -14,59 +12,31 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Map::Units::Unit; - using OpenSHC::Map::Units::UnitInstructionType; - using OpenSHC::Map::Units::UnitLogicState; - using OpenSHC::Map::Units::UnitType; - using OpenSHC::Map::Units::UnitTypeShort; - using OpenSHC::Map::Units::States::UnitState; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CFB20 - void AICState ::disbandAIPlayerSiegeUnits(int playerID) - + void AICState::disbandAIPlayerSiegeUnits(int playerID) { - - Unit* _unit; - - int _unitIDCounter; - - UnitTypeShort _unitType; - - _unitIDCounter = 1; - - _unit = &DAT_UnitsState::instance.units[1]; - - do { - - if ((((_unit->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) && (_unit->owner == playerID)) - && (((_unitType = _unit->unitType, - _unitType == OpenSHC::Map::Units::UT_S_CATAPULT - || (((_unitType == OpenSHC::Map::Units::UT_S_TREBUCHET - || (_unitType == OpenSHC::Map::Units::UT_S_TOWER)) - || (_unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM)))) - || ((_unitType == OpenSHC::Map::Units::UT_S_SHIELD - || (_unitType == OpenSHC::Map::Units::UT_S_FBALLISTA)))))) - && ((_unit->unknownSiegeTentRelated02 == 3 && (_unit->aiUnitBehaviourType != 0x15)))) { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( - (int)_unit->tribeID, OpenSHC::Map::Units::UIT_EXIT_SIEGE_EQUIPMENT, _unitIDCounter, _unit->uid, 0); - - /* - shouldn't logicalState be set to something too? */ - - (_unit->state).generic = OpenSHC::Map::Units::States::US_DISAPPEAR; - } - - _unit = _unit + 0x248; - - _unitIDCounter = _unitIDCounter + 1; - - } while ((int)_unit < 0x165141a); - - return; + for (int unitID = 1; unitID < 2500; unitID++) { + if (DAT_UnitsState::instance.units[unitID].logicalState == OpenSHC::Map::Units::ULS_INVISIBLE) + continue; + if (DAT_UnitsState::instance.units[unitID].owner != playerID) + continue; + if (DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_S_CATAPULT + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_S_TREBUCHET + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_S_TOWER + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_S_BATTERINGRAM + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_S_SHIELD + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_S_FBALLISTA) + continue; + if (DAT_UnitsState::instance.units[unitID].unknownSiegeTentRelated02 != 3) + continue; + if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType == 21) + continue; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( + DAT_UnitsState::instance.units[unitID].tribeID, OpenSHC::Map::Units::UIT_EXIT_SIEGE_EQUIPMENT, unitID, + DAT_UnitsState::instance.units[unitID].uid, 0); + DAT_UnitsState::instance.units[unitID].state.generic = OpenSHC::Map::Units::States::US_DISAPPEAR; + } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4d93de8de..31e47cb44 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35383,7 +35383,7 @@ SHC_3BB0A8C1_0x004CF920 | 96.9% | Reimplemented SHC_3BB0A8C1_0x004CFA10 | 0.0% | Pending -SHC_3BB0A8C1_0x004CFB20 | 0.0% | Pending +SHC_3BB0A8C1_0x004CFB20 | 97.8% | Reimplemented SHC_3BB0A8C1_0x004CFBC0 | 0.0% | Pending From 9c0e89caca138b4accf6c4ce706ec81c8a0bb2da Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:55:06 +0200 Subject: [PATCH 147/242] reimplement: SHC_3BB0A8C1_0x004CE930 86.96% Register allocation differs --- ...ndAttackTribePositionAndPathToDefenses.cpp | 76 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 34 insertions(+), 44 deletions(-) diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp index aae1a994e..fa83afc50 100644 --- a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -13,56 +13,46 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CE930 - void AICState ::findAttackTribePositionAndPathToDefenses(int playerID) + void AICState::findAttackTribePositionAndPathToDefenses(int playerID) { - uint local_8 = 0; - uint local_4 = 0; - int* local_c = &DAT_SkirmishDefinedData::instance.MaxAttackTribes1[0].tribeCount; + int x = 0; + int y = 0; + for (int i = 0; i < 11; i++) { + int targetUnitID = 0; + for (int j = 0; j < DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType + j]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID] + .aiTribeUIDs[j + DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType]) + continue; - bool _found = false; - do { - int iVar2 = 0; - if (0 < *local_c) { - short* psVar3 - = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + (*(int (*)[2])(local_c + -1))[0]; - do { - int iVar1 = (int)*psVar3; - if ((iVar1 != 0) - && (DAT_TribesState::instance.tribes[iVar1].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[iVar2 + (*(int (*)[2])(local_c + -1))[0]])) { - iVar2 = (int)DAT_TribesState::instance.tribes[iVar1].selectionTargetUnitID; - local_8 = (uint)DAT_UnitsState::instance.units[iVar2].x; - local_4 = (uint)DAT_UnitsState::instance.units[iVar2].y; - if (iVar2 != 0) { - _found = true; - break; - } - break; - } - iVar2 = iVar2 + 1; - psVar3 = psVar3 + 1; - } while (iVar2 < *local_c); + targetUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + x = DAT_UnitsState::instance.units[targetUnitID].x; + y = DAT_UnitsState::instance.units[targetUnitID].y; + break; } - if (_found) + if (targetUnitID != 0) break; - local_c = local_c + 2; - } while ((int)local_c <= 0xb42a2b); + } DAT_GameState::instance.playerDataArray[playerID].someTile = 0; + if (x == 0) + return; - if (local_8 != 0) { - int _tile = MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::tracePathToFriendlyDefensesAndReturnTileUnk, - DAT_PathFindingState::ptr)(playerID, local_8, local_4); - if (0 < _tile) { - short _y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; - DAT_GameState::instance.playerDataArray[playerID].someTile = _tile; - int iVar2 = DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; - DAT_GameState::instance.playerDataArray[playerID].someY = (int)_y; - DAT_GameState::instance.playerDataArray[playerID].someX = _tile - iVar2; - } - } + int tile = MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::tracePathToFriendlyDefensesAndReturnTileUnk, + DAT_PathFindingState::ptr)(playerID, x, y); + if (tile <= 0) + return; + + short tileY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]; + DAT_GameState::instance.playerDataArray[playerID].someTile = tile; + DAT_GameState::instance.playerDataArray[playerID].someY = tileY; + DAT_GameState::instance.playerDataArray[playerID].someX + = tile - DAT_ViewportRenderState::instance.translationMatrix[tileY].addXgetTile; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 31e47cb44..3101b6cbe 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35333,7 +35333,7 @@ SHC_3BB0A8C1_0x004CE860 | 0.0% | Pending SHC_3BB0A8C1_0x004CE890 | 0.0% | Pending -SHC_3BB0A8C1_0x004CE930 | 0.0% | Pending +SHC_3BB0A8C1_0x004CE930 | 87.0% | Register allocation differs SHC_3BB0A8C1_0x004CEA50 | 92.7% | Reimplemented functionally, stack ordering problem From c72a07219eaf50a0b75b723b7e1242ef02cd486b Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 14:55:07 +0200 Subject: [PATCH 148/242] reimplement: SHC_3BB0A8C1_0x004CC420 37.96% Loop strength reduction diff --- .../generateSiegeCreationInformation.cpp | 104 +++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 29 insertions(+), 77 deletions(-) diff --git a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp index de213a84a..e06149d2a 100644 --- a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp +++ b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp @@ -3,7 +3,6 @@ #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Game/GameMode.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Map/Units/UnitTypeShort.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -13,85 +12,38 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::Game::GameMode; - using OpenSHC::Map::Units::UnitType; - using OpenSHC::Map::Units::UnitTypeShort; - // FUNCTION: STRONGHOLDCRUSADER 0x004CC420 - void AICState ::generateSiegeCreationInformation(int playerID, int buildingID, int unitID) - + void AICState::generateSiegeCreationInformation(int playerID, int buildingID, int unitID) { - - UnitTypeShort UVar1; - - int iVar2; - - int _siegeIndex; - - int _engineIndexUnk; - - int _nextIndex; - - int _goal; - - if ((DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) - && (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != OpenSHC::Game::GM_SOLITARY)) { - - UVar1 = DAT_UnitsState::instance.units[unitID].unitType; - - if (UVar1 == OpenSHC::Map::Units::UT_S_TREBUCHET) { - - _siegeIndex = 2; - - } - - else { - - if (UVar1 != OpenSHC::Map::Units::UT_S_FBALLISTA) { - - return; - } - - _siegeIndex = 3; - } - - iVar2 = DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[_siegeIndex].slot; - - _goal = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[iVar2]; - - if (0 < _goal) { - - _engineIndexUnk = 0; - - while ((_nextIndex = _engineIndexUnk + 1, - *(int*)(playerID * 0x39f4 + iVar2 * 40 + 0x115eb14 + _engineIndexUnk * 4) <= 0 - || (buildingID - != *(int*)(playerID * 0x39f4 + 0x115f494 + (_engineIndexUnk + _siegeIndex * 5) * 0x14)))) { - - _engineIndexUnk = _nextIndex; - - if (_goal <= _nextIndex) { - - return; - } - } - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeIndex][_engineIndexUnk] - .unitID = unitID; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeIndex][_engineIndexUnk] - .uid = DAT_UnitsState::instance.units[unitID].uid; - - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeIndex][_engineIndexUnk] - .buildingID = 0; - } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; + if (DAT_GameSynchronyState::instance.currentGameMode == OpenSHC::Game::GM_SOLITARY) + return; + + int siegeIndex; + if (DAT_UnitsState::instance.units[unitID].unitType == OpenSHC::Map::Units::UT_S_TREBUCHET) + siegeIndex = 2; + else if (DAT_UnitsState::instance.units[unitID].unitType == OpenSHC::Map::Units::UT_S_FBALLISTA) + siegeIndex = 3; + else + return; + + int slot = DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].slot; + int locationCount = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[slot]; + int i; + for (i = 0; i < locationCount; i++) { + if (DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[slot][i] > 0 + && DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID + == buildingID) + break; } + if (i >= locationCount) + return; - return; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID = unitID; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid + = DAT_UnitsState::instance.units[unitID].uid; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID = 0; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3101b6cbe..e74b29250 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34867,7 +34867,7 @@ SHC_3BB0A8C1_0x004CC250 | 94.2% | Register scheduling differs SHC_3BB0A8C1_0x004CC390 | 0.0% | Pending -SHC_3BB0A8C1_0x004CC420 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC420 | 38.0% | Loop strength reduction diff SHC_3BB0A8C1_0x004CC520 | 0.0% | Pending From 51aaaee152e8c662b8871c6eed5a2f87ed5ea9fa Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:13:51 +0200 Subject: [PATCH 149/242] reimplement: SHC_3BB0A8C1_0x004CC000 92.86% Reimplemented --- src/OpenSHC/AI/AICState/buyGoods.cpp | 5 +++-- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/OpenSHC/AI/AICState/buyGoods.cpp b/src/OpenSHC/AI/AICState/buyGoods.cpp index 288fea7b5..479c46eb4 100644 --- a/src/OpenSHC/AI/AICState/buyGoods.cpp +++ b/src/OpenSHC/AI/AICState/buyGoods.cpp @@ -13,10 +13,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC000 BOOLEnum AICState::buyGoods(int playerID, ResourceType resourceType, int amount) { - int const cost = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::getBuyPrice, DAT_GameState::ptr)( + int cost = MACRO_CALL_MEMBER(Game::GameStateStructures_Func::getBuyPrice, DAT_GameState::ptr)( playerID, resourceType, amount); if (MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::processResourceGain, DAT_BuildingsState::ptr)( - playerID, resourceType, amount)) { + playerID, resourceType, amount) + != FALSE) { DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] -= cost; DAT_GameState::instance.playerDataArray[playerID].marketGold -= cost; MACRO_CALL_MEMBER(Game::GameStateStructures_Func::displayPlayerTradeVisualEffect, DAT_GameState::ptr)( diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e74b29250..8823a3f97 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34859,7 +34859,7 @@ SHC_3BB0A8C1_0x004CBE30 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CBFA0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CC000 | 100.0% | Reimplemented +SHC_3BB0A8C1_0x004CC000 | 92.9% | Reimplemented SHC_3BB0A8C1_0x004CC070 | 100.0% | Reimplemented From 1e2c7eb172602a306f065824fd9c7cb7c23495ce Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:13:51 +0200 Subject: [PATCH 150/242] reimplement: SHC_3BB0A8C1_0x004D39B0 96.63% Reimplemented --- src/OpenSHC/AI/AICState/buyRequiredGoods.cpp | 119 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 37 insertions(+), 84 deletions(-) diff --git a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp index 77dd56f18..8605948c5 100644 --- a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp +++ b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp @@ -2,10 +2,7 @@ #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/Game/Resources/ResourceType.hpp" -#include "OpenSHC/Game/Resources/ResourceTypeInt.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" @@ -13,91 +10,47 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - using OpenSHC::Game::Resources::ResourceType; - using OpenSHC::Game::Resources::ResourceTypeInt; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - // FUNCTION: STRONGHOLDCRUSADER 0x004D39B0 - void AICState ::buyRequiredGoods(int param_1) - + void AICState::buyRequiredGoods(int playerID) { - - AITypeInt AVar1; - - int amount; - - int playerID; - - int iVar2; - - BOOLEnum BVar3; - - ResourceTypeInt resourceType; - - playerID = param_1; - - AVar1 = DAT_GameState::instance.playerDataArray[param_1].aiType; - - if (AVar1 == OpenSHC::AI::AIT_NULL) { - + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) return; - } - - param_1 = 0; - - do { - - resourceType = DAT_SkirmishDefinedData::instance.ResourceAcquisitionPreferenceOrder[param_1]; - - if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0) || (0xb < param_1)) { - - if ((DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker != 0) - && (DAT_GameState::instance.playerDataArray[playerID].currentResources[2] < 20)) { - - resourceType = OpenSHC::Game::Resources::RT_WOOD; - } - - amount = DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType]; - - if ((amount != 0) - && ((((param_1 <= 3 - && (DAT_GameState::instance.playerDataArray[playerID].popularity - < *(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x18))) - || (0 < DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker)) - || (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)))) { - - iVar2 = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::getBuyPrice, DAT_GameState::ptr)( - playerID, (int)((int)(resourceType)), amount); - - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < iVar2) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::requestGoods, this)( - playerID, (ResourceType)((int)(resourceType)), amount * 2); - - } - - else { - - BVar3 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::buyGoods, this)( - playerID, (ResourceType)((int)(resourceType)), amount); - - if (BVar3 != FALSE) { - - DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType] = 0; - - return; - } - } - } + int aicIndex = aiType - 1; + + for (int i = 0; i < 25; i++) { + int resourceType = DAT_SkirmishDefinedData::instance.ResourceAcquisitionPreferenceOrder[i]; + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0 && i < 12) + continue; + + if (DAT_GameState::instance.playerDataArray[playerID].aiBuildingDestroyChoiceTracker != 0 + && DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_WOOD] < 20) + resourceType = Game::Resources::RT_WOOD; + + int amount = DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType]; + if (amount == 0) + continue; + if ((i > 3 + || DAT_GameState::instance.playerDataArray[playerID].popularity + >= this->aics[aicIndex].criticalPopularity) + && DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0 + && DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) + continue; + + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] + < MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::getBuyPrice, DAT_GameState::ptr)( + playerID, resourceType, amount)) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::requestGoods, this)( + playerID, (ResourceType)resourceType, amount * 2); + continue; } - param_1 = param_1 + 1; - - } while (param_1 < 25); - - return; + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::buyGoods, this)(playerID, (ResourceType)resourceType, amount) + != FALSE) { + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType] = 0; + return; + } + } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 8823a3f97..4612692ac 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35523,7 +35523,7 @@ SHC_3BB0A8C1_0x004D3940 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D3960 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D39B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D39B0 | 96.6% | Reimplemented SHC_3BB0A8C1_0x004D39F0 | 0.0% | Pending From 5e004e25061fe27917a1464172ea14bf36857a3d Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:13:51 +0200 Subject: [PATCH 151/242] reimplement: SHC_3BB0A8C1_0x004CD250 94.74% Reimplemented --- .../canNavigateUnitsFromTileToTargetTile.cpp | 13 ++++++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp index b68d96055..db81e30ae 100644 --- a/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp +++ b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp @@ -12,13 +12,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CD250 BOOLEnum AICState::canNavigateUnitsFromTileToTargetTile(int tribeID, int tile) { - int iVar1 = MACRO_CALL_MEMBER( - Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, - DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[tribeID].owner, - (int)(short)DAT_TileMapState::instance.PathConnectionLayer - [DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID].tile], - (int)(short)DAT_TileMapState::instance.PathConnectionLayer[tile], 0); - return (uint)(iVar1 != 0); + int owner = DAT_TribesState::instance.tribes[tribeID].owner; + int fromArea = (short)DAT_TileMapState::instance.PathConnectionLayer + [DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID].tile]; + return MACRO_CALL_MEMBER(Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(owner, fromArea, (short)DAT_TileMapState::instance.PathConnectionLayer[tile], 0) + != 0; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4612692ac..9e4745e45 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35271,7 +35271,7 @@ SHC_3BB0A8C1_0x004CD110 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CD160 | 91.7% | Register allocation differs -SHC_3BB0A8C1_0x004CD250 | 0.0% | Pending +SHC_3BB0A8C1_0x004CD250 | 94.7% | Reimplemented SHC_3BB0A8C1_0x004CD2A0 | 59.60% | Reimplemented functionally, code block ordering problem From 19d5677deca2cc61801f3fe839c65a6dec61882e Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:13:52 +0200 Subject: [PATCH 152/242] reimplement: SHC_3BB0A8C1_0x004CDB20 23.30% Loop/register structure differs --- ...mBuildingIDFromPlayersArrayOfBuildings.cpp | 89 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 26 insertions(+), 65 deletions(-) diff --git a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp index 0a150f5b5..ffc6b981f 100644 --- a/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp +++ b/src/OpenSHC/AI/AICState/chooseRandomBuildingIDFromPlayersArrayOfBuildings.cpp @@ -1,7 +1,5 @@ #include "../AICState.func.hpp" -#include "OpenSHC/Map/Buildings/BuildingTypeInt.hpp" - #include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" @@ -10,72 +8,35 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Map::Buildings::BuildingTypeInt; - // FUNCTION: STRONGHOLDCRUSADER 0x004CDB20 - int AICState ::chooseRandomBuildingIDFromPlayersArrayOfBuildings(int playerID) - + int AICState::chooseRandomBuildingIDFromPlayersArrayOfBuildings(int playerID) { - - int _count = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; - - int _chosenBuilding = 0; - - int _chosenBuildingTypeIndex = 46; - - if (0 < _count) { - - int _rng = (int)(unsigned char)SEC_RNG::instance.currentNumber2 & 7; - - short* _ptr = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings; - - do { - - int _buildingID = (int)*_ptr; - - if (_buildingID != 0) { - - int _selectionIndex = 0; - - if (0 < _chosenBuildingTypeIndex) { - - BuildingTypeInt _buildingType - = (BuildingTypeInt)(short)DAT_BuildingsState::instance.buildings[_buildingID].buildingType; - - do { - - BuildingTypeInt _cmpType; - - if (_rng < 2) { - _cmpType - = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet3[_selectionIndex]; - } else if (_rng < 4) { - _cmpType - = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet2[_selectionIndex]; - } else { - _cmpType - = DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1[_selectionIndex]; - } - - if (_buildingType == _cmpType) { - _chosenBuilding = _buildingID; - _chosenBuildingTypeIndex = _selectionIndex; - } - - _selectionIndex = _selectionIndex + 1; - - } while (_selectionIndex < _chosenBuildingTypeIndex); - } + int chosenBuildingID = 0; + int chosenPriority = 46; + int buildingCount = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildingsTracker; + int rng = SEC_RNG::instance.currentNumber2 & 7; + for (int i = 0; i < buildingCount; i++) { + int buildingID = DAT_GameState::instance.playerDataArray[playerID].top100TargetableBuildings[i]; + if (buildingID == 0) + continue; + + int buildingType = DAT_BuildingsState::instance.buildings[buildingID].buildingType; + for (int j = 0; j < chosenPriority; j++) { + bool isMatch; + if (rng <= 1) + isMatch = buildingType == DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet3[j]; + else if (rng <= 3) + isMatch = buildingType == DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet2[j]; + else + isMatch = buildingType == DAT_SkirmishDefinedData::instance.BuildingTargetPrioritySet1[j]; + + if (isMatch) { + chosenBuildingID = buildingID; + chosenPriority = j; } - - _ptr = _ptr + 1; - - _count = _count - 1; - - } while (_count != 0); + } } - - return _chosenBuilding; + return chosenBuildingID; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9e4745e45..c2c88e285 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35287,7 +35287,7 @@ SHC_3BB0A8C1_0x004CDA50 | 0.0% | Pending SHC_3BB0A8C1_0x004CDAB0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CDB20 | 0.0% | Pending +SHC_3BB0A8C1_0x004CDB20 | 23.3% | Loop/register structure differs SHC_3BB0A8C1_0x004CDBC0 | 65.0% | Loop counter spilled in orig From 5243bb00fe8402aedb2563febacc0cdffb574559 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:13:52 +0200 Subject: [PATCH 153/242] reimplement: SHC_3BB0A8C1_0x004CF870 100.00% Reimplemented --- .../AI/AICState/clearOutdatedAITribes.cpp | 69 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 22 insertions(+), 49 deletions(-) diff --git a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp index ba783a7c9..8e7e23178 100644 --- a/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp +++ b/src/OpenSHC/AI/AICState/clearOutdatedAITribes.cpp @@ -9,57 +9,30 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - // FUNCTION: STRONGHOLDCRUSADER 0x004CF870 - void AICState ::clearOutdatedAITribes(int playerID) - + void AICState::clearOutdatedAITribes(int playerID) { - - if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { - - int _index = 0; - - do { - - if (_index != 8) { - - int _tribeCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index].tribeCount; - - int _tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_index].tribeType; - - int _offset = 0; - - if (0 < _tribeCount) { - - short* _ptrTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + _tribeType; - - do { - int _tribeIDVal = (int)*_ptrTribeID; - if ((_tribeIDVal != 0) - && (DAT_TribesState::instance.tribes[_tribeIDVal].uid - != DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[_offset + _tribeType])) { - - *_ptrTribeID = 0; - - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_offset + _tribeType] = 0; - } - - _offset = _offset + 1; - - _ptrTribeID = _ptrTribeID + 1; - - } while (_offset < _tribeCount); - } - } - - _index = _index + 1; - - } while (_index < 0xb); + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; + + for (int i = 0; i < 11; i++) { + if (i == 8) + continue; + + int tribeCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[i].tribeCount; + int tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[i].tribeType; + for (int j = 0; j < tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeType + j]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[j + tribeType]) + continue; + + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeType + j] = 0; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[j + tribeType] = 0; + } } - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c2c88e285..5886383ed 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35377,7 +35377,7 @@ SHC_3BB0A8C1_0x004CF7C0 | 100.0% | Reimplemented, for-loop didn't work SHC_3BB0A8C1_0x004CF7F0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CF870 | 100.0% | Reimplemented, for-loop didn't work +SHC_3BB0A8C1_0x004CF870 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CF920 | 96.9% | Reimplemented From 503df75e3b2b6e2f803d7e84dcdd3135c3d08260 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:13:52 +0200 Subject: [PATCH 154/242] reimplement: SHC_3BB0A8C1_0x004CAC70 95.24% Reimplemented --- .../clearPlayerDataInformationChunk.cpp | 27 +++++-------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp index 468798d75..9eb65d0be 100644 --- a/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp +++ b/src/OpenSHC/AI/AICState/clearPlayerDataInformationChunk.cpp @@ -1,7 +1,6 @@ #include "../AICState.func.hpp" #include "OpenSHC/OS.func.hpp" -#include "OpenSHC/Synchrony/GameSynchronyState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -9,28 +8,14 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Synchrony::GameSynchronyState; - // FUNCTION: STRONGHOLDCRUSADER 0x004CAC70 - void AICState ::clearPlayerDataInformationChunk() - + void AICState::clearPlayerDataInformationChunk() { - int* _Dst = &DAT_GameState::instance.playerDataArray[0].aiFarmIndex; - int* _pAI = DAT_GameSynchronyState::instance.currentAIArray; - int* _pFullID = DAT_GameSynchronyState::instance.currentPlayerFullIDArray; - - do { - if (*_pFullID != -1 || *_pAI == 0) { - MACRO_CALL(OpenSHC::OS_Func::_memset)(_Dst, 0, (size_t)((int)(3748))); - } - - _pAI = _pAI + 1; - _pFullID = _pFullID + 1; - _Dst = _Dst + 3709; - - } while ((int)_pAI < 0x191dea0); - - return; + for (int i = 0; i < 9; i++) { + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[i] != -1 + || DAT_GameSynchronyState::instance.currentAIArray[i] == 0) + MACRO_CALL(OpenSHC::OS_Func::_memset)(&DAT_GameState::instance.playerDataArray[i].aiFarmIndex, 0, 3748); + } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5886383ed..61419d83d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34189,7 +34189,7 @@ SHC_3BB0A8C1_0x004CA4D0 | 0.0% | Pending SHC_3BB0A8C1_0x004CA8A0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CAC70 | 0.0% | Pending +SHC_3BB0A8C1_0x004CAC70 | 95.2% | Reimplemented SHC_3BB0A8C1_0x004CACB0 | 100.0% | Reimplemented From 58d19aca1bc9a8a6d8ee38499263412d43816b4d Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:13:53 +0200 Subject: [PATCH 155/242] reimplement: SHC_3BB0A8C1_0x004CE790 98.00% Reimplemented --- .../clearRallyFlagOnAllAIAttackTribes.cpp | 85 ++++--------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 19 insertions(+), 68 deletions(-) diff --git a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp index 8ef25ba8e..c06815f87 100644 --- a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp @@ -10,76 +10,27 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CE790 - void AICState ::clearRallyFlagOnAllAIAttackTribes(int param_1) - + void AICState::clearRallyFlagOnAllAIAttackTribes(int playerID) { - - int _tribeID; - - int _counter; - - short* _ptrTribeID; - - int* _ptrTribeCount; - - int _tribeCount; - - int _tribeType; - - if (DAT_GameState::instance.playerDataArray[param_1].aiType != OpenSHC::AI::AIT_NULL) { - - do { - - /* - first iteration: 0 */ - - _counter = 0; - - _tribeCount = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_counter].tribeCount; - - _tribeType = DAT_SkirmishDefinedData::instance.MaxBreachTribes[_counter].tribeType; - - /* - first iteration: 186 */ - - // _tribeType = (*(int (*)[2])(_ptrTribeCount + -1))[0]; - - if (0 < _tribeCount) { - - _ptrTribeID = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + _tribeType; - - do { - - _tribeID = (int)*_ptrTribeID; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[param_1] - .aiTribeUIDs[_counter + _tribeType])) { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, - DAT_TribesState::ptr)(_tribeID); - } - - _counter = _counter + 1; - - _ptrTribeID = _ptrTribeID + 1; - - } while (_counter < _tribeCount); - } - - _ptrTribeCount = _ptrTribeCount + 2; - - } while ((int)_ptrTribeCount < 0xb42a2c); + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; + + for (int i = 0; i < 11; i++) { + int tribeType = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType; + int tribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeCount; + for (int j = 0; j < tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeType + j]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[j + tribeType]) + continue; + + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)( + tribeID); + } } - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 61419d83d..ef5151d3b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35325,7 +35325,7 @@ SHC_3BB0A8C1_0x004CE660 | 0.0% | Pending SHC_3BB0A8C1_0x004CE6B0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CE790 | 0.0% | Pending +SHC_3BB0A8C1_0x004CE790 | 98.0% | Reimplemented SHC_3BB0A8C1_0x004CE830 | 100.0% | Reimplemented From 856014fce14d89850b8d38e4b8a02ba0de48eba1 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:13:53 +0200 Subject: [PATCH 156/242] reimplement: SHC_3BB0A8C1_0x004D38C0 83.78% AIC index folding differs --- ...determineAIPlayerAttackRequestResponse.cpp | 55 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 18 insertions(+), 39 deletions(-) diff --git a/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp b/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp index d638516e3..7628ed4fe 100644 --- a/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp +++ b/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp @@ -1,55 +1,34 @@ #include "../AICState.func.hpp" -#include "OpenSHC/Global.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D38C0 - BOOLEnum AICState ::determineAIPlayerAttackRequestResponse( - int playerID, undefined4 param_2, int requestedByPlayerID) - + BOOLEnum AICState::determineAIPlayerAttackRequestResponse(int playerID, undefined4 param_2, int requestedByPlayerID) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) + return FALSE; + int aicIndex = aiType - 1; + + if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue != 0) { + MACRO_CALL_MEMBER(AICState_Func::playWillNotAttack1BikFromPlayerToPlayer, this)(playerID, requestedByPlayerID); + return FALSE; + } - AITypeInt AVar1; - - AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar1 != OpenSHC::AI::AIT_NULL) { - - if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue == 0) { - - if (DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops - - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops - < *(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x1fc)) { - - MACRO_CALL(OpenSHC::Global_Func::PlayWillNotAttack2BikFromPlayerToPlayer)( - playerID, requestedByPlayerID); - - return FALSE; - } - - MACRO_CALL(OpenSHC::Global_Func::PlayWillAttackBikFromPlayerToPlayer)(playerID, requestedByPlayerID); - - return TRUE; - } - - MACRO_CALL(OpenSHC::Global_Func::PlayWillNotAttack1BikFromPlayerToPlayer)(playerID, requestedByPlayerID); + if (DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops + < this->aics[aicIndex].AttForceSupportAllyThreshold) { + MACRO_CALL_MEMBER(AICState_Func::playWillNotAttack2BikFromPlayerToPlayer, this)(playerID, requestedByPlayerID); + return FALSE; } - return FALSE; + MACRO_CALL_MEMBER(AICState_Func::playWillAttackBikFromPlayerToPlayer, this)(playerID, requestedByPlayerID); + return TRUE; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index ef5151d3b..185037903 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35517,7 +35517,7 @@ SHC_3BB0A8C1_0x004D3780 | 0.0% | Pending SHC_3BB0A8C1_0x004D3850 | 0.0% | Pending -SHC_3BB0A8C1_0x004D38C0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D38C0 | 83.8% | AIC index folding differs SHC_3BB0A8C1_0x004D3940 | 100.0% | Reimplemented From fe43623551c2752bf9d29a559e3fcb88004a5c37 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:13:53 +0200 Subject: [PATCH 157/242] reimplement: SHC_3BB0A8C1_0x004D3850 82.35% AIC index folding differs --- .../AI/AICState/determineAIPlayerHelp.cpp | 52 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 17 insertions(+), 37 deletions(-) diff --git a/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp b/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp index 0013a64d9..214c9d2e7 100644 --- a/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp +++ b/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp @@ -1,53 +1,33 @@ #include "../AICState.func.hpp" -#include "OpenSHC/Global.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D3850 - BOOLEnum AICState ::determineAIPlayerHelp(int playerID, int requestedByPlayerID) - + BOOLEnum AICState::determineAIPlayerHelp(int playerID, int requestedByPlayerID) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) + return FALSE; + int aicIndex = aiType - 1; + + if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue != 0) { + MACRO_CALL_MEMBER(AICState_Func::playWillNotHelp1BikFromPlayerToPlayer, this)(playerID, requestedByPlayerID); + return FALSE; + } - AITypeInt AVar1; - - AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar1 != OpenSHC::AI::AIT_NULL) { - - if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue == 0) { - - if (DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops - < *(int*)((int)this + (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x1fc)) { - - MACRO_CALL(OpenSHC::Global_Func::PlayWillNotHelp2BikFromPlayerToPlayer)( - playerID, requestedByPlayerID); - - return FALSE; - } - - MACRO_CALL(OpenSHC::Global_Func::PlayWillHelpBikFromPlayerToPlayer)(playerID, requestedByPlayerID); - - return TRUE; - } - - MACRO_CALL(OpenSHC::Global_Func::PlayWillNotHelp1BikFromPlayerToPlayer)(playerID, requestedByPlayerID); + if (DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + < this->aics[aicIndex].AttForceSupportAllyThreshold) { + MACRO_CALL_MEMBER(AICState_Func::playWillNotHelp2BikFromPlayerToPlayer, this)(playerID, requestedByPlayerID); + return FALSE; } - return FALSE; + MACRO_CALL_MEMBER(AICState_Func::playWillHelpBikFromPlayerToPlayer, this)(playerID, requestedByPlayerID); + return TRUE; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 185037903..b1af1054a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35515,7 +35515,7 @@ SHC_3BB0A8C1_0x004D3320 | 87.69% | Reimplemented, different register usage, effe SHC_3BB0A8C1_0x004D3780 | 0.0% | Pending -SHC_3BB0A8C1_0x004D3850 | 0.0% | Pending +SHC_3BB0A8C1_0x004D3850 | 82.3% | AIC index folding differs SHC_3BB0A8C1_0x004D38C0 | 83.8% | AIC index folding differs From c0613fe992d63fef07a55eea1128e8c9a98d40c7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:20:06 +0200 Subject: [PATCH 158/242] reimplement: SHC_3BB0A8C1_0x004CF7C0 98.15% Reimplemented --- .../AI/AICState/commandFourTribesToMove.cpp | 69 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 21 insertions(+), 50 deletions(-) diff --git a/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp b/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp index ad8c9a3ee..83e39cbc1 100644 --- a/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp +++ b/src/OpenSHC/AI/AICState/commandFourTribesToMove.cpp @@ -11,58 +11,29 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - // FUNCTION: STRONGHOLDCRUSADER 0x004CF7C0 - void AICState ::commandFourTribesToMove(int playerID) - + void AICState::commandFourTribesToMove(int playerID) { - - if (DAT_GameState::instance.playerDataArray[playerID].aiType != OpenSHC::AI::AIT_NULL) { - - int _counter2 = 0; - - int _counter = 0; - - short* _ptrTribeIDArray = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xba; - - do { - - int _tribeID = (int)*_ptrTribeIDArray; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_counter + 0xba])) { - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; - - /* - fixme: array too small? */ - - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[playerID * 5][_counter2] - .xOffset)), - (uint)((int)(DAT_GameState::instance.mapAndTime - .aiTribeMoveDestinationXYPairArray1[playerID * 5][_counter2] - .yOffset)), - 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - - _counter2 = _counter2 + 1; - } - - _counter = _counter + 1; - - _ptrTribeIDArray = _ptrTribeIDArray + 1; - - } while (_counter < 3); + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) + return; + + int destIndex = 0; + for (int i = 0; i < 3; i++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[186 + i]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[i + 186]) + continue; + + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_STAND_GROUND; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, + DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex].xOffset, + DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex].yOffset, + 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); + destIndex++; } - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b1af1054a..3dfc32cab 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35373,7 +35373,7 @@ SHC_3BB0A8C1_0x004CF6E0 | 62.22% | Reimplemented functionally, different registe SHC_3BB0A8C1_0x004CF750 | 62.22% | Reimplemented functionally, our compiler improves on original by avoiding recomputations -SHC_3BB0A8C1_0x004CF7C0 | 100.0% | Reimplemented, for-loop didn't work +SHC_3BB0A8C1_0x004CF7C0 | 98.2% | Reimplemented SHC_3BB0A8C1_0x004CF7F0 | 0.0% | Pending From 6daceacdabc6928ca8905cfecde4d20b04d6da3e Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:20:07 +0200 Subject: [PATCH 159/242] reimplement: SHC_3BB0A8C1_0x004CE200 55.26% Register/store scheduling diff --- .../AICState/computeEnemyKeepApproachTile.cpp | 185 +++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 49 insertions(+), 138 deletions(-) diff --git a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp index 8b9e81fde..1b1585398 100644 --- a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp +++ b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp @@ -4,7 +4,6 @@ #include "OpenSHC/Map/LandscapeState.func.hpp" #include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" -#include "OpenSHC/AI/TileDistancePair.hpp" #include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" @@ -18,156 +17,68 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::TileDistancePair; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CE200 - void AICState ::computeEnemyKeepApproachTile(int playerID) - + void AICState::computeEnemyKeepApproachTile(int playerID) { - - int _shortestDistanceTile; - - int _shortestDistanceX; - - TileDistancePair* _tilePointer; - - int iVar1; - - int* _distancePointer; - - int _shortestDistance; - - int local_c; - - int _keepX; - - int _keepY; - - int _tile; - - short _y; - - _keepX = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; - - _keepY = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; - + int keepX = DAT_GameState::instance.playerDataArray[playerID].campground.xEntry; + int keepY = DAT_GameState::instance.playerDataArray[playerID].campground.yEntry; this->aiBorderTilesIndex = 0; - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( - 8000, '\0', (void*)((int)(this->aiBorderTiles))); - + 8000, '\0', this->aiBorderTiles); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::recomputeAIPathCostToAttackedKeep, this)(playerID, 1); - local_c = 0; - - if (0 < this->aiBorderTilesIndex) { - - _distancePointer = &this->aiBorderTiles[0].distance; - - do { - - _tile = ((TileDistancePair*)(_distancePointer + -1))->tile; - - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, - DAT_DirectionAlgorithmState::ptr)(_keepX, _keepY, - _tile - - DAT_ViewportRenderState::instance - .translationMatrix[DAT_ViewportRenderState::instance - .tileTranslationMatrix_YComponent[_tile]] - .addXgetTile, - (int)((int)(DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]))); - - /* - avoiding unit death areas */ - - *_distancePointer = (uint)DAT_TileMapState::instance.unitDeathHeatMap[_tile] - + DAT_DirectionAlgorithmState::instance.distanceHigh; - - local_c = local_c + 1; - - _distancePointer = _distancePointer + 2; - - } while (local_c < this->aiBorderTilesIndex); + for (int i = 0; i < (int)this->aiBorderTilesIndex; i++) { + int tile = this->aiBorderTiles[i].tile; + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + DAT_DirectionAlgorithmState::ptr)(keepX, keepY, + tile + - DAT_ViewportRenderState::instance + .translationMatrix[DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]] + .addXgetTile, + DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]); + this->aiBorderTiles[i].distance + = DAT_TileMapState::instance.unitDeathHeatMap[tile] + DAT_DirectionAlgorithmState::instance.distanceHigh; } - _shortestDistanceTile = 0; - - _shortestDistance = 100000; - - if (0 < this->aiBorderTilesIndex) { - - _tilePointer = this->aiBorderTiles; - - iVar1 = this->aiBorderTilesIndex; - - do { - - if (_tilePointer->distance < _shortestDistance) { - - _shortestDistanceTile = _tilePointer->tile; - - _shortestDistance = _tilePointer->distance; - } - - _tilePointer = _tilePointer + 1; - - iVar1 = iVar1 + -1; - - } while (iVar1 != 0); + int shortestDistanceTile = 0; + int shortestDistance = 100000; + for (int i = 0; i < (int)this->aiBorderTilesIndex; i++) { + if (this->aiBorderTiles[i].distance < shortestDistance) { + shortestDistanceTile = this->aiBorderTiles[i].tile; + shortestDistance = this->aiBorderTiles[i].distance; + } } - /* - sets the first attack distance to the enemy keep */ - DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile = 0; - - if (0 < _shortestDistanceTile) { - - _y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_shortestDistanceTile]; - - DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY = (int)_y; - - DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile = _shortestDistanceTile; - - _shortestDistanceX - = _shortestDistanceTile - DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile; - - DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX = _shortestDistanceX; - - DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][0] = _shortestDistanceX; - - DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][1] - = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY; - - if ((short)DAT_TileMapState::instance.OrganismLayer + if (shortestDistanceTile <= 0) + return; + + short y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[shortestDistanceTile]; + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY = y; + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceTile = shortestDistanceTile; + int x = shortestDistanceTile - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX = x; + DAT_GameState::instance.mapAndTime.signpostEntryData[playerID - 1].x = x; + DAT_GameState::instance.mapAndTime.signpostEntryData[playerID - 1].y + = DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY; + + if ((short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX] + != 0) + MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)( + (short)DAT_TileMapState::instance.OrganismLayer [DAT_ViewportRenderState::instance .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] .addXgetTile - + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX] - != 0) { - - MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)( - (int)(short)DAT_TileMapState::instance.OrganismLayer - [DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] - .addXgetTile - + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]); - } - - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, - DAT_PathFindingState::ptr)(DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][0], - (uint)((int)(DAT_GameState::instance.mapAndTime.signpostEntryData[playerID + -1][1])), -1, -1, 2000, - FALSE); - - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::storeDestinationOptionsUnk, - DAT_PathFindingState::ptr)(playerID + -1); - } - - return; + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, + DAT_PathFindingState::ptr)(DAT_GameState::instance.mapAndTime.signpostEntryData[playerID - 1].x, + DAT_GameState::instance.mapAndTime.signpostEntryData[playerID - 1].y, -1, -1, 2000, FALSE); + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::storeDestinationOptionsUnk, + DAT_PathFindingState::ptr)(playerID - 1); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3dfc32cab..5e4f19c99 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35307,7 +35307,7 @@ SHC_3BB0A8C1_0x004CE110 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE1A0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CE200 | 0.0% | Pending +SHC_3BB0A8C1_0x004CE200 | 55.3% | Register/store scheduling diff SHC_3BB0A8C1_0x004CE270 | 0.0% | Pending From 20f92f376801c4bbdff802362f9045281fea6b46 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:20:07 +0200 Subject: [PATCH 160/242] reimplement: SHC_3BB0A8C1_0x004CFBC0 100.00% Reimplemented --- .../AI/AICState/countSiegeEngineUnits.cpp | 66 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 20 insertions(+), 48 deletions(-) diff --git a/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp b/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp index 562c048fb..4cad5f5ed 100644 --- a/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp +++ b/src/OpenSHC/AI/AICState/countSiegeEngineUnits.cpp @@ -1,63 +1,35 @@ #include "../AICState.func.hpp" -#include "OpenSHC/Map/Units/Unit.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Map/Units/UnitTypeShort.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" namespace OpenSHC { namespace AI { - using OpenSHC::Map::Units::Unit; - using OpenSHC::Map::Units::UnitLogicState; - using OpenSHC::Map::Units::UnitType; - using OpenSHC::Map::Units::UnitTypeShort; - // FUNCTION: STRONGHOLDCRUSADER 0x004CFBC0 int AICState::countSiegeEngineUnits(int playerID) { - int _count = 0; - Unit* _units = &DAT_UnitsState::instance.units[0]; - - for (int i = 1; i < 2500; i += 1) { - // Unit[1] - if (_units[i].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE && _units[i].owner == playerID - && _units[i].unknownSiegeTentRelated02 == 3 && _units[i].aiUnitBehaviourType != 0x15) { - UnitTypeShort t = _units[i].unitType; - if (t == OpenSHC::Map::Units::UT_S_CATAPULT || t == OpenSHC::Map::Units::UT_S_TREBUCHET - || t == OpenSHC::Map::Units::UT_S_TOWER || t == OpenSHC::Map::Units::UT_S_BATTERINGRAM - || t == OpenSHC::Map::Units::UT_S_FBALLISTA) { - _count = _count + 1; - } - } - - // Compiler unrolled the loop because 2499 is divisible by 3? - // // Unit[2] - // if (_units[i + 1].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE && _units[i + 1].owner == playerID - // && _units[i + 1].unknownSiegeTentRelated02 == 3 && _units[i + 1].aiUnitBehaviourType != 0x15) { - // UnitTypeShort t = _units[i + 1].unitType; - // if (t == OpenSHC::Map::Units::UT_S_CATAPULT || t == OpenSHC::Map::Units::UT_S_TREBUCHET - // || t == OpenSHC::Map::Units::UT_S_TOWER || t == OpenSHC::Map::Units::UT_S_BATTERINGRAM - // || t == OpenSHC::Map::Units::UT_S_FBALLISTA) { - // _count = _count + 1; - // } - // } - - // // Unit[3] - // if (_units[i + 2].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE && _units[i + 2].owner == playerID - // && _units[i + 2].unknownSiegeTentRelated02 == 3 && _units[i + 2].aiUnitBehaviourType != 0x15) { - // UnitTypeShort t = _units[i + 2].unitType; - // if (t == OpenSHC::Map::Units::UT_S_CATAPULT || t == OpenSHC::Map::Units::UT_S_TREBUCHET - // || t == OpenSHC::Map::Units::UT_S_TOWER || t == OpenSHC::Map::Units::UT_S_BATTERINGRAM - // || t == OpenSHC::Map::Units::UT_S_FBALLISTA) { - // _count = _count + 1; - // } - // } - }; - - return _count; + int count = 0; + for (int unitID = 1; unitID < 2500; unitID++) { + if (DAT_UnitsState::instance.units[unitID].logicalState == OpenSHC::Map::Units::ULS_INVISIBLE) + continue; + if (DAT_UnitsState::instance.units[unitID].owner != playerID) + continue; + if (DAT_UnitsState::instance.units[unitID].unknownSiegeTentRelated02 != 3) + continue; + if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType == 21) + continue; + + if (DAT_UnitsState::instance.units[unitID].unitType == OpenSHC::Map::Units::UT_S_CATAPULT + || DAT_UnitsState::instance.units[unitID].unitType == OpenSHC::Map::Units::UT_S_TREBUCHET + || DAT_UnitsState::instance.units[unitID].unitType == OpenSHC::Map::Units::UT_S_TOWER + || DAT_UnitsState::instance.units[unitID].unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM + || DAT_UnitsState::instance.units[unitID].unitType == OpenSHC::Map::Units::UT_S_FBALLISTA) + count++; + } + return count; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5e4f19c99..1733cee86 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35385,7 +35385,7 @@ SHC_3BB0A8C1_0x004CFA10 | 0.0% | Pending SHC_3BB0A8C1_0x004CFB20 | 97.8% | Reimplemented -SHC_3BB0A8C1_0x004CFBC0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CFBC0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CFCD0 | 0.0% | Pending From d9747325126b4bb007425bfb46e2c2f22423e717 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:20:08 +0200 Subject: [PATCH 161/242] reimplement: SHC_3BB0A8C1_0x004D0280 98.19% Reimplemented --- .../AICState/destroyAnyBuildingInCategory.cpp | 94 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 40 insertions(+), 56 deletions(-) diff --git a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp index 8f1d56ea7..3d9cd00bc 100644 --- a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp +++ b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp @@ -8,67 +8,51 @@ namespace OpenSHC { namespace AI { + using namespace OpenSHC::Map::Buildings; + // FUNCTION: STRONGHOLDCRUSADER 0x004D0280 void AICState::destroyAnyBuildingInCategory(int playerID, AINervousDestroyBuildingCategory buildingCategory) { - int _buildingID = 1; - if (1 < DAT_BuildingsState::instance.maxBuildingsCount) { - Map::Buildings::Building* pBVar2 = &DAT_BuildingsState::instance.buildings[1]; - do { - if (((pBVar2->logicalState != 0) && (pBVar2->logicalState != Map::Buildings::BLS_REMOVE)) - && (pBVar2->owner == playerID)) { + for (int buildingID = 1; buildingID < DAT_BuildingsState::instance.maxBuildingsCount; buildingID++) { + if (DAT_BuildingsState::instance.buildings[buildingID].logicalState == 0) + continue; + if (DAT_BuildingsState::instance.buildings[buildingID].logicalState == BLS_REMOVE) + continue; + if (DAT_BuildingsState::instance.buildings[buildingID].owner != playerID) + continue; - bool _matches = false; - Map::Buildings::BuildingTypeShort BVar1 = pBVar2->buildingType; + bool matches = false; + if (buildingCategory == AINDBC_FEAR_FACTOR_BUILDINGS) + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CESSPIT || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BURNINGSTAKE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GIBBET || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DUNGEON + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STRETCHINGRACK || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_RACKFLOGGING || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CHOPPINGBLOCK + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DUNKINGSTOOL || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DOGCAGE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STATUE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_SHRINE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DANCINGBEAR || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_POND || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GALLOWS || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STOCKS + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WITCHHOIST || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_MAYPOLE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GARDEN; + else if (buildingCategory == AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS) + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_FLETCHER || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BLACKSMITH || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_POLETURNER || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_ARMOURER + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TANNER || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_INN || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_APOTHECARY || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CHAPEL + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CHURCH || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CATHEDRAL; + else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GATEHOUSELARGE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GATEHOUSESMALL || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DRAWBRIDGE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER1 || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER2 || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER3 || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER4 + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER5 || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_ENGINEERSGUILD || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TUNNELERSGUILD + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_OILSMELTER; + else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_MERCENARYPOST || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BARRACKS || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STABLES; + else if (buildingCategory == AINDBC_WATER_BUILDINGS) + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WELL || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WATERPOT; + else if (buildingCategory == AINDBC_RESOURCE_BUILDINGS) + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_OXTETHER || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_IRONMINE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_PITCHRIG || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BAKERY + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BREWERY || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_QUARRY || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_MILL; + else if (buildingCategory == AINDBC_FARMS) + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WHEATFARM || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_HOPFARM || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_APPLEFARM || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DAIRYFARM; - if (buildingCategory == AINDBC_FEAR_FACTOR_BUILDINGS) { - _matches = (BVar1 == Map::Buildings::BT_CESSPIT || BVar1 == Map::Buildings::BT_BURNINGSTAKE - || BVar1 == Map::Buildings::BT_GIBBET || BVar1 == Map::Buildings::BT_DUNGEON - || BVar1 == Map::Buildings::BT_STRETCHINGRACK || BVar1 == Map::Buildings::BT_RACKFLOGGING - || BVar1 == Map::Buildings::BT_CHOPPINGBLOCK || BVar1 == Map::Buildings::BT_DUNKINGSTOOL - || BVar1 == Map::Buildings::BT_DOGCAGE || BVar1 == Map::Buildings::BT_STATUE - || BVar1 == Map::Buildings::BT_SHRINE || BVar1 == Map::Buildings::BT_DANCINGBEAR - || BVar1 == Map::Buildings::BT_POND || BVar1 == Map::Buildings::BT_GALLOWS - || BVar1 == Map::Buildings::BT_STOCKS || BVar1 == Map::Buildings::BT_WITCHHOIST - || BVar1 == Map::Buildings::BT_MAYPOLE || BVar1 == Map::Buildings::BT_GARDEN); - } else if (buildingCategory == AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS) { - _matches = (BVar1 == Map::Buildings::BT_FLETCHER || BVar1 == Map::Buildings::BT_BLACKSMITH - || BVar1 == Map::Buildings::BT_POLETURNER || BVar1 == Map::Buildings::BT_ARMOURER - || BVar1 == Map::Buildings::BT_TANNER || BVar1 == Map::Buildings::BT_INN - || BVar1 == Map::Buildings::BT_APOTHECARY || BVar1 == Map::Buildings::BT_CHAPEL - || BVar1 == Map::Buildings::BT_CHURCH || BVar1 == Map::Buildings::BT_CATHEDRAL); - } else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) { - _matches = (BVar1 == Map::Buildings::BT_GATEHOUSELARGE - || BVar1 == Map::Buildings::BT_GATEHOUSESMALL || BVar1 == Map::Buildings::BT_DRAWBRIDGE - || BVar1 == Map::Buildings::BT_TOWER1 || BVar1 == Map::Buildings::BT_TOWER2 - || BVar1 == Map::Buildings::BT_TOWER3 || BVar1 == Map::Buildings::BT_TOWER4 - || BVar1 == Map::Buildings::BT_TOWER5 || BVar1 == Map::Buildings::BT_ENGINEERSGUILD - || BVar1 == Map::Buildings::BT_TUNNELERSGUILD || BVar1 == Map::Buildings::BT_OILSMELTER); - } else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) { - _matches = (BVar1 == Map::Buildings::BT_MERCENARYPOST || BVar1 == Map::Buildings::BT_BARRACKS - || BVar1 == Map::Buildings::BT_STABLES); - } else if (buildingCategory == AINDBC_WATER_BUILDINGS) { - _matches = (BVar1 == Map::Buildings::BT_WELL || BVar1 == Map::Buildings::BT_WATERPOT); - } else if (buildingCategory == AINDBC_RESOURCE_BUILDINGS) { - _matches = (BVar1 == Map::Buildings::BT_OXTETHER || BVar1 == Map::Buildings::BT_IRONMINE - || BVar1 == Map::Buildings::BT_PITCHRIG || BVar1 == Map::Buildings::BT_BAKERY - || BVar1 == Map::Buildings::BT_BREWERY || BVar1 == Map::Buildings::BT_QUARRY - || BVar1 == Map::Buildings::BT_MILL); - } else if (buildingCategory == AINDBC_FARMS) { - _matches = (BVar1 == Map::Buildings::BT_WHEATFARM || BVar1 == Map::Buildings::BT_HOPFARM - || BVar1 == Map::Buildings::BT_APPLEFARM || BVar1 == Map::Buildings::BT_DAIRYFARM); - } + if (!matches) + continue; - if (_matches) { - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(_buildingID, playerID, 0x32); - MACRO_CALL_MEMBER( - Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_buildingID); - } - } - _buildingID = _buildingID + 1; - pBVar2 = pBVar2 + 1; - } while (_buildingID < DAT_BuildingsState::instance.maxBuildingsCount); + MACRO_CALL_MEMBER(BuildingsState_Func::giveBackResourceForDestroyedBuilding, DAT_BuildingsState::ptr)( + buildingID, playerID, 50); + MACRO_CALL_MEMBER(BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(buildingID); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1733cee86..e319d21a2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35399,7 +35399,7 @@ SHC_3BB0A8C1_0x004D0110 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0190 | 100.0% | Reimplemented, compiler didn't optimize one tail -SHC_3BB0A8C1_0x004D0280 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0280 | 98.2% | Reimplemented SHC_3BB0A8C1_0x004D0520 | 100.0% | Reimplemented From 05263b2b56c24877714cf5796f3b379e93e6be1b Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:20:08 +0200 Subject: [PATCH 162/242] reimplement: SHC_3BB0A8C1_0x004CB940 88.89% Register allocation differs --- .../AI/AICState/destroyBuildingIfNoWorker.cpp | 49 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp index 3cff7bcbf..e041584c2 100644 --- a/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp +++ b/src/OpenSHC/AI/AICState/destroyBuildingIfNoWorker.cpp @@ -14,34 +14,31 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB940 undefined4 AICState::destroyBuildingIfNoWorker(int buildingID) { - short _value = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; - int _owner = (int)DAT_BuildingsState::instance.buildings[buildingID].owner; + short countdown = DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue; + int owner = DAT_BuildingsState::instance.buildings[buildingID].owner; + if (countdown <= 0) + return 0; + if (DAT_GameSynchronyState::instance.currentPlayerFullIDArray[owner] != -1) + return 0; + if (DAT_GameSynchronyState::instance.currentAIArray[owner] == 0) + return 0; + if (DAT_GameSynchronyState::instance.currentGameMode == Game::GM_SOLITARY) + return 0; - if (0 < _value && DAT_GameSynchronyState::instance.currentPlayerFullIDArray[_owner] == -1 - && DAT_GameSynchronyState::instance.currentAIArray[_owner] != 0 - && DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY) { - - if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] != 0) { - if (DAT_GameState::instance.mapAndTime.monthTicks == _owner) - DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = _value + -1; - return 0; - } - - // workers == 0: check if old enough - if ((short)_value < (short)0x14) - return 0; - - // old enough: destroy - MACRO_CALL_MEMBER(AIVState_Func::resetCountdownInHeatMap, DAT_AIVState::ptr)( - (int)(short)DAT_BuildingsState::instance.buildings[buildingID].x, - (int)(short)DAT_BuildingsState::instance.buildings[buildingID].y); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(buildingID, _owner, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)( - buildingID); - return 1; + if (DAT_BuildingsState::instance.buildings[buildingID].workers[0] != 0) { + if (DAT_GameState::instance.mapAndTime.monthTicks == owner) + DAT_BuildingsState::instance.buildings[buildingID].unknownTickRelatedValue = countdown - 1; + return 0; } - return 0; + if (countdown < 20) + return 0; + + MACRO_CALL_MEMBER(AIVState_Func::resetCountdownInHeatMap, DAT_AIVState::ptr)( + DAT_BuildingsState::instance.buildings[buildingID].x, DAT_BuildingsState::instance.buildings[buildingID].y); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, + DAT_BuildingsState::ptr)(buildingID, owner, 50); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(buildingID); + return 1; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e319d21a2..263c12883 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34849,7 +34849,7 @@ SHC_3BB0A8C1_0x004CB810 | 0.0% | Pending SHC_3BB0A8C1_0x004CB890 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CB940 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB940 | 88.9% | Register allocation differs SHC_3BB0A8C1_0x004CB9F0 | 0.0% | Pending From 5bed2a5afdffed8df3cbbdb75be438e1ce844567 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:20:08 +0200 Subject: [PATCH 163/242] reimplement: SHC_3BB0A8C1_0x004CB810 92.31% Reimplemented --- src/OpenSHC/AI/AICState/destroyHouse.cpp | 23 ++++++++--------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/OpenSHC/AI/AICState/destroyHouse.cpp b/src/OpenSHC/AI/AICState/destroyHouse.cpp index 108bf6d85..acaa30e30 100644 --- a/src/OpenSHC/AI/AICState/destroyHouse.cpp +++ b/src/OpenSHC/AI/AICState/destroyHouse.cpp @@ -12,31 +12,24 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB810 BOOLEnum AICState::destroyHouse(int playerID) { - int _hovelID; - if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) return FALSE; - - _hovelID = DAT_GameState::instance.playerDataArray[playerID].currentPopulation; - - if (_hovelID > DAT_GameState::instance.playerDataArray[playerID].populationCap) + if (DAT_GameState::instance.playerDataArray[playerID].currentPopulation + > DAT_GameState::instance.playerDataArray[playerID].populationCap) return FALSE; - - if (_hovelID <= 8) + if (DAT_GameState::instance.playerDataArray[playerID].currentPopulation <= 8) return FALSE; - - if (DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk <= 0x14) + if (DAT_GameState::instance.playerDataArray[playerID].averagePopulationGrowthUnk <= 20) return FALSE; - _hovelID = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + int hovelID = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_HOVEL); - - if (_hovelID == 0) + if (hovelID == 0) return FALSE; MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::giveBackResourceForDestroyedBuilding, - DAT_BuildingsState::ptr)(_hovelID, playerID, 0x32); - MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(_hovelID); + DAT_BuildingsState::ptr)(hovelID, playerID, 50); + MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::destroyBuilding, DAT_BuildingsState::ptr)(hovelID); return TRUE; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 263c12883..40007cecf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34845,7 +34845,7 @@ SHC_3BB0A8C1_0x004CB803 | 0.0% | Pending SHC_3BB0A8C1_0x004CB804 | 0.0% | Pending -SHC_3BB0A8C1_0x004CB810 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB810 | 92.3% | Reimplemented SHC_3BB0A8C1_0x004CB890 | 100.0% | Reimplemented From 26193d38e1a5a278e86fca89941123f7f36caa59 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:23:59 +0200 Subject: [PATCH 164/242] reimplement: SHC_3BB0A8C1_0x004D2EC0 74.14% Call diffs, load order differs --- .../AICState/computeAttackPossibilities.cpp | 37 ++++--------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp index f67a8a032..4a8f8f26d 100644 --- a/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp +++ b/src/OpenSHC/AI/AICState/computeAttackPossibilities.cpp @@ -3,7 +3,6 @@ #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/IO/LowLevelMemory.func.hpp" #include "OpenSHC/Map/Units/TroopValueState.func.hpp" -#include "OpenSHC/Game/Player/PlayerData.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" @@ -13,48 +12,26 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Game::Player::PlayerData; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D2EC0 - void AICState ::computeAttackPossibilities(int playerID) - + void AICState::computeAttackPossibilities(int playerID) { - - PlayerData* piVar1; - - piVar1 = &DAT_GameState::instance.playerDataArray[playerID]; - MACRO_CALL_MEMBER(OpenSHC::IO::LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( - 80400, '\0', (void*)((int)(DAT_TileMapState::instance.AIInfoLayer))); - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackPrimeInfo, this)(playerID, piVar1->attackedPlayerID); - + 80400, '\0', DAT_TileMapState::instance.AIInfoLayer); + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setAttackPrimeInfo, this)( + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::recomputeTargetedBuildingTilesArray, DAT_TroopValueState::ptr)(playerID); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::recomputeAttackInfo, DAT_TroopValueState::ptr)( - playerID, piVar1->attackedPlayerID); - + playerID, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::computeSiegeSpotScores, DAT_TroopValueState::ptr)( - piVar1->attackedPlayerID, playerID); - + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, playerID); MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setScale3, DAT_TroopValueState::ptr)(1, playerID); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setTown2, DAT_TroopValueState::ptr)(1, playerID); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setGate2, DAT_TroopValueState::ptr)(1, playerID); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setWide3, DAT_TroopValueState::ptr)(1, playerID); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TroopValueState_Func::setMoat3, DAT_TroopValueState::ptr)(1, playerID); - MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::calculateAttackVectorsToCampFireOfPlayer, - DAT_GameState::ptr)(piVar1->attackedPlayerID); - - return; + DAT_GameState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 40007cecf..328817b44 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35505,7 +35505,7 @@ SHC_3BB0A8C1_0x004D2A70 | 0.0% | Pending SHC_3BB0A8C1_0x004D2E00 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D2EC0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D2EC0 | 74.1% | Call diffs, load order differs SHC_3BB0A8C1_0x004D2F80 | 100.0% | Reimplemented From 3b64a64182ba5949d0358e352f6202c7df01cc0a Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:23:59 +0200 Subject: [PATCH 165/242] reimplement: SHC_3BB0A8C1_0x004D3780 74.02% Constant 1 kept in register --- .../AI/AICState/computeNervousness.cpp | 52 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/OpenSHC/AI/AICState/computeNervousness.cpp b/src/OpenSHC/AI/AICState/computeNervousness.cpp index 6f1c880e4..61274298d 100644 --- a/src/OpenSHC/AI/AICState/computeNervousness.cpp +++ b/src/OpenSHC/AI/AICState/computeNervousness.cpp @@ -8,32 +8,28 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D3780 - void AICState ::computeNervousness(int playerID) - + void AICState::computeNervousness(int playerID) { - int _one = 1; - - int iVar1 = DAT_TroopValueState::instance.attackInfo.playerTotalTroopValueOfTroopsNearKeep[playerID]; - - int _totalTroopValueOfEnemy = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; - - int _someCutoff; - - if (_totalTroopValueOfEnemy < 50) { - _someCutoff = _one - 0x15; - } else if (_totalTroopValueOfEnemy < 100) { - _someCutoff = 0; - } else if (_totalTroopValueOfEnemy < 200) { - _someCutoff = 20; - } else if (_totalTroopValueOfEnemy < 400) { - _someCutoff = 100; - } else if (_totalTroopValueOfEnemy < 600) { - _someCutoff = 200; - } else { - _someCutoff = ((_totalTroopValueOfEnemy >= 800) - _one & 0xffffff38) + 500; - } - - if (iVar1 > _someCutoff + _totalTroopValueOfEnemy) { + int troopValueNearKeep = DAT_TroopValueState::instance.attackInfo.playerTotalTroopValueOfTroopsNearKeep[playerID]; + int enemyTroopValue = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; + + int margin; + if (enemyTroopValue < 50) + margin = -20; + else if (enemyTroopValue < 100) + margin = 0; + else if (enemyTroopValue < 200) + margin = 20; + else if (enemyTroopValue < 400) + margin = 100; + else if (enemyTroopValue < 600) + margin = 200; + else if (enemyTroopValue < 800) + margin = 300; + else + margin = 500; + + if (troopValueNearKeep > enemyTroopValue + margin) { DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue = 0; return; } @@ -41,13 +37,11 @@ namespace AI { if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue == 0) { if (DAT_GameState::instance.playerDataArray[playerID] .totalEnemyTroopValueByPlayerID[DAT_GameSynchronyState::instance.currentPlayerSlotID] - > iVar1) { + > troopValueNearKeep) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playNervous1BikFromPlayer, this)(playerID); - } MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::playRequestHelpBikFromPlayer, this)(playerID); } - - DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue = _one; + DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue = 1; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 328817b44..fcf08bd68 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35513,7 +35513,7 @@ SHC_3BB0A8C1_0x004D30E0 | 100.0% | Reimplemented, barring one register usage dif SHC_3BB0A8C1_0x004D3320 | 87.69% | Reimplemented, different register usage, effectively 100% -SHC_3BB0A8C1_0x004D3780 | 0.0% | Pending +SHC_3BB0A8C1_0x004D3780 | 74.0% | Constant 1 kept in register SHC_3BB0A8C1_0x004D3850 | 82.3% | AIC index folding differs From 7dee3f97e26e25753cf280657f4844b76960bc3f Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:23:59 +0200 Subject: [PATCH 166/242] reimplement: SHC_3BB0A8C1_0x004D1A00 58.00% Register allocation differs --- .../AICState/decideOnTribeAttackLocation.cpp | 207 ++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 91 insertions(+), 118 deletions(-) diff --git a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp index 5191a434e..21713a7e5 100644 --- a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp +++ b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp @@ -1,13 +1,11 @@ #include "../AICState.func.hpp" #include "OpenSHC/Game/GameStateStructures.func.hpp" -#include "OpenSHC/Global.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Random/RNG.func.hpp" #include "OpenSHC/Map/Units/UnitInstructionType.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -22,155 +20,130 @@ namespace OpenSHC { namespace AI { using OpenSHC::Map::Units::UnitInstructionType; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; // FUNCTION: STRONGHOLDCRUSADER 0x004D1A00 - void AICState ::decideOnTribeAttackLocation(uint tribeID_OR_moatWasHit) + void AICState::decideOnTribeAttackLocation(uint tribeID) { - uint _tribeID = tribeID_OR_moatWasHit; - - BOOLEnum _canHaveActivity - = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(tribeID_OR_moatWasHit, FALSE, TRUE); - if (_canHaveActivity != FALSE) { - DAT_TribesState::instance.tribes[_tribeID].counter = 0; + if (MACRO_CALL_MEMBER(AICState_Func::checkTribeActivityPercentages, this)(tribeID, FALSE, TRUE) != FALSE) { + DAT_TribesState::instance.tribes[tribeID].counter = 0; return; } - int _targetPlayer = (int)DAT_TribesState::instance.tribes[_tribeID].targetPlayer_outpost; - - if (DAT_TribesState::instance.tribes[_tribeID].randomNumber == 0) { - DAT_TribesState::instance.tribes[_tribeID].randomNumber = (int)SEC_RNG::instance.currentNumber2; + int targetPlayer = DAT_TribesState::instance.tribes[tribeID].targetPlayer_outpost; + if (DAT_TribesState::instance.tribes[tribeID].randomNumber == 0) { + DAT_TribesState::instance.tribes[tribeID].randomNumber = SEC_RNG::instance.currentNumber2; MACRO_CALL_MEMBER(OpenSHC::Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); } - int _rng = DAT_TribesState::instance.tribes[_tribeID].randomNumber; - short* psVar1 = &DAT_TribesState::instance.tribes[_tribeID].counter; - *psVar1 = *psVar1 + 1; - - if ((int)DAT_TribesState::instance.tribes[_tribeID].counter == _rng % 6 + 7) { - DAT_TribesState::instance.tribes[_tribeID].counter = 0; - tribeID_OR_moatWasHit = tribeID_OR_moatWasHit & 0xffffff00; - int _x = 0; - int _y = 0; - int _unitID = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::getUnitIDForIndexInTribe, DAT_TribesState::ptr)(_tribeID, 0); - if ((_unitID != 0) - && MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, - DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[_tribeID].owner, _targetPlayer, - (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].x)), - (uint)((int)((int)DAT_UnitsState::instance.units[_unitID].y)), (byte*)&tribeID_OR_moatWasHit, &_x, - &_y)) { - if ((char)tribeID_OR_moatWasHit != '\0') { + DAT_TribesState::instance.tribes[tribeID].counter++; + if (DAT_TribesState::instance.tribes[tribeID].counter + == DAT_TribesState::instance.tribes[tribeID].randomNumber % 6 + 7) { + DAT_TribesState::instance.tribes[tribeID].counter = 0; + byte moatWasHit = 0; + int x = 0; + int y = 0; + int unitID + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::getUnitIDForIndexInTribe, DAT_TribesState::ptr)( + tribeID, 0); + if (unitID != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, + DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[tribeID].owner, targetPlayer, + DAT_UnitsState::instance.units[unitID].x, DAT_UnitsState::instance.units[unitID].y, &moatWasHit, &x, + &y)) { + if (moatWasHit != 0) { MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( - _tribeID, ((UnitInstructionType)0x23), - DAT_ViewportRenderState::instance.translationMatrix[_y].addXgetTile + _x, 0, 0); + tribeID, (UnitInstructionType)35, DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x, + 0, 0); return; } MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( - _tribeID, OpenSHC::Map::Units::UIT_FILL_MOAT, _x, _y, 1000); + tribeID, OpenSHC::Map::Units::UIT_FILL_MOAT, x, y, 1000); return; } } - short sVar2 = DAT_TribesState::instance.tribes[_tribeID].tribeSubtype1; - - if ((sVar2 != 0xb6) && (sVar2 != 0xb9)) { - BOOLEnum BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, FALSE); - if (BVar4 != FALSE) + if (DAT_TribesState::instance.tribes[tribeID].tribeSubtype1 != 182 + && DAT_TribesState::instance.tribes[tribeID].tribeSubtype1 != 185) { + if (MACRO_CALL_MEMBER(AICState_Func::checkTribeActivityPercentages, this)(tribeID, FALSE, FALSE) != FALSE) return; - int _targetBuilding = (int)DAT_TribesState::instance.tribes[_tribeID].targetBuildingID; - if ((((_targetBuilding != 0) - && (DAT_BuildingsState::instance.buildings[_targetBuilding].uid - == DAT_TribesState::instance.tribes[_tribeID].targetBuildingUID)) - && (DAT_BuildingsState::instance.buildings[_targetBuilding].fireDuration == 0)) - && (BVar4 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID, FALSE, TRUE), - BVar4 != FALSE)) { - if (DAT_GameState::instance.mapAndTime.yearChanged == 0) - return; - DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = 0; + int targetBuildingID = DAT_TribesState::instance.tribes[tribeID].targetBuildingID; + if (targetBuildingID != 0 + && DAT_BuildingsState::instance.buildings[targetBuildingID].uid + == DAT_TribesState::instance.tribes[tribeID].targetBuildingUID + && DAT_BuildingsState::instance.buildings[targetBuildingID].fireDuration == 0 + && MACRO_CALL_MEMBER(AICState_Func::checkTribeActivityPercentages, this)(tribeID, FALSE, TRUE) != FALSE) { + if (DAT_GameState::instance.mapAndTime.yearChanged != 0) + DAT_TribesState::instance.tribes[tribeID].targetBuildingID = 0; return; } - int _buildingID - = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, - DAT_GameState::ptr)(_targetPlayer); - if (_buildingID != 0) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( - _tribeID, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, _buildingID, - DAT_BuildingsState::instance.buildings[_buildingID].uid, 0); - int _buildingUID = DAT_BuildingsState::instance.buildings[_buildingID].uid; - DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = (short)_buildingID; - DAT_TribesState::instance.tribes[_tribeID].targetBuildingUID = _buildingUID; + int buildingID = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + DAT_GameState::ptr)(targetPlayer); + if (buildingID != 0) { + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(tribeID, + OpenSHC::Map::Units::UIT_ATTACK_BUILDING, buildingID, DAT_BuildingsState::instance.buildings[buildingID].uid, + 0); + DAT_TribesState::instance.tribes[tribeID].targetBuildingID = buildingID; + DAT_TribesState::instance.tribes[tribeID].targetBuildingUID + = DAT_BuildingsState::instance.buildings[buildingID].uid; return; } - int _destinationX = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; - DAT_TribesState::instance.tribes[_tribeID].targetBuildingID = 0; - int _destinationY = DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry; - BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(_tribeID, - DAT_ViewportRenderState::instance.translationMatrix[_destinationY].addXgetTile + _destinationX); - if (BVar4 == FALSE) + int destinationX = DAT_GameState::instance.playerDataArray[targetPlayer].campground.xEntry; + DAT_TribesState::instance.tribes[tribeID].targetBuildingID = 0; + int destinationY = DAT_GameState::instance.playerDataArray[targetPlayer].campground.yEntry; + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( + tribeID, DAT_ViewportRenderState::instance.translationMatrix[destinationY].addXgetTile + destinationX) + == FALSE) return; - // was LAB_004d1c59 + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( - _tribeID, (uint)((int)(_destinationX)), (uint)((int)(_destinationY)), 1); + tribeID, destinationX, destinationY, 1); return; } - int _buildingID_2 - = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, - DAT_GameState::ptr)(_targetPlayer); - - int _destinationTile; - int _destinationX2; - int _destinationY2; - - if (_buildingID_2 == 0) { - int iVar5 = DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer].campground.yEntry] - .addXgetTile; - _destinationTile = iVar5 + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; + int buildingID = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + DAT_GameState::ptr)(targetPlayer); + int destinationTile; + if (buildingID == 0) { + destinationTile = DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[targetPlayer].campground.yEntry] + .addXgetTile + + DAT_GameState::instance.playerDataArray[targetPlayer].campground.xEntry; + } else if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) { + destinationTile = DAT_BuildingsState::instance.buildings[buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[buildingID].buildingEntryY] + .addXgetTile; } else { - int iVar5 = (int)DAT_TribesState::instance.tribes[_tribeID].selectionTargetUnitID; - if (iVar5 == 0) { - _destinationTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryY] - .addXgetTile; - } else { - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathfindingForAttacksUnk, - DAT_PathFindingState::ptr)(_tribeID, _buildingID_2, 1, - (dword)((int)((int)(short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_UnitsState::instance.units[iVar5].tile])), - _targetPlayer); - _destinationTile = DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile1; - if (DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper == 0) { - // was LAB_004d1d11 - int iVar5b = DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[_targetPlayer] - .campground.yEntry] - .addXgetTile; - _destinationTile - = iVar5b + DAT_GameState::instance.playerDataArray[_targetPlayer].campground.xEntry; - } - } + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathfindingForAttacksUnk, + DAT_PathFindingState::ptr)(tribeID, buildingID, 1, + (short)DAT_TileMapState::instance.PathConnectionLayer + [DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID].tile], + targetPlayer); + destinationTile = DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile1; + if (DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper == 0) + destinationTile + = DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[targetPlayer].campground.yEntry] + .addXgetTile + + DAT_GameState::instance.playerDataArray[targetPlayer].campground.xEntry; } - if (_destinationTile != 0) { - _destinationY2 = (int)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_destinationTile]; - _destinationX2 - = _destinationTile - DAT_ViewportRenderState::instance.translationMatrix[_destinationY2].addXgetTile; - BOOLEnum BVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( - _tribeID, _destinationTile); - if (BVar4 != FALSE) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( - _tribeID, (uint)((int)(_destinationX2)), (uint)((int)(_destinationY2)), 1); - return; - } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(_tribeID, _targetPlayer); + if (destinationTile == 0) + return; + + int destinationY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[destinationTile]; + int destinationX = destinationTile - DAT_ViewportRenderState::instance.translationMatrix[destinationY].addXgetTile; + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( + tribeID, destinationTile) + == FALSE) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(tribeID, targetPlayer); + return; } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + tribeID, destinationX, destinationY, 1); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index fcf08bd68..e8beab63d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35473,7 +35473,7 @@ SHC_3BB0A8C1_0x004D18B0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D1950 | 0.0% | Pending -SHC_3BB0A8C1_0x004D1A00 | 0.0% | Pending +SHC_3BB0A8C1_0x004D1A00 | 58.0% | Register allocation differs SHC_3BB0A8C1_0x004D1D60 | 52.5% | Stuck From d7f17660eb14f706eba51b94fff966ffb6e29c1f Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:34:22 +0200 Subject: [PATCH 167/242] reimplement: SHC_3BB0A8C1_0x004CDA50 100.00% Reimplemented --- .../addBuildingToTargetableBuildings.cpp | 22 ++++++++++++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp b/src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp index 8f92126ff..bd48cbe1c 100644 --- a/src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp +++ b/src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp @@ -1,5 +1,7 @@ #include "../AICState.func.hpp" +#include "OpenSHC/Game/GameMode.hpp" + #include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" @@ -10,14 +12,18 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CDA50 void AICState::addBuildingToTargetableBuildings(int buildingID) { - int _player = DAT_BuildingsState::instance.buildings[buildingID].owner; - if (DAT_GameSynchronyState::instance.DAT_CurrentGameMode != Game::GM_SOLITARY) { - int* piVar1 = &DAT_GameState::instance.playerDataArray[_player].top100TargetableBuildingsTracker; - if ((*piVar1 < 100) && (DAT_BuildingsState::instance.buildings[buildingID].fireDuration == 0)) { - DAT_GameState::instance.playerDataArray[_player].top100TargetableBuildings[*piVar1] = (short)buildingID; - *piVar1 = *piVar1 + 1; - } - } + int owner = DAT_BuildingsState::instance.buildings[buildingID].owner; + if (DAT_GameSynchronyState::instance.currentGameMode == Game::GM_SOLITARY) + return; + if (DAT_GameState::instance.playerDataArray[owner].top100TargetableBuildingsTracker >= 100) + return; + if (DAT_BuildingsState::instance.buildings[buildingID].fireDuration != 0) + return; + + DAT_GameState::instance.playerDataArray[owner] + .top100TargetableBuildings[DAT_GameState::instance.playerDataArray[owner].top100TargetableBuildingsTracker] + = buildingID; + DAT_GameState::instance.playerDataArray[owner].top100TargetableBuildingsTracker++; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e8beab63d..39ce06fbf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35283,7 +35283,7 @@ SHC_3BB0A8C1_0x004CD7B0 | 0.0% | Pending SHC_3BB0A8C1_0x004CD8F0 | 74.2% | Register allocation differs -SHC_3BB0A8C1_0x004CDA50 | 0.0% | Pending +SHC_3BB0A8C1_0x004CDA50 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CDAB0 | 100.0% | Reimplemented From 0890d4ad97e2af6e6145e720bea9d8c1cbc16684 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:34:22 +0200 Subject: [PATCH 168/242] reimplement: SHC_3BB0A8C1_0x004CC680 83.33% Register push placement diff --- .../AI/AICState/addEngineersToSelection.cpp | 44 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp b/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp index db3392918..7466c7338 100644 --- a/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp +++ b/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp @@ -3,6 +3,7 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/States/UnitState.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -13,30 +14,27 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC680 int AICState::addEngineersToSelection(int playerID, int unitCount) { - int tribeID; - uint unitID; + int tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { + if (unitCount <= 0) + return tribeID; + if (DAT_UnitsState::instance.units[unitID].logicalState != Map::Units::ULS_NORMAL) + continue; + if (DAT_UnitsState::instance.units[unitID].owner != playerID) + continue; + if (DAT_UnitsState::instance.units[unitID].dying != 0) + continue; + if (DAT_UnitsState::instance.units[unitID].unitType != Map::Units::UT_E_ENGINEER) + continue; + if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType != 10) + continue; + if (DAT_UnitsState::instance.units[unitID].tribeID != 0) + continue; + if (DAT_UnitsState::instance.units[unitID].state.generic == Map::Units::States::US_STAND_UPUnk) + continue; - tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - unitID = 1; - if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { - /* Unit offset 150 */ - Map::Units::Unit* _ptrUnit = &DAT_UnitsState::instance.units[1]; - do { - if (unitCount <= 0) { - return tribeID; - } - if ((((_ptrUnit->logicalState == Map::Units::ULS_NORMAL) && (_ptrUnit->owner == playerID)) - && (_ptrUnit->dying == 0)) - && (((_ptrUnit->unitType == Map::Units::UT_E_ENGINEER) && (_ptrUnit->aiUnitBehaviourType == 10)) - && ((_ptrUnit->tribeID == 0) - && ((_ptrUnit->state).generic != Map::Units::States::US_STAND_UPUnk)))) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( - unitID, tribeID); - unitCount = unitCount + -1; - } - unitID = unitID + 1; - _ptrUnit = _ptrUnit + 1; - } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + unitCount--; } return tribeID; } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 39ce06fbf..506fa0191 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34873,7 +34873,7 @@ SHC_3BB0A8C1_0x004CC520 | 0.0% | Pending SHC_3BB0A8C1_0x004CC5A0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CC680 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC680 | 83.3% | Register push placement diff SHC_3BB0A8C1_0x004CC6B0 | 0.0% | Pending From f28b0157c984e4eb83d4c9f3ea52729a552d2028 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:34:22 +0200 Subject: [PATCH 169/242] reimplement: SHC_3BB0A8C1_0x004D4040 96.97% Reimplemented --- .../AI/AICState/addEngineersToTribe.cpp | 31 ++++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp b/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp index 2d3d8b873..48bc61b6a 100644 --- a/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp +++ b/src/OpenSHC/AI/AICState/addEngineersToTribe.cpp @@ -1,6 +1,7 @@ #include "../AICState.func.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" +#include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -10,21 +11,21 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D4040 void AICState::addEngineersToTribe(int playerID) { - int _unitID = 1; - if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { - Map::Units::Unit* _pUnit = &DAT_UnitsState::instance.units[1]; - do { - /* if logicalState == normal && owner == playerID && unitType == 0x1e (engineer) - && aiUnitBehaviourType == 10 */ - if ((((_pUnit->logicalState == Map::Units::ULS_NORMAL) && (_pUnit->owner == playerID)) - && (_pUnit->dying == 0)) - && (((_pUnit->unitType == Map::Units::UT_E_ENGINEER) && (_pUnit->aiUnitBehaviourType == 10)) - && (_pUnit->tribeID == 0))) { - MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(_unitID, 10); - } - _unitID = _unitID + 1; - _pUnit = _pUnit + 1; - } while (_unitID < (int)DAT_UnitsState::instance.maxUnitCount); + for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { + if (DAT_UnitsState::instance.units[unitID].logicalState != Map::Units::ULS_NORMAL) + continue; + if (DAT_UnitsState::instance.units[unitID].owner != playerID) + continue; + if (DAT_UnitsState::instance.units[unitID].dying != 0) + continue; + if (DAT_UnitsState::instance.units[unitID].unitType != Map::Units::UT_E_ENGINEER) + continue; + if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType != 10) + continue; + if (DAT_UnitsState::instance.units[unitID].tribeID != 0) + continue; + + MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 10); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 506fa0191..e08493779 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35531,7 +35531,7 @@ SHC_3BB0A8C1_0x004D3AE0 | 0.0% | Pending SHC_3BB0A8C1_0x004D3F20 | 0.0% | Pending -SHC_3BB0A8C1_0x004D4040 | 100.0% | Reimplemented, for loop didn't work +SHC_3BB0A8C1_0x004D4040 | 97.0% | Reimplemented SHC_3BB0A8C1_0x004D40B0 | 100.0% | Reimplemented From 5af594ebb1fddcb0d366a7a8a3082f4f41eee9d8 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:34:23 +0200 Subject: [PATCH 170/242] reimplement: SHC_3BB0A8C1_0x004CFA10 96.88% Reimplemented --- .../AI/AICState/addRallyPointForTribe.cpp | 106 +++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 31 insertions(+), 77 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp b/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp index db4cc64bc..241944136 100644 --- a/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp +++ b/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp @@ -2,10 +2,8 @@ #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/Map/Navigation/PathFindingState.func.hpp" -#include "OpenSHC/Map/Units/Unit.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Map/Units/UnitTypeShort.hpp" #include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -16,86 +14,42 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Map::Units::Unit; - using OpenSHC::Map::Units::UnitLogicState; - using OpenSHC::Map::Units::UnitType; - using OpenSHC::Map::Units::UnitTypeShort; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CFA10 - void AICState ::addRallyPointForTribe(int tribeID) - + void AICState::addRallyPointForTribe(int tribeID) { - - short* psVar1; - - BOOLEnum _areInDifferentTeamsUnk; - - Unit* _ptrUnit; - - UnitTypeShort _unitType; - DAT_TribesState::instance.tribes[tribeID].rallyPointCount = 0; - - _ptrUnit = &DAT_UnitsState::instance.units[1]; - - do { - - if (_ptrUnit->logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) { - - _areInDifferentTeamsUnk = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::getTeamsDifferent, - DAT_GameState::ptr)(DAT_TribesState::instance.tribes[tribeID].owner, (int)((int)(_ptrUnit->owner))); - - if (_areInDifferentTeamsUnk == FALSE) { - - _unitType = _ptrUnit->unitType; - - if ((((_unitType == OpenSHC::Map::Units::UT_S_CATAPULT) - || (_unitType == OpenSHC::Map::Units::UT_S_TREBUCHET)) - || (_unitType == OpenSHC::Map::Units::UT_S_FBALLISTA)) - && (_ptrUnit->unknownSiegeTentRelated02 == 3)) { - - MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::computeNextRallyPointDestination, - DAT_PathFindingState::ptr)(-1, (int)((int)(_ptrUnit->x)), (int)((int)(_ptrUnit->y))); - - DAT_TribesState::instance.tribes[tribeID] - .rallyPointArray[DAT_TribesState::instance.tribes[tribeID].rallyPointCount][0] - = (short)DAT_PathFindingState::instance.ALG_ResultX; - - DAT_TribesState::instance.tribes[tribeID] - .rallyPointArray[DAT_TribesState::instance.tribes[tribeID].rallyPointCount][1] - = (short)DAT_PathFindingState::instance.ALG_ResultY; - - psVar1 = &DAT_TribesState::instance.tribes[tribeID].rallyPointCount; - - *psVar1 = *psVar1 + 1; - - if (8 < DAT_TribesState::instance.tribes[tribeID].rallyPointCount) - break; - } - } - } - - _ptrUnit = _ptrUnit + 0x248; - - } while ((int)_ptrUnit < 0x165141a); - - if (DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex < 0) { - - DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex = 0; + for (int unitID = 1; unitID < 2500; unitID++) { + if (DAT_UnitsState::instance.units[unitID].logicalState == OpenSHC::Map::Units::ULS_INVISIBLE) + continue; + if (MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::getTeamsDifferent, DAT_GameState::ptr)( + DAT_TribesState::instance.tribes[tribeID].owner, DAT_UnitsState::instance.units[unitID].owner) + != FALSE) + continue; + if (DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_S_CATAPULT + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_S_TREBUCHET + && DAT_UnitsState::instance.units[unitID].unitType != OpenSHC::Map::Units::UT_S_FBALLISTA) + continue; + if (DAT_UnitsState::instance.units[unitID].unknownSiegeTentRelated02 != 3) + continue; + + MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeNextRallyPointDestination, + DAT_PathFindingState::ptr)(-1, DAT_UnitsState::instance.units[unitID].x, DAT_UnitsState::instance.units[unitID].y); + DAT_TribesState::instance.tribes[tribeID] + .rallyPointArray[DAT_TribesState::instance.tribes[tribeID].rallyPointCount][0] + = DAT_PathFindingState::instance.ALG_ResultX; + DAT_TribesState::instance.tribes[tribeID] + .rallyPointArray[DAT_TribesState::instance.tribes[tribeID].rallyPointCount][1] + = DAT_PathFindingState::instance.ALG_ResultY; + DAT_TribesState::instance.tribes[tribeID].rallyPointCount++; + if (DAT_TribesState::instance.tribes[tribeID].rallyPointCount >= 9) + break; } - if (DAT_TribesState::instance.tribes[tribeID].rallyPointCount - <= DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex) { - + if (DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex < 0) + DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex = 0; + if (DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex + >= DAT_TribesState::instance.tribes[tribeID].rallyPointCount) DAT_TribesState::instance.tribes[tribeID].currentRallyPointIndex = 0; - } - - return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e08493779..f28172d6b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35381,7 +35381,7 @@ SHC_3BB0A8C1_0x004CF870 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CF920 | 96.9% | Reimplemented -SHC_3BB0A8C1_0x004CFA10 | 0.0% | Pending +SHC_3BB0A8C1_0x004CFA10 | 96.9% | Reimplemented SHC_3BB0A8C1_0x004CFB20 | 97.8% | Reimplemented From f9dc9049955d1ef7437fcab823e353f6286808d2 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:34:23 +0200 Subject: [PATCH 171/242] reimplement: SHC_3BB0A8C1_0x004CC720 95.24% Reimplemented --- .../AI/AICState/addUnitsToTribe166.cpp | 36 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp b/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp index fa55cb886..5e0cbafd8 100644 --- a/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp +++ b/src/OpenSHC/AI/AICState/addUnitsToTribe166.cpp @@ -12,25 +12,23 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC720 void AICState::addUnitsToTribe166(int playerID) { - int tribeID; - uint unitID = 1; - if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { - Map::Units::Unit* pUVar1 = &DAT_UnitsState::instance.units[1]; - do { - if ((((pUVar1->owner == playerID) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) - && (pUVar1->dying == 0)) - && (pUVar1->aiUnitBehaviourType == 6)) { - tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; - if (pUVar1->tribeID != tribeID) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( - unitID, (int)pUVar1->tribeID); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( - unitID, tribeID); - } - } - unitID = unitID + 1; - pUVar1 = pUVar1 + 1; - } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { + if (DAT_UnitsState::instance.units[unitID].owner != playerID) + continue; + if (DAT_UnitsState::instance.units[unitID].logicalState != Map::Units::ULS_NORMAL) + continue; + if (DAT_UnitsState::instance.units[unitID].dying != 0) + continue; + if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType != 6) + continue; + + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; + if (DAT_UnitsState::instance.units[unitID].tribeID == tribeID) + continue; + + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, DAT_UnitsState::instance.units[unitID].tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f28172d6b..b7043c83e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34877,7 +34877,7 @@ SHC_3BB0A8C1_0x004CC680 | 83.3% | Register push placement diff SHC_3BB0A8C1_0x004CC6B0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CC720 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC720 | 95.2% | Reimplemented SHC_3BB0A8C1_0x004CC7B0 | 0.0% | Pending From 18fd733c240f3d382f26f06f0f8d802c42f02c39 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:39:53 +0200 Subject: [PATCH 172/242] reimplement: SHC_3BB0A8C1_0x004D27E0 92.00% Reimplemented --- src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp | 18 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp index 77bb32f81..cf99d0e24 100644 --- a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp @@ -13,15 +13,15 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D27E0 void AICState::addUnitToItsTribe(int unitID, int aiUnitBehaviourType) { - int iVar1 = (int)DAT_UnitsState::instance.units[unitID].owner; - if (DAT_GameState::instance.playerDataArray[iVar1].aiType != AITA_NULL) { - DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = (short)aiUnitBehaviourType; - iVar1 = MACRO_CALL_MEMBER(AICState_Func::addUnitToSmallestBehaviourTypeTribe, this)( - iVar1, unitID, aiUnitBehaviourType); - if (iVar1 != 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); - } - } + int owner = DAT_UnitsState::instance.units[unitID].owner; + if (DAT_GameState::instance.playerDataArray[owner].aiType == AITA_NULL) + return; + + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = aiUnitBehaviourType; + int tribeID + = MACRO_CALL_MEMBER(AICState_Func::addUnitToSmallestBehaviourTypeTribe, this)(owner, unitID, aiUnitBehaviourType); + if (tribeID != 0) + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b7043c83e..b2a4297ca 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35493,7 +35493,7 @@ SHC_3BB0A8C1_0x004D2730 | 0.0% | Pending SHC_3BB0A8C1_0x004D2790 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D27E0 | 100.0% | Reimplemented +SHC_3BB0A8C1_0x004D27E0 | 92.0% | Reimplemented SHC_3BB0A8C1_0x004D2830 | 100.0% | Reimplemented From 85abc53c4091c246aa47acbdc4dd6a886d2ebc88 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:39:54 +0200 Subject: [PATCH 173/242] reimplement: SHC_3BB0A8C1_0x004D2730 79.17% AIC index folding differs --- .../AICState/addUnitToSmallestPatrolTribe.cpp | 19 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp index a4ec79c91..40602a5c4 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp @@ -1,10 +1,8 @@ #include "../AICState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" -#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" -#include "OpenSHC/Globals/DAT_AICState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -15,14 +13,15 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D2730 void AICState::addUnitToSmallestPatrolTribe(int unitID) { - int iVar1 = (int)DAT_UnitsState::instance.units[unitID].owner; - int _aiType = DAT_GameState::instance.playerDataArray[iVar1].aiType; - if (_aiType != AITA_NULL) { - DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 4; - iVar1 = MACRO_CALL_MEMBER(AI::AICState_Func::getSmallestPatrolTribe, DAT_AICState::ptr)( - iVar1, (int)this->aics[_aiType - 1].OuterPatrolGroupsCount); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, iVar1); - } + int owner = DAT_UnitsState::instance.units[unitID].owner; + int aiType = DAT_GameState::instance.playerDataArray[owner].aiType; + if (aiType == AITA_NULL) + return; + + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 4; + int tribeID = MACRO_CALL_MEMBER(AICState_Func::getSmallestPatrolTribe, this)( + owner, this->aics[aiType - 1].OuterPatrolGroupsCount); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b2a4297ca..4d32dd9bb 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35489,7 +35489,7 @@ SHC_3BB0A8C1_0x004D2500 | 0.0% | Pending SHC_3BB0A8C1_0x004D2660 | 0.0% | Pending -SHC_3BB0A8C1_0x004D2730 | 0.0% | Pending +SHC_3BB0A8C1_0x004D2730 | 79.2% | AIC index folding differs SHC_3BB0A8C1_0x004D2790 | 100.0% | Reimplemented From 28422d42c7c7191f79d68c0e1f2bcaf777fb88a5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:39:54 +0200 Subject: [PATCH 174/242] reimplement: SHC_3BB0A8C1_0x004CC840 94.29% Reimplemented --- .../AICState/aiAddUnitToMoatDiggerTribe.cpp | 21 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp index c9a91b8db..3db77b3cc 100644 --- a/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp @@ -12,20 +12,17 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC840 void AICState::aiAddUnitToMoatDiggerTribe(int unitID) { - int _owner = (int)DAT_UnitsState::instance.units[unitID].owner; + int owner = DAT_UnitsState::instance.units[unitID].owner; DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 5; - int _tribe = (int)DAT_GameState::instance.playerDataArray[_owner].aiTribeIDs[10]; - if ((_tribe == 0) - || (DAT_TribesState::instance.tribes[_tribe].uid - != DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10])) { - _tribe - = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_owner); - int _uid = DAT_TribesState::instance.tribes[_tribe].uid; - DAT_GameState::instance.playerDataArray[_owner].aiTribeIDs[10] = (short)_tribe; - DAT_GameState::instance.playerDataArray[_owner].aiTribeUIDs[10] = _uid; + int tribeID = DAT_GameState::instance.playerDataArray[owner].aiTribeIDs[10]; + if (tribeID == 0 + || DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[owner].aiTribeUIDs[10]) { + tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(owner); + DAT_GameState::instance.playerDataArray[owner].aiTribeIDs[10] = tribeID; + DAT_GameState::instance.playerDataArray[owner].aiTribeUIDs[10] = DAT_TribesState::instance.tribes[tribeID].uid; } - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribe); - DAT_TribesState::instance.tribes[_tribe].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4d32dd9bb..fd9415ce6 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34881,7 +34881,7 @@ SHC_3BB0A8C1_0x004CC720 | 95.2% | Reimplemented SHC_3BB0A8C1_0x004CC7B0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CC840 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC840 | 94.3% | Reimplemented SHC_3BB0A8C1_0x004CC8D0 | 100.0% | Reimplemented From ba5fa9d2e900f25f554f11ccdb373fe222a58319 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:39:54 +0200 Subject: [PATCH 175/242] reimplement: SHC_3BB0A8C1_0x004D2790 91.30% Reimplemented --- .../AI/AICState/aiAssignUnitToDefensiveTribe.cpp | 16 ++++++++-------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp index cccc97fe4..bd7a41dec 100644 --- a/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiAssignUnitToDefensiveTribe.cpp @@ -13,14 +13,14 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D2790 void AICState::aiAssignUnitToDefensiveTribe(int unitID) { - int _playerID = (int)DAT_UnitsState::instance.units[unitID].owner; - if (DAT_GameState::instance.playerDataArray[_playerID].aiType != AITA_NULL) { - DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 2; - int _tribeID = MACRO_CALL_MEMBER(AICState_Func::getDefensiveTribeForUnit, this)(_playerID, unitID); - if (_tribeID != 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); - } - } + int owner = DAT_UnitsState::instance.units[unitID].owner; + if (DAT_GameState::instance.playerDataArray[owner].aiType == AITA_NULL) + return; + + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 2; + int tribeID = MACRO_CALL_MEMBER(AICState_Func::getDefensiveTribeForUnit, this)(owner, unitID); + if (tribeID != 0) + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index fd9415ce6..e4acffefb 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35491,7 +35491,7 @@ SHC_3BB0A8C1_0x004D2660 | 0.0% | Pending SHC_3BB0A8C1_0x004D2730 | 79.2% | AIC index folding differs -SHC_3BB0A8C1_0x004D2790 | 100.0% | Reimplemented +SHC_3BB0A8C1_0x004D2790 | 91.3% | Reimplemented SHC_3BB0A8C1_0x004D27E0 | 92.0% | Reimplemented From 67aaa70b4be929083221c1a02fe74aab7ade4dce Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:39:55 +0200 Subject: [PATCH 176/242] reimplement: SHC_3BB0A8C1_0x004D40B0 94.87% Reimplemented --- .../AICState/aiReassignTunnelersToTribe.cpp | 28 +++++++++++-------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp index cc833862a..6165dd546 100644 --- a/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiReassignTunnelersToTribe.cpp @@ -4,7 +4,6 @@ #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -12,19 +11,24 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D40B0 - void AICState::aiReassignTunnelersToTribe(int param_1) + void AICState::aiReassignTunnelersToTribe(int playerID) { for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { - Map::Units::Unit* _pUnit = &DAT_UnitsState::instance.units[unitID]; - if ((((_pUnit->logicalState == Map::Units::ULS_NORMAL) && (_pUnit->owner == param_1)) - && (_pUnit->dying == 0)) - && ((_pUnit->unitType == Map::Units::UT_TUNNELER && (_pUnit->aiUnitBehaviourType == 0xf)))) { - if (_pUnit->tribeID != 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( - unitID, (int)_pUnit->tribeID); - } - MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 0xf); - } + if (DAT_UnitsState::instance.units[unitID].logicalState != Map::Units::ULS_NORMAL) + continue; + if (DAT_UnitsState::instance.units[unitID].owner != playerID) + continue; + if (DAT_UnitsState::instance.units[unitID].dying != 0) + continue; + if (DAT_UnitsState::instance.units[unitID].unitType != Map::Units::UT_TUNNELER) + continue; + if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType != 15) + continue; + + if (DAT_UnitsState::instance.units[unitID].tribeID != 0) + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, DAT_UnitsState::instance.units[unitID].tribeID); + MACRO_CALL_MEMBER(AICState_Func::addUnitToItsTribe, this)(unitID, 15); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e4acffefb..3d3cb1754 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35533,7 +35533,7 @@ SHC_3BB0A8C1_0x004D3F20 | 0.0% | Pending SHC_3BB0A8C1_0x004D4040 | 97.0% | Reimplemented -SHC_3BB0A8C1_0x004D40B0 | 100.0% | Reimplemented +SHC_3BB0A8C1_0x004D40B0 | 94.9% | Reimplemented SHC_3BB0A8C1_0x004D4130 | 100.0% | Reimplemented From a8623042e08f0c4c316a086c404332e183b36c2f Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:39:55 +0200 Subject: [PATCH 177/242] reimplement: SHC_3BB0A8C1_0x004CC520 93.75% Reimplemented --- .../AI/AICState/aiRecruitEngineers.cpp | 34 +++++++++++-------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp b/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp index c42651eeb..23c4bf441 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitEngineers.cpp @@ -14,20 +14,26 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC520 void AICState::aiRecruitEngineers(int playerID) { - int recruitmentBuilding; - int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if ((((_aiType != AITA_NULL) && (DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired != FALSE)) - && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) - && (((0x1d < (int)this->aics[_aiType - 1].recruitGoldThreshold - + DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] - && (recruitmentBuilding = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, - 0 < recruitmentBuilding)) - && (DAT_BuildingsState::instance.buildings[recruitmentBuilding].buildingType - == Map::Buildings::BT_ENGINEERSGUILD)))) { - MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( - Map::Units::UT_E_ENGINEER, recruitmentBuilding, playerID, 0); - DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = FALSE; - } + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) + return; + if (DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired == FALSE) + return; + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) + return; + if (this->aics[aiType - 1].recruitGoldThreshold + + DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] + < 30) + return; + int guildID = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + if (guildID <= 0) + return; + if (DAT_BuildingsState::instance.buildings[guildID].buildingType != Map::Buildings::BT_ENGINEERSGUILD) + return; + + MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + Map::Units::UT_E_ENGINEER, guildID, playerID, 0); + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = FALSE; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3d3cb1754..11c5cfb0e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34869,7 +34869,7 @@ SHC_3BB0A8C1_0x004CC390 | 0.0% | Pending SHC_3BB0A8C1_0x004CC420 | 38.0% | Loop strength reduction diff -SHC_3BB0A8C1_0x004CC520 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC520 | 93.8% | Reimplemented SHC_3BB0A8C1_0x004CC5A0 | 0.0% | Pending From 9579581b48ac8808fdf6c022e4bd3a773f505ac6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:39:55 +0200 Subject: [PATCH 178/242] reimplement: SHC_3BB0A8C1_0x004CF660 97.22% Reimplemented --- .../AICState/aiCommandWallAssaultTribes.cpp | 34 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp index 3f1f25be3..a1b457e72 100644 --- a/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandWallAssaultTribes.cpp @@ -11,24 +11,24 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF660 - void AICState::aiCommandWallAssaultTribes(int param_1) + void AICState::aiCommandWallAssaultTribes(int playerID) { - if (DAT_GameState::instance.playerDataArray[param_1].aiType != AITA_NULL) { - int iVar1 = 0; - short* psVar2 = DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs + 0xbe; - do { - int tribeID = (int)*psVar2; - if (((tribeID != 0) - && (DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[param_1].aiTribeUIDs[iVar1 + 0xbe])) - && (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID != 0)) { - DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( - tribeID, Map::Units::STBT_0x3f2); - } - iVar1 = iVar1 + 1; - psVar2 = psVar2 + 1; - } while (iVar1 < 2); + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) + return; + + for (int i = 0; i < 2; i++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[190 + i]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[i + 190]) + continue; + if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) + continue; + + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, Map::Units::STBT_0x3f2); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 11c5cfb0e..017596043 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35367,7 +35367,7 @@ SHC_3BB0A8C1_0x004CF560 | 37.74% | Reimplemented functionally, different registe SHC_3BB0A8C1_0x004CF5E0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CF660 | 100.0% | Reimplemented without for-loop +SHC_3BB0A8C1_0x004CF660 | 97.2% | Reimplemented SHC_3BB0A8C1_0x004CF6E0 | 62.22% | Reimplemented functionally, different register usage From 01be9ea0f2d29a4996993a427e06cf5e8ec3b294 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:44:40 +0200 Subject: [PATCH 179/242] reimplement: SHC_3BB0A8C1_0x004CB4D0 97.50% Reimplemented --- .../AI/AICState/aiShouldBuildIronMine.cpp | 26 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp index 7ddf0e041..155e3e57a 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp @@ -12,23 +12,21 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB4D0 uint AICState::aiShouldBuildIronMine(PlayerID playerID) { - int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (aiType == AITA_NULL) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) return 0; - } - AICSpecification const* spec = &this->aics[aiType - 1]; - if ((int)spec->populationPerIronmine <= 0) { + int aicIndex = aiType - 1; + if (this->aics[aicIndex].populationPerIronmine <= 0) return 0; - } - int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, - DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_IRONMINE, 1); - if (iVar3 < 1) { - iVar3 = 1; - } else if (iVar3 >= (int)spec->maxIronmines) { + + int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)( + playerID, Map::Buildings::BT_IRONMINE, 1); + if (count <= 0) + count = 1; + else if (count >= this->aics[aicIndex].maxIronmines) return 0; - } - return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / iVar3 - >= (int)spec->populationPerIronmine; + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / count + >= this->aics[aicIndex].populationPerIronmine; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 017596043..4fd735068 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34217,7 +34217,7 @@ SHC_3BB0A8C1_0x004CB330 | 0.0% | Pending SHC_3BB0A8C1_0x004CB3A0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CB4D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB4D0 | 97.5% | Reimplemented SHC_3BB0A8C1_0x004CB540 | 0.0% | Pending From c434c4b9405ad299227cf7fcab0343468337bbac Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:44:40 +0200 Subject: [PATCH 180/242] reimplement: SHC_3BB0A8C1_0x004CB540 97.50% Reimplemented --- .../AI/AICState/aiShouldBuildPitchrig.cpp | 32 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp index 0227c21c7..b09490a9d 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp @@ -10,27 +10,23 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB540 - uint AICState::aiShouldBuildPitchrig(PlayerID param_1) + uint AICState::aiShouldBuildPitchrig(PlayerID playerID) { - int const aiType = DAT_GameState::instance.playerDataArray[param_1].aiType; - if (aiType == AITA_NULL) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) return 0; - } - AICSpecification const* spec = &this->aics[aiType - 1]; - if ((int)spec->populationPerPitchrig <= 0) { + int aicIndex = aiType - 1; + if (this->aics[aicIndex].populationPerPitchrig <= 0) return 0; - } - int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, - DAT_BuildingsState::ptr)(param_1, Map::Buildings::BT_PITCHRIG, 1); - if (iVar3 < 1) { - iVar3 = 1; - } else { - if (iVar3 >= (int)spec->maxPitchrigs) { - return 0; - } - } - return DAT_GameState::instance.playerDataArray[param_1].currentPopulation / iVar3 - >= (int)spec->populationPerPitchrig; + + int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)( + playerID, Map::Buildings::BT_PITCHRIG, 1); + if (count <= 0) + count = 1; + else if (count >= this->aics[aicIndex].maxPitchrigs) + return 0; + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / count + >= this->aics[aicIndex].populationPerPitchrig; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4fd735068..9daf94d64 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34219,7 +34219,7 @@ SHC_3BB0A8C1_0x004CB3A0 | 0.0% | Pending SHC_3BB0A8C1_0x004CB4D0 | 97.5% | Reimplemented -SHC_3BB0A8C1_0x004CB540 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB540 | 97.5% | Reimplemented SHC_3BB0A8C1_0x004CB5B0 | 0.0% | Pending From b2012ee07917bad76871f8ef2dc736028a397dfc Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:44:41 +0200 Subject: [PATCH 181/242] reimplement: SHC_3BB0A8C1_0x004CB330 97.50% Reimplemented --- .../AI/AICState/aiShouldBuildQuarry.cpp | 26 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp index ac4afab74..86930a063 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp @@ -12,23 +12,21 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB330 uint AICState::aiShouldBuildQuarry(PlayerID playerID) { - int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (aiType == AITA_NULL) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) return 0; - } - AICSpecification const* spec = &this->aics[aiType - 1]; - if ((int)spec->populationPerQuarry <= 0) { + int aicIndex = aiType - 1; + if (this->aics[aicIndex].populationPerQuarry <= 0) return 0; - } - int _quarryCount = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, - DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_QUARRY, 1); - if (_quarryCount < 1) { - _quarryCount = 1; - } else if (_quarryCount >= (int)spec->maxQuarries) { + + int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)( + playerID, Map::Buildings::BT_QUARRY, 1); + if (count <= 0) + count = 1; + else if (count >= this->aics[aicIndex].maxQuarries) return 0; - } - return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / _quarryCount - >= (int)spec->populationPerQuarry; + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / count + >= this->aics[aicIndex].populationPerQuarry; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9daf94d64..27f77263c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34213,7 +34213,7 @@ SHC_3BB0A8C1_0x004CB220 | 0.0% | Pending SHC_3BB0A8C1_0x004CB290 | 0.0% | Pending -SHC_3BB0A8C1_0x004CB330 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB330 | 97.5% | Reimplemented SHC_3BB0A8C1_0x004CB3A0 | 0.0% | Pending From 201352c7877d09074c0c8d039a5f008ff29507df Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:44:41 +0200 Subject: [PATCH 182/242] reimplement: SHC_3BB0A8C1_0x004CC5A0 85.71% Register allocation differs --- .../assignRequiredIdleEngineersToNewTribe.cpp | 56 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp index d1f3f4888..f05cf559c 100644 --- a/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp +++ b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp @@ -4,7 +4,6 @@ #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_TribesState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" @@ -14,33 +13,34 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC5A0 int AICState::assignRequiredIdleEngineersToNewTribe(int playerID, int count) { - Map::Units::States::UnitStateShort UVar1; - int tribeID - = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - uint unitID = 1; - if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { - Map::Units::Unit* psVar2 = &DAT_UnitsState::instance.units[1]; - do { - if (count < 1) { - return tribeID; - } - if (((((psVar2->logicalState == Map::Units::ULS_NORMAL) && (psVar2->owner == playerID)) - && (psVar2->dying == 0)) - && ((psVar2->unitType == Map::Units::UT_E_ENGINEER && (psVar2->aiUnitBehaviourType != 0x16)))) - && ((psVar2->aiUnitBehaviourType != 10 && (psVar2->engineerRelatedUnk == 0))) - && (((UVar1 = (psVar2->state).generic, UVar1 == 0x69 || (UVar1 == 2)) - || (UVar1 == Map::Units::States::US_IDLEUnk)))) { - if (psVar2->tribeID != 0) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( - unitID, (int)psVar2->tribeID); - } - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( - unitID, tribeID); - count = count + -1; - } - unitID = unitID + 1; - psVar2 = psVar2 + 1; - } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + int tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { + if (count <= 0) + return tribeID; + if (DAT_UnitsState::instance.units[unitID].logicalState != Map::Units::ULS_NORMAL) + continue; + if (DAT_UnitsState::instance.units[unitID].owner != playerID) + continue; + if (DAT_UnitsState::instance.units[unitID].dying != 0) + continue; + if (DAT_UnitsState::instance.units[unitID].unitType != Map::Units::UT_E_ENGINEER) + continue; + if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType == 22) + continue; + if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType == 10) + continue; + if (DAT_UnitsState::instance.units[unitID].engineerRelatedUnk != 0) + continue; + if (DAT_UnitsState::instance.units[unitID].state.generic != 105 + && DAT_UnitsState::instance.units[unitID].state.generic != 2 + && DAT_UnitsState::instance.units[unitID].state.generic != Map::Units::States::US_IDLEUnk) + continue; + + if (DAT_UnitsState::instance.units[unitID].tribeID != 0) + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, DAT_UnitsState::instance.units[unitID].tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + count--; } return tribeID; } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 27f77263c..25e77c423 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34871,7 +34871,7 @@ SHC_3BB0A8C1_0x004CC420 | 38.0% | Loop strength reduction diff SHC_3BB0A8C1_0x004CC520 | 93.8% | Reimplemented -SHC_3BB0A8C1_0x004CC5A0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC5A0 | 85.7% | Register allocation differs SHC_3BB0A8C1_0x004CC680 | 83.3% | Register push placement diff From dbcfb4e34c70363c32ee7e7598faf9a55e684a5c Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:51:19 +0200 Subject: [PATCH 183/242] reimplement: SHC_3BB0A8C1_0x004D48F0 86.67% Register allocation differs --- src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp | 46 ++++--------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 11 insertions(+), 37 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp b/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp index 907bb3a06..2d81632a7 100644 --- a/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp +++ b/src/OpenSHC/AI/AICState/aiBuyAndSellGoods.cpp @@ -1,53 +1,27 @@ #include "../AICState.func.hpp" -#include "OpenSHC/Game/Player/PlayerData.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" - #include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { - using OpenSHC::Game::Player::PlayerData; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - // FUNCTION: STRONGHOLDCRUSADER 0x004D48F0 - void AICState ::aiBuyAndSellGoods(int playerID) - + void AICState::aiBuyAndSellGoods(int playerID) { - - PlayerData* _pPlayerData; - - int _pMarketID; - - _pMarketID = DAT_GameState::instance.playerDataArray[playerID].marketplace.id; - + int marketID = DAT_GameState::instance.playerDataArray[playerID].marketplace.id; DAT_GameState::instance.playerDataArray[playerID].hasMarketUnk = 0; - - if (_pMarketID != 0) { - + if (marketID != 0) DAT_GameState::instance.playerDataArray[playerID].hasMarketUnk = 1; - } - - if (DAT_GameState::instance.playerDataArray[playerID].hasMarketUnk != 0) { - - _pPlayerData = &DAT_GameState::instance.playerDataArray[playerID]; - - _pPlayerData->willBuy = _pPlayerData->willBuy ^ TRUE; - - if (_pPlayerData->willBuy == FALSE) { - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellExcessGoods, this)(playerID); - - return; - } - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::buyRequiredGoods, this)(playerID); + if (DAT_GameState::instance.playerDataArray[playerID].hasMarketUnk == 0) + return; + DAT_GameState::instance.playerDataArray[playerID].willBuy + = DAT_GameState::instance.playerDataArray[playerID].willBuy ^ TRUE; + if (DAT_GameState::instance.playerDataArray[playerID].willBuy == FALSE) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellExcessGoods, this)(playerID); return; } - - return; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::buyRequiredGoods, this)(playerID); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 25e77c423..f64a75d65 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35555,7 +35555,7 @@ SHC_3BB0A8C1_0x004D4680 | 64.80% | Stuck, register usage SHC_3BB0A8C1_0x004D4870 | 0.0% | Pending -SHC_3BB0A8C1_0x004D48F0 | 100.0% | Reimplemented +SHC_3BB0A8C1_0x004D48F0 | 86.7% | Register allocation differs SHC_3BB0A8C1_0x004D4940 | 100.0% | Reimplemented From 46a25b2e610b10fb744cb5fbcef9067fe72d2cbb Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:51:20 +0200 Subject: [PATCH 184/242] reimplement: SHC_3BB0A8C1_0x004CEC80 100.00% Reimplemented --- .../aiChoiceAttForceRallyPercentage.cpp | 71 +++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 26 insertions(+), 47 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp index 1b408cc26..890450502 100644 --- a/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp +++ b/src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp @@ -1,7 +1,6 @@ #include "../AICState.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" @@ -10,56 +9,36 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CEC80 - BOOLEnum AICState ::aiChoiceAttForceRallyPercentage(int param_1) - + BOOLEnum AICState::aiChoiceAttForceRallyPercentage(int playerID) { - - AITypeInt _aiType = DAT_GameState::instance.playerDataArray[param_1].aiType; - - if (_aiType == OpenSHC::AI::AIT_NULL) { - - return 0; - } - - int const _aiIndex = _aiType - 1; - int _activeTribes = 0; - int _nonMoving = 0; - - for (int _index = 0; _index < 11; _index++) { - - int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeType; - - int const _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index].tribeCount; - - for (int _tribeIndex = 0; _tribeIndex < _maxTribeCount; _tribeIndex++) { - - int const _tribeID - = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - - if (((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[param_1] - .aiTribeUIDs[_tribeIndex + _tribeTypeStart])) - && (_activeTribes += 1, DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk < 0x14)) { - - _nonMoving += 1; - } + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) + return FALSE; + int aicIndex = aiType - 1; + + int activeTribes = 0; + int rallyingTribes = 0; + for (int i = 0; i < 11; i++) { + int tribeType = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType; + int tribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeCount; + for (int j = 0; j < tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeType + j]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[j + tribeType]) + continue; + + activeTribes++; + if (DAT_TribesState::instance.tribes[tribeID].percentageMovingUnk < 20) + rallyingTribes++; } } - if (_activeTribes <= 0) { - - return 0; - } - - return (uint)((_nonMoving * 100) / _activeTribes >= (int)this->aics[_aiIndex].AttForceRallyPercentage); + if (activeTribes <= 0) + return FALSE; + return rallyingTribes * 100 / activeTribes >= this->aics[aicIndex].AttForceRallyPercentage; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f64a75d65..358330f10 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35341,7 +35341,7 @@ SHC_3BB0A8C1_0x004CEB50 | 98.8% | Reimplemented SHC_3BB0A8C1_0x004CEB80 | 0.0% | Pending -SHC_3BB0A8C1_0x004CEC80 | 0.0% | Pending +SHC_3BB0A8C1_0x004CEC80 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CED90 | 100.0% | Reimplemented From bc8a2033ccf2aef0dab03c0fb5babd6e26f9beae Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:51:20 +0200 Subject: [PATCH 185/242] reimplement: SHC_3BB0A8C1_0x004D0580 95.65% Reimplemented --- .../AI/AICState/aiOfTypeInCurrentGame.cpp | 51 ++++--------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 11 insertions(+), 42 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp b/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp index dcb0264d5..b8de9aefa 100644 --- a/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp +++ b/src/OpenSHC/AI/AICState/aiOfTypeInCurrentGame.cpp @@ -1,55 +1,24 @@ #include "../AICState.func.hpp" -#include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/Game/Player/PlayerData.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" - #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::Game::Player::PlayerData; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - 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 0x004D0580 - BOOLEnum AICState ::aiOfTypeInCurrentGame(int param_1) - + BOOLEnum AICState::aiOfTypeInCurrentGame(int aicIndex) { - - int* _ptrCurrentAIArray; - - PlayerData* _playerData; - - _playerData = &DAT_GameState::instance.playerDataArray[1]; - - _ptrCurrentAIArray = DAT_GameSynchronyState::instance.currentAIArray + 1; - - while (((*_ptrCurrentAIArray == 0 || (_playerData->lordKilledByPlayerID != 0)) - || (param_1 != _playerData->aiType + ~OpenSHC::AI::AIT_NULL))) { - - _ptrCurrentAIArray = _ptrCurrentAIArray + 1; - - _playerData = _playerData + 0xe7d; - - if (0x191de9f < (int)_ptrCurrentAIArray) { - - return FALSE; - } + for (int playerID = 1; playerID < 9; playerID++) { + if (DAT_GameSynchronyState::instance.currentAIArray[playerID] == 0) + continue; + if (DAT_GameState::instance.playerDataArray[playerID].lordKilledByPlayerID != 0) + continue; + if (DAT_GameState::instance.playerDataArray[playerID].aiType - 1 != aicIndex) + continue; + return TRUE; } - - return TRUE; + return FALSE; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 358330f10..532326fb9 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35403,7 +35403,7 @@ SHC_3BB0A8C1_0x004D0280 | 98.2% | Reimplemented SHC_3BB0A8C1_0x004D0520 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D0580 | 0.0% | Pending +SHC_3BB0A8C1_0x004D0580 | 95.7% | Reimplemented SHC_3BB0A8C1_0x004D05D0 | 100.0% | Reimplemented From 99f979072f8b4a1c57366f044105451e19b2ab05 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:51:21 +0200 Subject: [PATCH 186/242] reimplement: SHC_3BB0A8C1_0x004CE4D0 93.83% Reimplemented --- src/OpenSHC/AI/AICState/aiRetreatUnits.cpp | 59 ++++++++-------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 23 insertions(+), 38 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp index 9b494261b..7cdacce2c 100644 --- a/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRetreatUnits.cpp @@ -3,7 +3,6 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" -#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_SkirmishDefinedData.hpp" @@ -11,9 +10,6 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; // FUNCTION: STRONGHOLDCRUSADER 0x004CE4D0 void AICState::aiRetreatUnits(int playerID) @@ -21,39 +17,28 @@ namespace AI { if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) return; - for (int _index1 = 0; _index1 < 11; _index1++) { - int const _tribeTypeStart = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index1].tribeType; - int _tribeIndex = 0; - int const _maxTribeCount = (int)DAT_SkirmishDefinedData::instance.MaxAttackTribes1[_index1].tribeCount; - - for (; _tribeIndex < _maxTribeCount; _tribeIndex++) { - int const _tribeID - = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[_tribeTypeStart + _tribeIndex]; - - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[_tribeTypeStart + _tribeIndex])) { - - DAT_TribesState::instance.tribes[_tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - if (_tribeTypeStart == 0xbe) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); - } else if (_tribeTypeStart == 0xd) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); - } else { - int const _hasHorses - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, - DAT_TribesState::ptr)(_tribeID); - if (_hasHorses != FALSE) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)( - _tribeID, playerID); - } else { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); - } - } - } + for (int i = 0; i < 11; i++) { + int tribeType = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType; + int tribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeCount; + for (int j = 0; j < tribeCount; j++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeType + j]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[j + tribeType]) + continue; + + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + if (tribeType == 190) + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(tribeID, playerID); + else if (tribeType == 13) + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(tribeID, playerID); + else if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::selectionContainsHorses, + DAT_TribesState::ptr)(tribeID) + != FALSE) + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(tribeID, playerID); + else + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 532326fb9..b509422b8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35315,7 +35315,7 @@ SHC_3BB0A8C1_0x004CE3B0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CE430 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CE4D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CE4D0 | 93.8% | Reimplemented SHC_3BB0A8C1_0x004CE530 | 0.0% | Pending From bf7afe8cda76dd3eb1b1d8e1aad1289d982dc41c Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 15:51:21 +0200 Subject: [PATCH 187/242] reimplement: SHC_3BB0A8C1_0x004D1950 98.00% Reimplemented --- .../aiRegisterTribeAndAssignTarget.cpp | 71 +++++-------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 20 insertions(+), 53 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp b/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp index f052d2bd8..1d2272d15 100644 --- a/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp +++ b/src/OpenSHC/AI/AICState/aiRegisterTribeAndAssignTarget.cpp @@ -8,62 +8,29 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004D1950 - void AICState ::aiRegisterTribeAndAssignTarget(int tribeID, int tribeUID) - + void AICState::aiRegisterTribeAndAssignTarget(int tribeID, int tribeUID) { - - int _index; - - short* _tribe; - - int* _uid; - - if (DAT_TribesState::instance.tribes[tribeID].size < 1) { - - DAT_TribesState::instance.tribes[tribeID].tribeState = 3; - + if (DAT_TribesState::instance.tribes[tribeID].size > 0) { + if (DAT_GameState::instance.playerDataArray[DAT_TribesState::instance.tribes[tribeID].owner].aiType + == OpenSHC::AI::AIT_NULL) + return; + + for (int i = 0; i < 1000; i++) { + int existingTribeID = this->tribeIDArray[i]; + if (existingTribeID != 0 + && DAT_TribesState::instance.tribes[existingTribeID].uid == this->tribeUIDArray[i]) + continue; + + this->tribeIDArray[i] = tribeID; + this->tribeUIDArray[i] = tribeUID; + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTargetForTribeBasedOnTargetChoiceLogic, this)( + DAT_TribesState::instance.tribes[tribeID].owner, tribeID); + return; + } return; } - - if (DAT_GameState::instance.playerDataArray[DAT_TribesState::instance.tribes[tribeID].owner].aiType - != OpenSHC::AI::AIT_NULL) { - - _index = 0; - - _uid = this->tribeUIDArray; - - _tribe = this->tribeIDArray; - - do { - - if ((*_tribe == 0) || (DAT_TribesState::instance.tribes[*_tribe].uid != *_uid)) { - - this->tribeIDArray[_index] = (short)tribeID; - - this->tribeUIDArray[_index] = tribeUID; - - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::setTargetForTribeBasedOnTargetChoiceLogic, this)( - DAT_TribesState::instance.tribes[tribeID].owner, tribeID); - - return; - } - - _index = _index + 1; - - _tribe = _tribe + 1; - - _uid = _uid + 1; - - } while (_index < 1000); - } - - return; + DAT_TribesState::instance.tribes[tribeID].tribeState = 3; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b509422b8..811c4d58a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35471,7 +35471,7 @@ SHC_3BB0A8C1_0x004D1710 | 0.0% | Pending SHC_3BB0A8C1_0x004D18B0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D1950 | 0.0% | Pending +SHC_3BB0A8C1_0x004D1950 | 98.0% | Reimplemented SHC_3BB0A8C1_0x004D1A00 | 58.0% | Register allocation differs From 1b124776aeeaf6f2527c7a06a839b3bff4cba438 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:00:06 +0200 Subject: [PATCH 188/242] reimplement: SHC_3BB0A8C1_0x004CCD20 63.91% Loop register allocation diff --- .../addUnitToSmallestBehaviourTypeTribe.cpp | 122 ++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 56 insertions(+), 68 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp index c26db36f6..50144e366 100644 --- a/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToSmallestBehaviourTypeTribe.cpp @@ -11,81 +11,69 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CCD20 int AICState::addUnitToSmallestBehaviourTypeTribe( - undefined4 playerID, undefined4 param_2, undefined4 aiUnitBehaviourType) + undefined4 playerID, undefined4 unitID, undefined4 aiUnitBehaviourType) { - int _playerID = (int)playerID; - int AVar1 = DAT_GameState::instance.playerDataArray[_playerID].aiType; - if (AVar1 == AITA_NULL) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) return 0; - } - int _tribeTypeOffset - = DAT_SkirmishDefinedData::instance.AIUnitBehaviourTypeMapping[(int)aiUnitBehaviourType + -10]; - int _smallestTribe = 0; - int _smallestTribeOffset = 0; - short _smallestTribeSize = 1000; - dword _groupsCount; - if (_tribeTypeOffset == 0xf) { - _groupsCount = this->aics[AVar1 - 1].AttUnitPatrolGroupsCount; - } else if (_tribeTypeOffset == 0xba) { - _groupsCount = this->aics[AVar1 - 1].AttUnitBackupGroupsCount; - } else if (_tribeTypeOffset == 0xbe) { - _groupsCount = this->aics[AVar1 - 1].AttUnitSiegeDefGroupsCount; - } else if (_tribeTypeOffset == 0xc0) { - _groupsCount = this->aics[AVar1 - 1].AttMainGroupsCount; - } else { - _groupsCount = 1; + int aicIndex = aiType - 1; + int tribeType = DAT_SkirmishDefinedData::instance.AIUnitBehaviourTypeMapping[aiUnitBehaviourType - 10]; + int groupsCount; + switch (tribeType) { + case 15: + groupsCount = this->aics[aicIndex].AttUnitPatrolGroupsCount; + break; + case 186: + groupsCount = this->aics[aicIndex].AttUnitBackupGroupsCount; + break; + case 190: + groupsCount = this->aics[aicIndex].AttUnitSiegeDefGroupsCount; + break; + case 192: + groupsCount = this->aics[aicIndex].AttMainGroupsCount; + break; + default: + groupsCount = 1; + break; } - int _selectedTribe; - int _selectedSlot; - if ((int)_groupsCount < 1 || _groupsCount == 1) { - int _tribeID_groupsCount1 - = (int)DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_tribeTypeOffset]; - if ((_tribeID_groupsCount1 != 0) - && (DAT_TribesState::instance.tribes[_tribeID_groupsCount1].uid - == DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { - return _tribeID_groupsCount1; - } - _selectedTribe = MACRO_CALL_MEMBER( - Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); - _selectedSlot = _tribeTypeOffset; + int selectedTribeID = 0; + int selectedSlot = 0; + if (groupsCount <= 1) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeType]; + if (tribeID != 0 + && DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[tribeType]) + return tribeID; + selectedTribeID + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + selectedSlot = tribeType; } else { - int _maxOffset = _groupsCount + _tribeTypeOffset; - _selectedTribe = 0; - _selectedSlot = 0; - short* _pTribeIDs = DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs + _tribeTypeOffset; - if (_tribeTypeOffset < _maxOffset) { - do { - int _tribeID_2 = (int)*_pTribeIDs; - if ((_tribeID_2 == 0) - || (DAT_TribesState::instance.tribes[_tribeID_2].uid - != DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_tribeTypeOffset])) { - _selectedTribe = MACRO_CALL_MEMBER( - Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(_playerID); - _selectedSlot = _tribeTypeOffset; - break; - } - short _tribeSize = DAT_TribesState::instance.tribes[_tribeID_2].size; - if (_tribeSize < _smallestTribeSize) { - _smallestTribeOffset = _tribeTypeOffset; - _smallestTribe = _tribeID_2; - _smallestTribeSize = _tribeSize; - } - _pTribeIDs = _pTribeIDs + 1; - _tribeTypeOffset = _tribeTypeOffset + 1; - _selectedTribe = _smallestTribe; - _selectedSlot = _smallestTribeOffset; - } while (_tribeTypeOffset < _maxOffset); + int smallestSize = 1000; + for (int slot = tribeType; slot < tribeType + groupsCount; slot++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[slot]; + if (tribeID == 0 + || DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[slot]) { + selectedTribeID = MACRO_CALL_MEMBER( + Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + selectedSlot = slot; + break; + } + if (DAT_TribesState::instance.tribes[tribeID].size < smallestSize) { + smallestSize = DAT_TribesState::instance.tribes[tribeID].size; + selectedTribeID = tribeID; + selectedSlot = slot; + } } } - if (0 < _selectedTribe) { - DAT_GameState::instance.playerDataArray[_playerID].aiTribeIDs[_selectedSlot] = (short)_selectedTribe; - DAT_GameState::instance.playerDataArray[_playerID].aiTribeUIDs[_selectedSlot] - = DAT_TribesState::instance.tribes[_selectedTribe].uid; - return _selectedTribe; - } - return 0; + if (selectedTribeID <= 0) + return 0; + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[selectedSlot] = selectedTribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[selectedSlot] + = DAT_TribesState::instance.tribes[selectedTribeID].uid; + return selectedTribeID; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 811c4d58a..30a12f33a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34893,7 +34893,7 @@ SHC_3BB0A8C1_0x004CCAF0 | 68.1% | Register allocation differs SHC_3BB0A8C1_0x004CCBE0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CCD20 | 0.0% | Pending +SHC_3BB0A8C1_0x004CCD20 | 63.9% | Loop register allocation diff SHC_3BB0A8C1_0x004CCEDC | 0.0% | Pending From 09a271042d2415a314863c6f6e5afd1367de1f64 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:00:06 +0200 Subject: [PATCH 189/242] reimplement: SHC_3BB0A8C1_0x004D2660 59.57% Branch layout differs --- .../AI/AICState/assignUnitToATribe.cpp | 49 +++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp index 659a8fb29..9f320a41b 100644 --- a/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp +++ b/src/OpenSHC/AI/AICState/assignUnitToATribe.cpp @@ -1,6 +1,5 @@ #include "../AICState.func.hpp" -#include "OpenSHC/Global.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AITypeA.hpp" @@ -14,38 +13,28 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D2660 void AICState::assignUnitToATribe(int unitID) { - short* _unitTypeIndex; - int _isOfType; - int _tribeID; - int _playerID = (int)DAT_UnitsState::instance.units[unitID].owner; - if (DAT_GameState::instance.playerDataArray[_playerID].aiType != AITA_NULL) { - int iVar1; - if ((DAT_GameState::instance.playerDataArray[_playerID].aivCurrentPauseIndex == 1) - && (0 < DAT_GameState::instance.playerDataArray[_playerID].aivPauses[1])) { - iVar1 = 1; - } else { - iVar1 = 0; - } - _unitTypeIndex = (short*)MACRO_CALL(Global_Func::GetUnitTypeIndexForUnitID)(unitID, iVar1); - int _tribeSize = DAT_GameState::instance.playerDataArray[_playerID] - .aivUnitLocationSlotLocationCount[(int)_unitTypeIndex]; - DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 1; - if (_tribeSize < 1) { - _isOfType = MACRO_CALL_MEMBER(AICState_Func::unitIDIsRangedOrArmored, this)(unitID); - if (_isOfType != 0) { - _tribeID = MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(_playerID, 0); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( - unitID, _tribeID); - return; - } - _tribeID = MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(_playerID, 1); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + int owner = DAT_UnitsState::instance.units[unitID].owner; + if (DAT_GameState::instance.playerDataArray[owner].aiType == AITA_NULL) + return; + + AIVUnitType aivUnitType = MACRO_CALL_MEMBER(AICState_Func::getUnitTypeIndexForUnitID, this)(unitID, + DAT_GameState::instance.playerDataArray[owner].aivCurrentPauseIndex == 1 + && DAT_GameState::instance.playerDataArray[owner].aivPauses[1] > 0 + ? 1 + : 0); + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 1; + if (DAT_GameState::instance.playerDataArray[owner].aivUnitLocationSlotLocationCount[aivUnitType] <= 0) { + if (MACRO_CALL_MEMBER(AICState_Func::unitIDIsRangedOrArmored, this)(unitID) != 0) { + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(owner, 0)); return; } - _tribeID = MACRO_CALL_MEMBER(AICState_Func::smallestTribeOfUnitType, this)( - _playerID, (OpenSHC::Map::Units::UnitType)((int)_unitTypeIndex)); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, _tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, MACRO_CALL_MEMBER(AICState_Func::createTribeForUnitType, this)(owner, 1)); + return; } + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, MACRO_CALL_MEMBER(AICState_Func::smallestTribeOfUnitType, this)(owner, aivUnitType)); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 30a12f33a..65907dddd 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35487,7 +35487,7 @@ SHC_3BB0A8C1_0x004D20C0 | 0.0% | Pending SHC_3BB0A8C1_0x004D2500 | 0.0% | Pending -SHC_3BB0A8C1_0x004D2660 | 0.0% | Pending +SHC_3BB0A8C1_0x004D2660 | 59.6% | Branch layout differs SHC_3BB0A8C1_0x004D2730 | 79.2% | AIC index folding differs From c468eb274280367310e26b72038e0fc3bd6c303e Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:00:07 +0200 Subject: [PATCH 190/242] reimplement: SHC_3BB0A8C1_0x004D28B0 73.04% Register allocation differs --- .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 129 ++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 57 insertions(+), 74 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp index ac950d54f..26d070116 100644 --- a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -14,80 +14,63 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D28B0 void AICState::aiGiveOuterPatrolCommand(int playerID) { - int* piVar1; - short sVar2; - int iVar3; - short* psVar4; - int _buildingID; - int _buildingID2; - int _tile; - BOOLEnum _canNavigate; - int _aicOffset; - int _tribeID; - int _index; - int _count; - int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType != 0) { - _aicOffset = (_aiType + -1) * 0x2a4; - _count = (int)this->aics[_aiType - 1].OuterPatrolGroupsCount; - _index = 0; - if (((0 < _count) - && (piVar1 = &DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker, - *piVar1 = *piVar1 + 1, - (int)this->aics[_aiType - 1].OuterPatrolRallyDelay - <= DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker)) - && (DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker = 0, 0 < _count)) { - psVar4 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xaa; - do { - _tribeID = (int)*psVar4; - DAT_TribesState::instance.tribes[_tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; - if (((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_index + 0xaa])) - && ((DAT_TribesState::instance.tribes[_tribeID].percentageMovingUnk <= 0xa - && ((DAT_TribesState::instance.tribes[_tribeID].percentageShootingUnk <= 0xa - && (DAT_TribesState::instance.tribes[_tribeID].percentageAttackingUnk <= 0xa)))))) { - bool _hasTarget = true; - if (((int)this->aics[_aiType - 1].OuterPatrolGroupsMove == 0) - || (_buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)( - playerID, _index), - _buildingID == 0)) { - _buildingID2 = MACRO_CALL_MEMBER( - AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); - if (_buildingID2 == 0) { - _hasTarget = false; - } else { - _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID2].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID2] - .buildingEntryY] - .addXgetTile; - } - } else { - _tile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] - .buildingEntryY] - .addXgetTile; - } - if (_hasTarget && _tile != 0) { - sVar2 = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_tile]; - iVar3 = DAT_ViewportRenderState::instance.translationMatrix[sVar2].addXgetTile; - _canNavigate = MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( - _tribeID, _tile); - if (_canNavigate == FALSE) { - MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(_tribeID, playerID); - } else { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, - DAT_TribesState::ptr)(_tribeID, _tile - iVar3, (int)sVar2, 0); - } - } - } - _index = _index + 1; - psVar4 = psVar4 + 1; - } while (_index < _count); + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == 0) + return; + int aicIndex = aiType - 1; + int groupsCount = this->aics[aicIndex].OuterPatrolGroupsCount; + if (groupsCount <= 0) + return; + + DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker++; + if (DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker + < this->aics[aicIndex].OuterPatrolRallyDelay) + return; + DAT_GameState::instance.playerDataArray[playerID].outerPatrolRallyDelayTracker = 0; + + for (int i = 0; i < groupsCount; i++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[170 + i]; + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_AGGRESSIVE; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[i + 170]) + continue; + if (DAT_TribesState::instance.tribes[tribeID].percentageMovingUnk > 10) + continue; + if (DAT_TribesState::instance.tribes[tribeID].percentageShootingUnk > 10) + continue; + if (DAT_TribesState::instance.tribes[tribeID].percentageAttackingUnk > 10) + continue; + + int buildingID = 0; + if (this->aics[aicIndex].OuterPatrolGroupsMove != 0) + buildingID = MACRO_CALL_MEMBER(AICState_Func::getTargetableBuildingForPlayerID, this)(playerID, i); + int tile; + if (buildingID != 0) { + tile = DAT_BuildingsState::instance.buildings[buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[buildingID].buildingEntryY] + .addXgetTile; + } else { + buildingID = MACRO_CALL_MEMBER(AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + if (buildingID == 0) + continue; + tile = DAT_BuildingsState::instance.buildings[buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[buildingID].buildingEntryY] + .addXgetTile; } - } + if (tile == 0) + continue; + + int y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]; + int x = tile - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; + if (MACRO_CALL_MEMBER(AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, tile) != FALSE) + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + tribeID, x, y, 0); + else + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(tribeID, playerID); } } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 65907dddd..eecf7d842 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35499,7 +35499,7 @@ SHC_3BB0A8C1_0x004D2830 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D2870 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D28B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D28B0 | 73.0% | Register allocation differs SHC_3BB0A8C1_0x004D2A70 | 0.0% | Pending From 89f7c6e956122afb9e1da93b69d137a7407814d7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:00:07 +0200 Subject: [PATCH 191/242] reimplement: SHC_3BB0A8C1_0x004CB3A0 85.29% Register allocation differs --- .../AI/AICState/aiRequiresExtraOxtethers.cpp | 119 +++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 43 insertions(+), 78 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp index abcbb1837..75f3d197d 100644 --- a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp +++ b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp @@ -9,89 +9,54 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Map::Buildings::BuildingType; - // FUNCTION: STRONGHOLDCRUSADER 0x004CB3A0 - undefined4 AICState ::aiRequiresExtraOxtethers(int playerID) - + undefined4 AICState::aiRequiresExtraOxtethers(int playerID) { - int _playerID = playerID; - - int _buildingID - = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, - DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_QUARRY); - - // _stoneWaiting declared first so it gets lower stack slot - int _stoneWaiting = 0; - int _quarryID = 0; - - int _oxTetherCount = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, - DAT_BuildingsState::ptr)(_playerID, OpenSHC::Map::Buildings::BT_OXTETHER, 1); - - if (_oxTetherCount >= 0xa) { - return (undefined4)(0); - } - - int* piVar1 = &DAT_GameState::instance.playerDataArray[_playerID].highestLoadedQuarryUnk; - - *piVar1 = 0; - - if (_buildingID != 0) { - - do { - int _localStone - = DAT_BuildingsState::instance - .buildings[(short)DAT_BuildingsState::instance.buildings[_buildingID].quarryStockpileID] - .resourceStone; - - int _linkedTetherCount = 0; - - short* _linkedTetherIDs = DAT_BuildingsState::instance.buildings[_buildingID].quarryLinkedOxTethers; - - int _oxTetherLoopIndex = 3; - - do { - int _linkedTetherID = (int)*_linkedTetherIDs; - - if (_linkedTetherID != 0) { - if ((DAT_BuildingsState::instance.buildings[_linkedTetherID].buildingType - == OpenSHC::Map::Buildings::BT_OXTETHER) - && (DAT_BuildingsState::instance.buildings[_linkedTetherID].oxtetherLinkedQuarryID - == _buildingID)) { - _linkedTetherCount = _linkedTetherCount + 1; - } else { - *_linkedTetherIDs = 0; - } - } - - _linkedTetherIDs = _linkedTetherIDs + 1; - _oxTetherLoopIndex = _oxTetherLoopIndex + -1; - - } while (_oxTetherLoopIndex != 0); - - if (_linkedTetherCount <= 0) { - *piVar1 = _buildingID; - return (undefined4)(1); - } - - if (_stoneWaiting < _localStone / _linkedTetherCount) { - _quarryID = _buildingID; - _stoneWaiting = _localStone / _linkedTetherCount; - } - - _buildingID - = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findNextBuildingForPlayerAndType, - DAT_BuildingsState::ptr)(_playerID, OpenSHC::Map::Buildings::BT_QUARRY, _buildingID); - - } while (_buildingID != 0); + int quarryID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_QUARRY); + int highestStonePerTether = 0; + int highestQuarryID = 0; + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)( + playerID, OpenSHC::Map::Buildings::BT_OXTETHER, 1) + >= 10) + return 0; + + DAT_GameState::instance.playerDataArray[playerID].highestLoadedQuarryUnk = 0; + if (quarryID == 0) + return 0; + + for (; quarryID != 0; + quarryID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findNextBuildingForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_QUARRY, quarryID)) { + int stone = DAT_BuildingsState::instance + .buildings[(short)DAT_BuildingsState::instance.buildings[quarryID].quarryStockpileID] + .resources[Game::Resources::RT_STONE]; + int tetherCount = 0; + for (int i = 0; i < 3; i++) { + int tetherID = DAT_BuildingsState::instance.buildings[quarryID].quarryLinkedOxTethers[i]; + if (tetherID == 0) + continue; + if (DAT_BuildingsState::instance.buildings[tetherID].buildingType == OpenSHC::Map::Buildings::BT_OXTETHER + && DAT_BuildingsState::instance.buildings[tetherID].oxtetherLinkedQuarryID == quarryID) + tetherCount++; + else + DAT_BuildingsState::instance.buildings[quarryID].quarryLinkedOxTethers[i] = 0; + } - if (0x14 < _stoneWaiting) { - *piVar1 = _quarryID; - return (undefined4)(1); + if (tetherCount <= 0) { + DAT_GameState::instance.playerDataArray[playerID].highestLoadedQuarryUnk = quarryID; + return 1; + } + if (stone / tetherCount > highestStonePerTether) { + highestQuarryID = quarryID; + highestStonePerTether = stone / tetherCount; } } - return (undefined4)(0); + if (highestStonePerTether <= 20) + return 0; + DAT_GameState::instance.playerDataArray[playerID].highestLoadedQuarryUnk = highestQuarryID; + return 1; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index eecf7d842..f8f235e86 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34215,7 +34215,7 @@ SHC_3BB0A8C1_0x004CB290 | 0.0% | Pending SHC_3BB0A8C1_0x004CB330 | 97.5% | Reimplemented -SHC_3BB0A8C1_0x004CB3A0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB3A0 | 85.3% | Register allocation differs SHC_3BB0A8C1_0x004CB4D0 | 97.5% | Reimplemented From 8c4f2d2c5b06a4acb1d4c2baf4c9b6f9c8afb3a6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:13:01 +0200 Subject: [PATCH 192/242] reimplement: SHC_3BB0A8C1_0x004CAEA0 100.00% Reimplemented --- .../AI/AICState/aiUpdateTaxesAndRations.cpp | 106 ++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 46 insertions(+), 62 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp index 122c929c7..b3e668cc0 100644 --- a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp +++ b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp @@ -1,105 +1,89 @@ #include "../AICState.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - // FUNCTION: STRONGHOLDCRUSADER 0x004CAEA0 void AICState::aiUpdateTaxesAndRations(int playerID) { - AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType == OpenSHC::AI::AIT_NULL) + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) return; + int aicIndex = aiType - 1; - _aiType = _aiType - 1; - int const _popularity = DAT_GameState::instance.playerDataArray[playerID].popularity; - - if (_popularity <= (int)this->aics[_aiType].criticalPopularity) { + int popularity = DAT_GameState::instance.playerDataArray[playerID].popularity; + if (popularity <= this->aics[aicIndex].criticalPopularity) DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 2; - } else if (_popularity <= (int)this->aics[_aiType].lowestPopularity) { + else if (popularity <= this->aics[aicIndex].lowestPopularity) DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 1; - } else if (_popularity >= (int)this->aics[_aiType].highestPopularity) { + else if (popularity >= this->aics[aicIndex].highestPopularity) DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue = 0; - } - - int const _decision = DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue; - if (_decision == 2) { - int const _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; + if (DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue == 2) { DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 2; - if (_totalFood <= 0) { + if (DAT_GameState::instance.playerDataArray[playerID].totalFood <= 0) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; - } else if (_totalFood <= 4) { + else if (DAT_GameState::instance.playerDataArray[playerID].totalFood <= 4) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; - } else { - DAT_GameState::instance.playerDataArray[playerID].rationsSetting = (_totalFood > 8) + 3; - } - } else if (_decision == 1) { - int const _currentTaxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; - int const _taxesMin = (int)this->aics[_aiType].taxesMin; - if (_currentTaxes > _taxesMin) { - DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _currentTaxes - 1; - } else { - DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxesMin; - } - int const _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; - if (_totalFood <= 0) { + else if (DAT_GameState::instance.playerDataArray[playerID].totalFood <= 8) + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 3; + else + DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; + } else if (DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue == 1) { + if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting > this->aics[aicIndex].taxesMin) + DAT_GameState::instance.playerDataArray[playerID].taxesSetting--; + else + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = this->aics[aicIndex].taxesMin; + + if (DAT_GameState::instance.playerDataArray[playerID].totalFood <= 0) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; - } else if (_totalFood <= 10) { + else if (DAT_GameState::instance.playerDataArray[playerID].totalFood <= 10) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; - } else { + else DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 3; - } - int const _rationsMod = (int)this->aics[_aiType].doubleRationsFoodThreshold; - if (_rationsMod != 0 && _totalFood >= _rationsMod) + if (this->aics[aicIndex].doubleRationsFoodThreshold != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalFood >= this->aics[aicIndex].doubleRationsFoodThreshold) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; - } else if (_decision == 0) { - int const _taxes = DAT_GameState::instance.playerDataArray[playerID].taxesSetting; - int const _taxesMax = (int)this->aics[_aiType].taxesMax; - - if (_taxes < _taxesMax) { - int const _peasants = DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants; - int _newTaxesVal; - if (_peasants >= 0xf) { - _newTaxesVal = 6; - } else { - _newTaxesVal = (_peasants >= 0xa) + 4; - } + } else if (DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue == 0) { + if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting < this->aics[aicIndex].taxesMax) { + int lowerTaxesLimit; + if (DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants >= 15) + lowerTaxesLimit = 6; + else if (DAT_GameState::instance.playerDataArray[playerID].previousAvailablePeasants >= 10) + lowerTaxesLimit = 5; + else + lowerTaxesLimit = 4; - if (!(DAT_GameState::instance.playerDataArray[playerID].storedPopularityPercent > _popularity)) { - DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxes + 1; - } else if (_taxes > _newTaxesVal) { - DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxes - 1; - } + if (DAT_GameState::instance.playerDataArray[playerID].storedPopularityPercent <= popularity) + DAT_GameState::instance.playerDataArray[playerID].taxesSetting++; + else if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting > lowerTaxesLimit) + DAT_GameState::instance.playerDataArray[playerID].taxesSetting--; } else { - DAT_GameState::instance.playerDataArray[playerID].taxesSetting = _taxesMax; + DAT_GameState::instance.playerDataArray[playerID].taxesSetting = this->aics[aicIndex].taxesMax; } - int const _totalFood = DAT_GameState::instance.playerDataArray[playerID].totalFood; - if (_totalFood <= 10) { + if (DAT_GameState::instance.playerDataArray[playerID].totalFood <= 10) { DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; } else { DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 2; - int const _rationsMod = (int)this->aics[_aiType].doubleRationsFoodThreshold; - if (_rationsMod != 0 && _totalFood >= _rationsMod) + if (this->aics[aicIndex].doubleRationsFoodThreshold != 0 + && DAT_GameState::instance.playerDataArray[playerID].totalFood + >= this->aics[aicIndex].doubleRationsFoodThreshold) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; } } if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting < 0) DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 0; - if (11 < DAT_GameState::instance.playerDataArray[playerID].taxesSetting) + if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting > 11) DAT_GameState::instance.playerDataArray[playerID].taxesSetting = 11; if (DAT_GameState::instance.playerDataArray[playerID].rationsSetting < 0) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 0; - if (4 < DAT_GameState::instance.playerDataArray[playerID].rationsSetting) + if (DAT_GameState::instance.playerDataArray[playerID].rationsSetting > 4) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f8f235e86..1bf606938 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34197,7 +34197,7 @@ SHC_3BB0A8C1_0x004CAD10 | 0.0% | Pending SHC_3BB0A8C1_0x004CAE20 | 0.0% | Pending -SHC_3BB0A8C1_0x004CAEA0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CAEA0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB060 | 100.0% | Reimplemented From 050d4c29049baca6b6730e92e119de426ace747c Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:13:01 +0200 Subject: [PATCH 193/242] reimplement: SHC_3BB0A8C1_0x004CDCF0 41.75% Register allocation differs --- ...iShouldAttackOrWaitForTeamCoordination.cpp | 140 +++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 56 insertions(+), 86 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp index 87fdcd61e..1004fb6c6 100644 --- a/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldAttackOrWaitForTeamCoordination.cpp @@ -3,12 +3,8 @@ #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Synchrony/GameSynchronyState.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/Game/GameMode2.hpp" -#include "OpenSHC/Game/Player/PlayerData.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.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" @@ -17,93 +13,67 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - using OpenSHC::Game::GameMode2; - using OpenSHC::Game::Player::PlayerData; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - // FUNCTION: STRONGHOLDCRUSADER 0x004CDCF0 - BOOLEnum AICState ::aiShouldAttackOrWaitForTeamCoordination(int playerID) - + BOOLEnum AICState::aiShouldAttackOrWaitForTeamCoordination(int playerID) { - - AITypeInt _aiType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType == OpenSHC::AI::AIT_NULL) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) return FALSE; - } - - if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk != 1) { - int _attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; - if (DAT_GameState::instance.playerDataArray[_attackedPlayerID].totalTroopValue < 100) { - DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 0; - } - - int _attForceBase = *(int*)((int)this + (_aiType - 1) * 0x2a4 + 0x1f4); - int _currentWaveStrength - = DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength; - int _totalAttack = DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops - - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops; - - if (_totalAttack < _attForceBase + _currentWaveStrength) { - return FALSE; - } - - if (DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel == 0) { - return TRUE; - } - - int _readyTeamMembers = 0; - int _unreadyTeamMembers = 0; - int _iPlayer = 1; - PlayerData* _pPlayerData = &DAT_GameState::instance.playerDataArray[1]; - - do { - if (_iPlayer != playerID) { - int _isAlive = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(_iPlayer); - if (_isAlive != 0) { - BOOLEnum _isAI = MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, - DAT_GameSynchronyState::ptr)(_iPlayer); - if (_isAI != FALSE) { - if (DAT_GameState::instance.mapAndTime.playerTeams[_iPlayer] - == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { - if (_pPlayerData->aiPlayerState != 0) { - return TRUE; - } - if (_pPlayerData->totalAttackTroops - _pPlayerData->totalAttackingEngineerTroops - >= *(int*)((int)this + (_pPlayerData->aiType - 1) * 0x2a4 + 0x1f4) - + _pPlayerData->currentWaveRandomAttackingStrength) { - _readyTeamMembers = _readyTeamMembers + 1; - } else { - _unreadyTeamMembers = _unreadyTeamMembers + 1; - } - } - } - } - } - _iPlayer = _iPlayer + 1; - _pPlayerData = _pPlayerData + 1; - } while (_iPlayer < 9); - - if (_readyTeamMembers >= DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel) { - return TRUE; - } - if (_unreadyTeamMembers == 0) { + int aicIndex = aiType - 1; + if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 1) + return TRUE; + + if (DAT_GameState::instance.playerDataArray[DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID] + .totalTroopValue + <= 100) + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength = 0; + + if (DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops + - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops + < this->aics[aicIndex].AttForceBase + + DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength) + return FALSE; + if (DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel == 0) + return TRUE; + + int readyTeamMembers = 0; + int unreadyTeamMembers = 0; + for (int otherPlayerID = 1; otherPlayerID < 9; otherPlayerID++) { + if (otherPlayerID == playerID) + continue; + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + otherPlayerID) + == 0) + continue; + if (MACRO_CALL_MEMBER(OpenSHC::Synchrony::GameSynchronyState_Func::isAIPlayer, DAT_GameSynchronyState::ptr)( + otherPlayerID) + == FALSE) + continue; + if (DAT_GameState::instance.mapAndTime.playerTeams[otherPlayerID] + != DAT_GameState::instance.mapAndTime.playerTeams[playerID]) + continue; + + if (DAT_GameState::instance.playerDataArray[otherPlayerID].aiPlayerState != 0) return TRUE; - } - DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience - = DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience + 1; - if (DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience <= 0x30 - || (DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_CAMPAIGN_MISSION)) { - return FALSE; - } + if (DAT_GameState::instance.playerDataArray[otherPlayerID].totalAttackTroops + - DAT_GameState::instance.playerDataArray[otherPlayerID].totalAttackingEngineerTroops + >= this->aics[DAT_GameState::instance.playerDataArray[otherPlayerID].aiType - 1].AttForceBase + + DAT_GameState::instance.playerDataArray[otherPlayerID].currentWaveRandomAttackingStrength) + readyTeamMembers++; + else + unreadyTeamMembers++; } - return TRUE; + if (readyTeamMembers >= DAT_GameState::instance.playerDataArray[playerID].aiAttackCoordinationLevel) + return TRUE; + if (unreadyTeamMembers == 0) + return TRUE; + + DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience++; + if (DAT_GameState::instance.playerDataArray[playerID].aiCoordinatedAttackPatience > 48 + && DAT_GameCore::instance.gameMode_2 != OpenSHC::Game::GM_CAMPAIGN_MISSION) + return TRUE; + return FALSE; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1bf606938..596db0411 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35293,7 +35293,7 @@ SHC_3BB0A8C1_0x004CDBC0 | 65.0% | Loop counter spilled in orig SHC_3BB0A8C1_0x004CDCA0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CDCF0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CDCF0 | 41.8% | Register allocation differs SHC_3BB0A8C1_0x004CDE60 | 76.09% | Reimplemented functionally different register usage From ad40592fbbe1c1495b43fcad421a96ed543e2cc3 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:13:01 +0200 Subject: [PATCH 194/242] reimplement: SHC_3BB0A8C1_0x004CD690 94.94% Reimplemented --- .../AI/AICState/aiRecruitSortieMeleeUnits.cpp | 134 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 45 insertions(+), 91 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp index 29d463777..4326ee098 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp @@ -3,7 +3,6 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -13,101 +12,56 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; using OpenSHC::Map::Units::UnitType; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CD690 - void AICState ::aiRecruitSortieMeleeUnits(int playerID) - + void AICState::aiRecruitSortieMeleeUnits(int playerID) { - - AITypeInt AVar1; - - int iVar2; - - int _unitID; - - int _section1016id; - - UnitType _unitType; - - AVar1 = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (AVar1 != OpenSHC::AI::AIT_NULL) { - - iVar2 = (AVar1 + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - - _section1016id = *(int*)((int)this + iVar2 + 0x154); - - if (((((-1 < _section1016id) - && (DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 < _section1016id)) - && (0 < DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount)) - && ((DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0 - && (_unitType = *(UnitType*)((int)this + iVar2 + 0x158), - _unitType != OpenSHC::Map::Units::UT_E_ENGINEER)))) - && ((_unitType != OpenSHC::Map::Units::UT_E_LADDER - && (_unitType != OpenSHC::Map::Units::UT_TUNNELER)))) { - - if ((int)_unitType < 0x46) { - - _section1016id = DAT_GameState::instance.playerDataArray[playerID].barracks.id; - - } - - else { - - _section1016id = DAT_GameState::instance.playerDataArray[playerID].mercenaryPost.id; - } - - if (_section1016id != 0) { - - if ((int)_unitType < 0x46) { - - _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, - DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_section1016id)), playerID, 0); - - } - - else { - - _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, - DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_section1016id)), playerID, 0); - } - - if (_unitID == 0) { - - _section1016id = *(int*)((int)this + iVar2 + 0x9c); - - if ((0 < _section1016id) && (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason == 2)) { - - DAT_GameState::instance.playerDataArray[playerID] - .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] - = _section1016id; - - return; - } - - } - - else { - - DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType = 7; - - _section1016id = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::createTribeForUnitType, this)( - playerID, (int)((int)(167))); - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( - _unitID, _section1016id); - } - } - } + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) + return; + int aicIndex = aiType - 1; + if (this->aics[aicIndex].SortieUnitMeleeMin < 0) + return; + if (DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 >= this->aics[aicIndex].SortieUnitMeleeMin) + return; + if (DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount <= 0) + return; + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) + return; + UnitType unitType = (UnitType)this->aics[aicIndex].SortieUnitMelee; + if (unitType == OpenSHC::Map::Units::UT_E_ENGINEER || unitType == OpenSHC::Map::Units::UT_E_LADDER + || unitType == OpenSHC::Map::Units::UT_TUNNELER) + return; + + int buildingID; + if (unitType < 70) + buildingID = DAT_GameState::instance.playerDataArray[playerID].barracks.id; + else + buildingID = DAT_GameState::instance.playerDataArray[playerID].mercenaryPost.id; + if (buildingID == 0) + return; + + int unitID; + if (unitType < 70) + unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, DAT_UnitsState::ptr)( + unitType, buildingID, playerID, 0); + else + unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + unitType, buildingID, playerID, 0); + + if (unitID == 0) { + if (this->aics[aicIndex].tradeAmountEquipment > 0 + && DAT_UnitsState::instance.euroUnitAcquisitionFailReason == 2) + DAT_GameState::instance.playerDataArray[playerID] + .resourcesToAcquireArray[DAT_UnitsState::instance.euroUnitRequiredResource] + = this->aics[aicIndex].tradeAmountEquipment; + return; } - return; + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 7; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::createTribeForUnitType, this)(playerID, 167)); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 596db0411..f8ae6e9f8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35277,7 +35277,7 @@ SHC_3BB0A8C1_0x004CD2A0 | 59.60% | Reimplemented functionally, code block orderi SHC_3BB0A8C1_0x004CD560 | 0.0% | Pending -SHC_3BB0A8C1_0x004CD690 | 0.0% | Pending +SHC_3BB0A8C1_0x004CD690 | 94.9% | Reimplemented SHC_3BB0A8C1_0x004CD7B0 | 0.0% | Pending From 33be0450691656ee831a4e21f9adcdc0b3497988 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:13:02 +0200 Subject: [PATCH 195/242] reimplement: SHC_3BB0A8C1_0x004CD560 95.24% Reimplemented --- .../AICState/aiRecruitSortieRangedUnits.cpp | 140 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 47 insertions(+), 95 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp index 55f5036c4..951822739 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitSortieRangedUnits.cpp @@ -3,7 +3,6 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -13,105 +12,58 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; using OpenSHC::Map::Units::UnitType; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CD560 - void AICState ::aiRecruitSortieRangedUnits(int playerID) - + void AICState::aiRecruitSortieRangedUnits(int playerID) { - - UnitType unitType; - - int iVar1; - - uint _unitID; - - int iVar2; - - int _buildingID; - - AITypeInt _aiType; - - _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - - if (_aiType != OpenSHC::AI::AIT_NULL) { - - iVar1 = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - - iVar2 = *(int*)((int)this + iVar1 + 0x14c); - - /* - bug: missing != 0? */ - - if (((((-1 < iVar2) - && (DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 - < DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 / 2 + iVar2)) - && (0 < DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount)) - && ((DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0 - && (unitType = *(UnitType*)((int)this + iVar1 + 0x150), - unitType != OpenSHC::Map::Units::UT_E_ENGINEER)))) - && ((unitType != OpenSHC::Map::Units::UT_E_LADDER && (unitType != OpenSHC::Map::Units::UT_TUNNELER)))) { - - if ((int)unitType < 0x46) { - - _buildingID = DAT_GameState::instance.playerDataArray[playerID].barracks.id; - - } - - else { - - _buildingID = DAT_GameState::instance.playerDataArray[playerID].mercenaryPost.id; - } - - if (_buildingID != 0) { - - if ((int)unitType < 0x46) { - - _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, - DAT_UnitsState::ptr)(unitType, (undefined4)((int)(_buildingID)), playerID, 0); - - } - - else { - - _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, - DAT_UnitsState::ptr)(unitType, (undefined4)((int)(_buildingID)), playerID, 0); - } - - if (_unitID == 0) { - - iVar2 = *(int*)((int)this + iVar1 + 0x9c); - - if ((0 < iVar2) && (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason == 2)) { - - DAT_GameState::instance.playerDataArray[playerID] - .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = iVar2; - - return; - } - - } - - else { - - DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType = 6; - - iVar2 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::createTribeForUnitType, this)( - playerID, (int)((int)(166))); - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( - _unitID, iVar2); - } - } - } + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) + return; + int aicIndex = aiType - 1; + if (this->aics[aicIndex].SortieUnitRangedMin < 0) + return; + if (DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 + >= DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 / 2 + + this->aics[aicIndex].SortieUnitRangedMin) + return; + if (DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount <= 0) + return; + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) + return; + UnitType unitType = (UnitType)this->aics[aicIndex].SortieUnitRanged; + if (unitType == OpenSHC::Map::Units::UT_E_ENGINEER || unitType == OpenSHC::Map::Units::UT_E_LADDER + || unitType == OpenSHC::Map::Units::UT_TUNNELER) + return; + + int buildingID; + if (unitType < 70) + buildingID = DAT_GameState::instance.playerDataArray[playerID].barracks.id; + else + buildingID = DAT_GameState::instance.playerDataArray[playerID].mercenaryPost.id; + if (buildingID == 0) + return; + + int unitID; + if (unitType < 70) + unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, DAT_UnitsState::ptr)( + unitType, buildingID, playerID, 0); + else + unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + unitType, buildingID, playerID, 0); + + if (unitID == 0) { + if (this->aics[aicIndex].tradeAmountEquipment > 0 + && DAT_UnitsState::instance.euroUnitAcquisitionFailReason == 2) + DAT_GameState::instance.playerDataArray[playerID] + .resourcesToAcquireArray[DAT_UnitsState::instance.euroUnitRequiredResource] + = this->aics[aicIndex].tradeAmountEquipment; + return; } - return; + DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 6; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( + unitID, MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::createTribeForUnitType, this)(playerID, 166)); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f8ae6e9f8..0b12ef91d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35275,7 +35275,7 @@ SHC_3BB0A8C1_0x004CD250 | 94.7% | Reimplemented SHC_3BB0A8C1_0x004CD2A0 | 59.60% | Reimplemented functionally, code block ordering problem -SHC_3BB0A8C1_0x004CD560 | 0.0% | Pending +SHC_3BB0A8C1_0x004CD560 | 95.2% | Reimplemented SHC_3BB0A8C1_0x004CD690 | 94.9% | Reimplemented From 57da4dcb26c2cf06c4b96ea3f233f4fec9d002be Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:23:56 +0200 Subject: [PATCH 196/242] reimplement: SHC_3BB0A8C1_0x004CFCD0 55.97% Unresolved attackInfo offsets --- .../AICState/aiCommandSiegeEngineTribes.cpp | 171 ++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 73 insertions(+), 100 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp index ff2b625bf..42e6b8588 100644 --- a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp @@ -4,10 +4,8 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" -#include "OpenSHC/Map/Units/Unit.hpp" #include "OpenSHC/Map/Units/UnitLogicState.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/Map/Units/UnitTypeShort.hpp" #include "OpenSHC/Globals/DAT_DirectionAlgorithmState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -15,108 +13,83 @@ #include "OpenSHC/Globals/DAT_TroopValueState.hpp" #include "OpenSHC/Globals/DAT_UnitsState.hpp" #include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" + namespace OpenSHC { namespace AI { - using OpenSHC::Map::Units::SomeTribeBehaviorType; - using OpenSHC::Map::Units::Unit; - using OpenSHC::Map::Units::UnitLogicState; - using OpenSHC::Map::Units::UnitType; - using OpenSHC::Map::Units::UnitTypeShort; - using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ + + using namespace OpenSHC::Map::Units; + // FUNCTION: STRONGHOLDCRUSADER 0x004CFCD0 - void AICState ::aiCommandSiegeEngineTribes(int playerID) + void AICState::aiCommandSiegeEngineTribes(int playerID) { - int _targetTribeIDs[3]; - _targetTribeIDs[0] = 0; - _targetTribeIDs[1] = 0; - _targetTribeIDs[2] = 0; - int _validCount = 0; - int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xba]; - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xba])) { - _targetTribeIDs[0] = _tribeID; - _validCount = 1; - } - _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbb]; - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbb])) { - _targetTribeIDs[_validCount] = _tribeID; - _validCount += 1; - } - _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xbc]; - if ((_tribeID != 0) - && (DAT_TribesState::instance.tribes[_tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xbc])) { - _targetTribeIDs[_validCount] = _tribeID; + int shieldTargetTribeIDs[3]; + shieldTargetTribeIDs[0] = 0; + shieldTargetTribeIDs[1] = 0; + shieldTargetTribeIDs[2] = 0; + int targetCount = 0; + for (int i = 0; i < 3; i++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[186 + i]; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[186 + i]) + continue; + shieldTargetTribeIDs[targetCount] = tribeID; + targetCount++; } - int _shieldCount = 0; - for (int _unitID = 1; _unitID < 2500; _unitID++) { - UnitTypeShort _unitType; - if ((DAT_UnitsState::instance.units[_unitID].logicalState != OpenSHC::Map::Units::ULS_INVISIBLE) - && ((((_unitType = DAT_UnitsState::instance.units[_unitID].unitType, - _unitType == OpenSHC::Map::Units::UT_S_TOWER - || (_unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM)) - || (_unitType == OpenSHC::Map::Units::UT_S_SHIELD)) - && ((DAT_UnitsState::instance.units[_unitID].unknownSiegeTentRelated02 == 3 - && (DAT_UnitsState::instance.units[_unitID].aiUnitBehaviourType != 0x15)))))) { - if (_unitType == OpenSHC::Map::Units::UT_S_TOWER) { - int _engineTribeID = (int)DAT_UnitsState::instance.units[_unitID].tribeID; - if ((_engineTribeID != 0) - && (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc - + -4) - != 0)) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, - DAT_TribesState::ptr)(_engineTribeID, OpenSHC::Map::Units::STBT_0x414); - } - } else if (_unitType == OpenSHC::Map::Units::UT_S_BATTERINGRAM) { - int _engineTribeID = (int)DAT_UnitsState::instance.units[_unitID].tribeID; - if (_engineTribeID != 0) { - if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.gateValuesArray + playerID * 0x177bc - + -4) - != 0) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, - DAT_TribesState::ptr)(_engineTribeID, OpenSHC::Map::Units::STBT_0x3f6); - } else { - if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray - + playerID * 0x177bc + -4) - != 0) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::assignAttackTargetsForTribe, - DAT_TribesState::ptr)(_engineTribeID, OpenSHC::Map::Units::STBT_0x413); - } - } - } - } else if (_unitType == OpenSHC::Map::Units::UT_S_SHIELD) { - int _shieldTribeID = (int)DAT_UnitsState::instance.units[_unitID].tribeID; - if ((_shieldTribeID != 0) && (_shieldCount < 3)) { - int _targetTribeID = _targetTribeIDs[_shieldCount]; - DAT_TribesState::instance.tribes[_shieldTribeID].field56_0x1f2 = (short)_targetTribeID; - DAT_TribesState::instance.tribes[_shieldTribeID].uid2 - = DAT_TribesState::instance.tribes[_targetTribeID].uid; - int _targetUnitID = (int)DAT_TribesState::instance.tribes[_targetTribeID].selectionTargetUnitID; - DAT_TribesState::instance.tribes[_targetTribeID].tribeID = (short)_shieldTribeID; - int _targetTile = DAT_UnitsState::instance.units[_targetUnitID].tile; - _shieldCount = _shieldCount + 1; - if (0 < _targetTile) { - uint y1 - = (uint)DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[_targetTile]; - uint x1 = _targetTile - DAT_ViewportRenderState::instance.translationMatrix[y1].addXgetTile; - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - _shieldTribeID, x1, y1, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func:: - calculatePreferredRelativeOrientation, - DAT_DirectionAlgorithmState::ptr)((int)DAT_UnitsState::instance.units[_targetUnitID].x, - (int)((int)(DAT_UnitsState::instance.units[_targetUnitID].y)), (int)((int)(x1)), - (int)((int)(y1))); - DAT_TribesState::instance.tribes[_shieldTribeID].orientation - = (short)DAT_DirectionAlgorithmState::instance.orientation; - } - } - } + + int shieldCount = 0; + for (int unitID = 1; unitID < 2500; unitID++) { + if (DAT_UnitsState::instance.units[unitID].logicalState == ULS_INVISIBLE) + continue; + if (DAT_UnitsState::instance.units[unitID].unitType != UT_S_TOWER + && DAT_UnitsState::instance.units[unitID].unitType != UT_S_BATTERINGRAM + && DAT_UnitsState::instance.units[unitID].unitType != UT_S_SHIELD) + continue; + if (DAT_UnitsState::instance.units[unitID].unknownSiegeTentRelated02 != 3) + continue; + if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType == 21) + continue; + + int tribeID = DAT_UnitsState::instance.units[unitID].tribeID; + if (tribeID == 0) + continue; + + if (DAT_UnitsState::instance.units[unitID].unitType == UT_S_TOWER) { + if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc - 4) != 0) + MACRO_CALL_MEMBER(TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, STBT_0x414); + } else if (DAT_UnitsState::instance.units[unitID].unitType == UT_S_BATTERINGRAM) { + if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.gateValuesArray + playerID * 0x177bc - 4) != 0) + MACRO_CALL_MEMBER(TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, STBT_0x3f6); + else if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc - 4) + != 0) + MACRO_CALL_MEMBER(TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( + tribeID, STBT_0x413); + } else { + if (shieldCount >= 3) + continue; + + int targetTribeID = shieldTargetTribeIDs[shieldCount]; + DAT_TribesState::instance.tribes[tribeID].field56_0x1f2 = targetTribeID; + DAT_TribesState::instance.tribes[tribeID].uid2 = DAT_TribesState::instance.tribes[targetTribeID].uid; + int targetUnitID = DAT_TribesState::instance.tribes[targetTribeID].selectionTargetUnitID; + DAT_TribesState::instance.tribes[targetTribeID].tribeID = tribeID; + int tile = DAT_UnitsState::instance.units[targetUnitID].tile; + shieldCount++; + if (tile <= 0) + continue; + + int y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]; + int x = tile - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; + MACRO_CALL_MEMBER(TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, x, y, 0, 0, Instructions::UMSE_0); + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::calculatePreferredRelativeOrientation, + DAT_DirectionAlgorithmState::ptr)( + DAT_UnitsState::instance.units[targetUnitID].x, DAT_UnitsState::instance.units[targetUnitID].y, x, y); + DAT_TribesState::instance.tribes[tribeID].orientation = DAT_DirectionAlgorithmState::instance.orientation; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 0b12ef91d..3c97098b3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35387,7 +35387,7 @@ SHC_3BB0A8C1_0x004CFB20 | 97.8% | Reimplemented SHC_3BB0A8C1_0x004CFBC0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CFCD0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CFCD0 | 56.0% | Unresolved attackInfo offsets SHC_3BB0A8C1_0x004CFF60 | 0.0% | Pending From fc9775a7510f3158cb713181527022038193ddd8 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:23:56 +0200 Subject: [PATCH 197/242] reimplement: SHC_3BB0A8C1_0x004D2A70 29.89% Orig duplicates move blocks --- .../AI/AICState/aiGiveRaidInstructions.cpp | 302 +++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 109 insertions(+), 195 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp index 5ee5c34cb..e772953e7 100644 --- a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -1,11 +1,9 @@ #include "../AICState.func.hpp" -#include "OpenSHC/Global.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Map/Units/UnitInstructionType.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -17,209 +15,125 @@ namespace OpenSHC { namespace AI { - using OpenSHC::Map::Units::UnitInstructionType; - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - // FUNCTION: STRONGHOLDCRUSADER 0x004D2A70 - void AICState ::aiGiveRaidInstructions(int playerID) + void AICState::aiGiveRaidInstructions(int playerID) { - int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType == 0) + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == 0) return; - int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter; - *piVar1 = *piVar1 + 1; - - BOOLEnum _indexTo6 = FALSE; - - if (*(int*)((int)this + (_aiType + -1) * 0x2a4 + 0x1f0) - <= DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter) { + DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter++; + if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter + >= this->aics[aiType - 1].RaidRetargetDelay) DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter = 0; - } - if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk == 0) { + if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk == 0) DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; - } else { - int iVar4 = DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown; - if (0 < iVar4) - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = iVar4 + -1; - } - -// Helper: do the movement command given a tile -// (was shared LAB_004d2d8d block) -#define DO_MOVE_TO_TILE(_tile, _tribeID3) \ - do { \ - if ((_tile) != 0) { \ - short sVar2_ = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[(_tile)]; \ - int iVar4_ = DAT_ViewportRenderState::instance.translationMatrix[sVar2_].addXgetTile; \ - BOOLEnum BVar5_ = MACRO_CALL_MEMBER( \ - OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)((_tribeID3), (_tile)); \ - if (BVar5_ == FALSE) { \ - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)((_tribeID3), playerID); \ - } else { \ - MACRO_CALL_MEMBER( \ - OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( \ - (_tribeID3), (uint)((int)((_tile) - iVar4_)), (uint)((int)((int)sVar2_)), 0); \ - } \ - } \ - } while (0) - - short* _ptrTribeID3 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + 0xb4; - - do { - int _tribeID3 = (int)*_ptrTribeID3; - DAT_TribesState::instance.tribes[_tribeID3].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - - if ((_tribeID3 != 0) - && (DAT_TribesState::instance.tribes[_tribeID3].uid - == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[_indexTo6 + 0xb4])) { - - int iVar4; - BOOLEnum BVar5; - int _buildingID, _buildingID_2, _buildingTile; - - if ((DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2) - && (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, - DAT_UnitsState::ptr)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) - != 0)) { - - if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) { - _buildingID_2 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( - DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk, - (undefined4)((int)(_indexTo6))); - if (_buildingID_2 == 0) { - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); - if (_buildingID != 0) { - _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] - .buildingEntryY] - .addXgetTile; - DO_MOVE_TO_TILE(_buildingTile, _tribeID3); - } - } else { - _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] - .buildingEntryY] - .addXgetTile; - DO_MOVE_TO_TILE(_buildingTile, _tribeID3); - } - } - - } else if ((DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown - == 0) - && (iVar4 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, - this)(_aiType + -1, playerID), - DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk < iVar4)) { - - if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) - && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, TRUE), - BVar5 == FALSE)) { - - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( - playerID, (undefined4)((int)(_indexTo6))); - - if (_buildingID != 0) { - _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] - .buildingEntryY] - .addXgetTile; - DO_MOVE_TO_TILE(_buildingTile, _tribeID3); - } else { - _buildingID_2 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); - if (_buildingID_2 != 0) { - _buildingTile - = (int)DAT_BuildingsState::instance.buildings[_buildingID_2].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID_2] - .buildingEntryY] - .addXgetTile; - DO_MOVE_TO_TILE(_buildingTile, _tribeID3); - } - } - } - - } else if ((DAT_SkirmishDefinedData::instance.TribeTypeID[_indexTo6] == 0xb6) - || (DAT_SkirmishDefinedData::instance.TribeTypeID[_indexTo6] == 0xb5)) { - - if ((DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter == 0) - && (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, FALSE), - BVar5 == FALSE)) { - - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)( - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk, - (undefined4)((int)(_indexTo6))); - - if (_buildingID == 0) { - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)( - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); - } - - if (_buildingID != 0) { - _buildingTile = (int)DAT_BuildingsState::instance.buildings[_buildingID].buildingEntryX - + DAT_ViewportRenderState::instance - .translationMatrix[DAT_BuildingsState::instance.buildings[_buildingID] - .buildingEntryY] - .addXgetTile; - DO_MOVE_TO_TILE(_buildingTile, _tribeID3); - } - } + else if (DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown > 0) + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown--; + + for (int i = 0; i < 6; i++) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[180 + i]; + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + if (tribeID == 0) + continue; + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[i + 180]) + continue; + + int buildingID = 0; + if (DAT_GameState::instance.playerDataArray[playerID].requestStateUnk == 2 + && MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk) + != 0) { + if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter != 0) + continue; + buildingID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, + this)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk, i); + if (buildingID == 0) + buildingID + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + } else if (DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown == 0 + && DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk + < MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( + aiType - 1, playerID)) { + if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter != 0) + continue; + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)(tribeID, i, TRUE) + != FALSE) + continue; + buildingID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, + this)(playerID, i); + if (buildingID == 0) + buildingID + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + } else if (DAT_SkirmishDefinedData::instance.TribeTypeID[i] == 182 + || DAT_SkirmishDefinedData::instance.TribeTypeID[i] == 181) { + if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter != 0) + continue; + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)(tribeID, i, FALSE) + != FALSE) + continue; + buildingID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, + this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk, i); + if (buildingID == 0) + buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + } else { + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)(tribeID, i, FALSE) + != FALSE) + continue; + + int targetBuildingID = DAT_TribesState::instance.tribes[tribeID].targetBuildingID; + if (targetBuildingID != 0 + && DAT_BuildingsState::instance.buildings[targetBuildingID].uid + == DAT_TribesState::instance.tribes[tribeID].targetBuildingUID + && DAT_BuildingsState::instance.buildings[targetBuildingID].fireDuration == 0 + && MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)(tribeID, i, TRUE) + != FALSE) { + if (DAT_GameState::instance.mapAndTime.yearChanged != 0) + DAT_TribesState::instance.tribes[tribeID].targetBuildingID = 0; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 100; + continue; + } - } else { - BVar5 - = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)(_tribeID3, _indexTo6, FALSE); - if (BVar5 == FALSE) { - iVar4 = (int)DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID; - if ((((iVar4 == 0) - || (DAT_BuildingsState::instance.buildings[iVar4].uid - != DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID)) - || (DAT_BuildingsState::instance.buildings[iVar4].fireDuration != 0)) - || (BVar5 = MACRO_CALL(OpenSHC::Global_Func::CheckTribeActivityPercentages)( - _tribeID3, _indexTo6, TRUE), - BVar5 == FALSE)) { - iVar4 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)( - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); - if (iVar4 == 0) { - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown - = 0; - } else { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, - DAT_UnitsState::ptr)(_tribeID3, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, iVar4, - DAT_BuildingsState::instance.buildings[iVar4].uid, 0); - int iVar3 = DAT_BuildingsState::instance.buildings[iVar4].uid; - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = (short)iVar4; - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingUID = iVar3; - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown - = 100; - } - } else { - if (DAT_GameState::instance.mapAndTime.yearChanged != 0) - DAT_TribesState::instance.tribes[_tribeID3].targetBuildingID = 0; - DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown - = 100; - } - } + targetBuildingID + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)( + DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + if (targetBuildingID == 0) { + DAT_TribesState::instance.tribes[tribeID].targetBuildingID = 0; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; + continue; } + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(tribeID, + OpenSHC::Map::Units::UIT_ATTACK_BUILDING, targetBuildingID, + DAT_BuildingsState::instance.buildings[targetBuildingID].uid, 0); + DAT_TribesState::instance.tribes[tribeID].targetBuildingID = targetBuildingID; + DAT_TribesState::instance.tribes[tribeID].targetBuildingUID + = DAT_BuildingsState::instance.buildings[targetBuildingID].uid; + DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 100; + continue; } - _ptrTribeID3 = _ptrTribeID3 + 1; - _indexTo6 = _indexTo6 + TRUE; - } while ((int)_indexTo6 < 6); - -#undef DO_MOVE_TO_TILE + if (buildingID == 0) + continue; + int tile = DAT_BuildingsState::instance.buildings[buildingID].buildingEntryX + + DAT_ViewportRenderState::instance + .translationMatrix[DAT_BuildingsState::instance.buildings[buildingID].buildingEntryY] + .addXgetTile; + if (tile == 0) + continue; + + int y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]; + int x = tile - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, tile) + == FALSE) + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToCampfire, this)(tribeID, playerID); + else + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( + tribeID, x, y, 0); + } } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 3c97098b3..f6734bf32 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35501,7 +35501,7 @@ SHC_3BB0A8C1_0x004D2870 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D28B0 | 73.0% | Register allocation differs -SHC_3BB0A8C1_0x004D2A70 | 0.0% | Pending +SHC_3BB0A8C1_0x004D2A70 | 29.9% | Orig duplicates move blocks SHC_3BB0A8C1_0x004D2E00 | 100.0% | Reimplemented From a8e27f2b015d64e115ab33eabc9b9a037fea5b96 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:36:16 +0200 Subject: [PATCH 198/242] reimplement: SHC_3BB0A8C1_0x004D3AE0 35.82% Block layout differs --- src/OpenSHC/AI/AICState/aiRecruitUnits.cpp | 341 +++++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 144 insertions(+), 199 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp index 057d9f7c5..f7f6a4555 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp @@ -3,17 +3,13 @@ #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" #include "OpenSHC/Map/TileMapState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" -#include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AIRecruitUnitChoice.hpp" -#include "OpenSHC/AI/AIRecruitUnitChoiceInt.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/AI/AIUnitBehaviourType.hpp" #include "OpenSHC/Game/GameMode2.hpp" #include "OpenSHC/Game/TrailType.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Map/Units/UnitType.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" #include "OpenSHC/Globals/DAT_GameCore.hpp" @@ -26,220 +22,169 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AICState; - using OpenSHC::AI::AIRecruitUnitChoice; - using OpenSHC::AI::AIRecruitUnitChoiceInt; - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - using OpenSHC::AI::AIUnitBehaviourType; - using OpenSHC::Game::GameMode2; - using OpenSHC::Game::TrailType; - using OpenSHC::Map::Buildings::BuildingType; using OpenSHC::Map::Units::UnitType; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; // FUNCTION: STRONGHOLDCRUSADER 0x004D3AE0 - void AICState ::aiRecruitUnits(int playerID) + void AICState::aiRecruitUnits(int playerID) { - int _playerID2 = playerID; - AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - UnitType _unitType = ((UnitType)0); - AICState* _pAICState = this; - int _tribeID_defDiggingUnitMax; - - if (_aiType == OpenSHC::AI::AIT_NULL) + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) return; + int aicIndex = aiType - 1; - bool bVar3 = false; - bool _recruitDefDiggingUnit = false; - int iVar6 = _aiType + ~OpenSHC::AI::AIT_NULL; - - if (((DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER) - && (DAT_GameCore::instance.isSkirmishTrail == TRUE)) - && (DAT_GameCore::instance.currentTrailType == OpenSHC::Game::TT_EXTREME)) - bVar3 = true; - - int iVar4 = iVar6 * 0xa9; - int _aicRecruitInterval = *(int*)((int)this - + (DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling + iVar4) * 4 + 0x164); - int local_8 = -(uint)(_aicRecruitInterval != 0) + 2; - if (bVar3) - local_8 = -(uint)(_aicRecruitInterval != 0) + 3; + bool isExtremeTrail = DAT_GameCore::instance.gameMode_2 == OpenSHC::Game::GM_SKIRMISH_AND_MULTIPLAYER + && DAT_GameCore::instance.isSkirmishTrail == TRUE + && DAT_GameCore::instance.currentTrailType == OpenSHC::Game::TT_EXTREME; - int _nervousActionTracker = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; + int recruitInterval + = (&this->aics[aicIndex].RecruitInterval)[DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling]; + int recruitCount = recruitInterval != 0 ? 1 : 2; + if (isExtremeTrail) + recruitCount++; - if (_nervousActionTracker < 1) { - int* piVar1 = &DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker; - *piVar1 = *piVar1 + 1; - if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker < _aicRecruitInterval) + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0) { + DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker++; + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker < recruitInterval) return; } else { - local_8 = 4; + recruitCount = 4; } - int iVar5 = DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount; DAT_GameState::instance.playerDataArray[playerID].aiRecruitIntervalTracker = 0; + if (DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount <= 0) + return; + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) + return; - if ((0 < iVar5) && (DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) { - AIRecruitUnitChoiceInt AVar2 = DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState; + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_DEFENSIVE) { + int defTotal = this->aics[aicIndex].DefTotal; + if (isExtremeTrail) + defTotal = defTotal * 4 / 3; + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) + defTotal = defTotal * 4; + if (DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk >= defTotal) + return; + } else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState + == OpenSHC::AI::AIRUC_RAIDING) { + if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk + >= MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( + aicIndex, playerID)) + return; + } else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState + == OpenSHC::AI::AIRUC_ATTACKING + && DAT_GameState::instance.playerDataArray[playerID].aiPlayerState != 0) { + return; + } - if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { - int _defTotal = *(int*)((int)this + iVar6 * 0x2a4 + 0x170); - if (bVar3) - _defTotal = (_defTotal * 4) / 3; - if (0 < _nervousActionTracker) - _defTotal = _defTotal * 4; - if (_defTotal <= DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk) - return; - } else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { - iVar5 = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( - iVar6, playerID); - if (iVar5 <= DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk) + bool recruitDiggingUnit = false; + if (this->aics[aicIndex].DefDiggingUnitMax != 0 + && MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)( + playerID) + != 0) { + int diggerTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10]; + if (diggerTribeID == 0 + || DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10] + != DAT_TribesState::instance.tribes[diggerTribeID].uid + || DAT_TribesState::instance.tribes[diggerTribeID].size < this->aics[aicIndex].DefDiggingUnitMax) + recruitDiggingUnit = true; + } + + UnitType unitType = (UnitType)0; + int behaviourType = 0; + for (int i = 0; i < recruitCount; i++) { + if (recruitDiggingUnit && (SEC_RNG::instance.currentNumber2 & 1) != 0) + recruitDiggingUnit = false; + + if (recruitDiggingUnit) { + if (DAT_GameState::instance.playerDataArray[playerID].barracks.id == 0 + && DAT_GameState::instance.playerDataArray[playerID].mercenaryPost.id == 0) return; - } else if ((AVar2 == OpenSHC::AI::AIRUC_ATTACKING) - && (DAT_GameState::instance.playerDataArray[playerID].aiPlayerState != 0)) + unitType = (UnitType)this->aics[aicIndex].DefDiggingUnit; + } else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState + == OpenSHC::AI::AIRUC_DEFENSIVE) { + if (DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex > 7) + DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex = 0; + if ((&this->aics[aicIndex].DefUnit1)[DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex] + == 0) + DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex = 0; + int choice = DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex; + unitType = (UnitType)(&this->aics[aicIndex].DefUnit1)[choice]; + DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex = choice + 1; + } else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState + == OpenSHC::AI::AIRUC_RAIDING) { + if (DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex > 7) + DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex = 0; + if ((&this->aics[aicIndex].RaidUnit1)[DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex] + == 0) + DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex = 0; + int choice = DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex; + unitType = (UnitType)(&this->aics[aicIndex].RaidUnit1)[choice]; + DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex = choice + 1; + } else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState + == OpenSHC::AI::AIRUC_ATTACKING) { + behaviourType = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::randomlySelectAttackUnitTypeToRecruit, this)( + playerID); + unitType = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getUnitTypeForUnitBehaviourType, this)( + playerID, (AIUnitBehaviourType)behaviourType); + } + if (unitType == (UnitType)0) return; - iVar6 = iVar6 * 0x2a4; - - if (((*(int*)((int)this + iVar6 + 0x15c) != 0) - && (iVar5 = MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, - DAT_TileMapState::ptr)(playerID), - iVar5 != 0)) - && ((_tribeID_defDiggingUnitMax = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10], - _tribeID_defDiggingUnitMax == 0 - || ((DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10] - != DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].uid - || ((int)DAT_TribesState::instance.tribes[_tribeID_defDiggingUnitMax].size - < *(int*)((int)this + iVar6 + 0x15c))))))) { - _recruitDefDiggingUnit = true; + int buildingID; + if (unitType == OpenSHC::Map::Units::UT_E_ENGINEER || unitType == OpenSHC::Map::Units::UT_E_LADDER) + buildingID = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + else if (unitType == OpenSHC::Map::Units::UT_TUNNELER) + buildingID = DAT_GameState::instance.playerDataArray[playerID].tunnelersGuild.id; + else if (unitType == OpenSHC::Map::Units::UT_E_MONK) + buildingID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_CATHEDRAL); + else if (unitType < 70) + buildingID = DAT_GameState::instance.playerDataArray[playerID].barracks.id; + else + buildingID = DAT_GameState::instance.playerDataArray[playerID].mercenaryPost.id; + if (buildingID == 0) + return; + + int unitID; + if (unitType == OpenSHC::Map::Units::UT_E_ENGINEER || unitType == OpenSHC::Map::Units::UT_E_LADDER + || unitType == OpenSHC::Map::Units::UT_TUNNELER || unitType == OpenSHC::Map::Units::UT_E_MONK + || unitType >= 70) + unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + unitType, buildingID, playerID, 0); + else + unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, DAT_UnitsState::ptr)( + unitType, buildingID, playerID, 0); + + if (unitID == 0) { + if (this->aics[aicIndex].tradeAmountEquipment <= 0) + return; + if (DAT_UnitsState::instance.euroUnitAcquisitionFailReason != 2) + return; + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0) + DAT_GameState::instance.playerDataArray[playerID] + .resourcesToAcquireArray[DAT_UnitsState::instance.euroUnitRequiredResource] + = this->aics[aicIndex].tradeAmountEquipment; + else + DAT_GameState::instance.playerDataArray[playerID] + .resourcesToAcquireArray[DAT_UnitsState::instance.euroUnitRequiredResource] + = 5; + return; } - playerID = 0; - if (0 < local_8) { - do { - // If we should recruit a digging unit but RNG says no, fall through to normal recruit - if (_recruitDefDiggingUnit && ((byte)SEC_RNG::instance.currentNumber2 & 1) != 0) - _recruitDefDiggingUnit = false; - - if (_recruitDefDiggingUnit) { - if (DAT_GameState::instance.playerDataArray[_playerID2].barracks.id == 0) { - if (DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id == 0) - return; - } - _unitType = *(UnitType*)((int)this + iVar6 + 0x160); - } else { - AIRecruitUnitChoiceInt _unitTypeChoice - = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; - - if (_unitTypeChoice == OpenSHC::AI::AIRUC_DEFENSIVE) { - if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex) - DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; - if (*(int*)((int)this - + (DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex + iVar4) - * 4 - + 0x184) - == 0) - DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex = 0; - int _unitChoiceIndex - = DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex; - _unitType = *(UnitType*)((int)this + (iVar4 + _unitChoiceIndex) * 4 + 0x184); - DAT_GameState::instance.playerDataArray[_playerID2].aiDefUnitChoiceIndex - = _unitChoiceIndex + 1; - } else if (_unitTypeChoice == OpenSHC::AI::AIRUC_RAIDING) { - if (7 < DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex) - DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; - if (*(int*)((int)this - + (DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex - + iVar4) - * 4 - + 0x1ac) - == 0) - DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = 0; - iVar5 = DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex; - _unitType = *(UnitType*)((int)this + (iVar4 + iVar5) * 4 + 0x1ac); - DAT_GameState::instance.playerDataArray[_playerID2].aiRaidUnitChoiceIndex = iVar5 + 1; - } else if (_unitTypeChoice == OpenSHC::AI::AIRUC_ATTACKING) { - _pAICState = (AICState*)MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::randomlySelectAttackUnitTypeToRecruit, this)(_playerID2); - _unitType = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getUnitTypeForUnitBehaviourType, - this)(_playerID2, (AIUnitBehaviourType)((int)(_pAICState))); - } - } - - if (_unitType == ((UnitType)0)) - return; - - int _buildingID; - if (_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; - else if (_unitType == OpenSHC::Map::Units::UT_E_LADDER) - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].engineersGuild.id; - else if (_unitType == OpenSHC::Map::Units::UT_TUNNELER) - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].tunnelersGuild.id; - else if (_unitType == OpenSHC::Map::Units::UT_E_MONK) - _buildingID = MACRO_CALL_MEMBER( - OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, - DAT_BuildingsState::ptr)(_playerID2, OpenSHC::Map::Buildings::BT_CATHEDRAL); - else if ((int)_unitType < 0x46) - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].barracks.id; - else - _buildingID = DAT_GameState::instance.playerDataArray[_playerID2].mercenaryPost.id; - - if (_buildingID == 0) - return; - - int _unitID; - if (((_unitType == OpenSHC::Map::Units::UT_E_ENGINEER) - || (_unitType == OpenSHC::Map::Units::UT_E_LADDER) - || (_unitType == OpenSHC::Map::Units::UT_TUNNELER)) - || ((_unitType == OpenSHC::Map::Units::UT_E_MONK || (0x45 < (int)_unitType)))) { - _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::nonEuroRecruit, - DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); - } else { - _unitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::euroRecruit, - DAT_UnitsState::ptr)(_unitType, (undefined4)((int)(_buildingID)), _playerID2, 0); - } - - if (_unitID == 0) { - iVar6 = *(int*)((int)this + iVar6 + 0x9c); - if (iVar6 < 1) - return; - if (DAT_UnitsState::instance.DAT_EuroUnitAcquisitionFailReason != 2) - return; - if (DAT_GameState::instance.playerDataArray[_playerID2].aiNervousActionsTracker < 1) { - DAT_GameState::instance.playerDataArray[_playerID2] - .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = iVar6; - return; - } - DAT_GameState::instance.playerDataArray[_playerID2] - .resourcesToAcquireArray[DAT_UnitsState::instance.DAT_EuroUnitRequiredResource] = 5; - return; - } - - if (_recruitDefDiggingUnit) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); - } else { - AVar2 = DAT_GameState::instance.playerDataArray[_playerID2].aiRecruitUnitChoiceState; - if (AVar2 == OpenSHC::AI::AIRUC_DEFENSIVE) { - if (DAT_GameState::instance.playerDataArray[_playerID2].totalDefensiveTroopsUnk - < *(int*)((int)this + iVar6 + 0x180)) - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignUnitToATribe, this)(_unitID); - else - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToSmallestPatrolTribe, this)( - _unitID); - } else if (AVar2 == OpenSHC::AI::AIRUC_RAIDING) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignUnitToDefensiveTribe, this)(_unitID); - } else if (AVar2 == OpenSHC::AI::AIRUC_ATTACKING) { - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToItsTribe, this)( - _unitID, (int)((int)(_pAICState))); - } - } - - playerID = playerID + 1; - if (local_8 <= playerID) - return; - } while (true); + if (recruitDiggingUnit) + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAddUnitToMoatDiggerTribe, this)(unitID); + else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState + == OpenSHC::AI::AIRUC_DEFENSIVE) { + if (DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk < this->aics[aicIndex].DefWalls) + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignUnitToATribe, this)(unitID); + else + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToSmallestPatrolTribe, this)(unitID); + } else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState + == OpenSHC::AI::AIRUC_RAIDING) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAssignUnitToDefensiveTribe, this)(unitID); + } else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState + == OpenSHC::AI::AIRUC_ATTACKING) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToItsTribe, this)(unitID, behaviourType); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f6734bf32..1541acdba 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35527,7 +35527,7 @@ SHC_3BB0A8C1_0x004D39B0 | 96.6% | Reimplemented SHC_3BB0A8C1_0x004D39F0 | 0.0% | Pending -SHC_3BB0A8C1_0x004D3AE0 | 0.0% | Pending +SHC_3BB0A8C1_0x004D3AE0 | 35.8% | Block layout differs SHC_3BB0A8C1_0x004D3F20 | 0.0% | Pending From 1d84683d1a80cd83b31cadf0ba8b543bed50fcfc Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:36:17 +0200 Subject: [PATCH 199/242] reimplement: SHC_3BB0A8C1_0x004D2000 13.95% Branch order restructured --- .../AI/AICState/aiCreateSiegeUnits.cpp | 431 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 134 insertions(+), 299 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index 543f48f42..c5536ffb4 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -6,15 +6,12 @@ #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" #include "OpenSHC/Commands/MappersEnum.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" -#include "OpenSHC/Map/Buildings/BuildingTypeShort.hpp" #include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp" #include "OpenSHC/Map/Units/UnitInstructionType.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" @@ -28,319 +25,157 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - using OpenSHC::AI::Tribes::AITribeType; using OpenSHC::Commands::MappersEnum; using OpenSHC::Map::Buildings::BuildingType; - using OpenSHC::Map::Buildings::BuildingTypeShort; - using OpenSHC::Map::Units::SomeTribeBehaviorType; - using OpenSHC::Map::Units::UnitInstructionType; using OpenSHC::Map::Units::UnitType; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; // FUNCTION: STRONGHOLDCRUSADER 0x004D2000 - void AICState ::aiCreateSiegeUnits(int playerID) + void AICState::aiCreateSiegeUnits(int playerID) { - AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType == OpenSHC::AI::AIT_NULL) + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) return; - - int _engineersGuildID = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; - if (!((0 < _engineersGuildID) - && (DAT_BuildingsState::instance.buildings[_engineersGuildID].buildingType - == OpenSHC::Map::Buildings::BT_ENGINEERSGUILD)) - || DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) + int guildID = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + if (guildID <= 0) + return; + if (DAT_BuildingsState::instance.buildings[guildID].buildingType != OpenSHC::Map::Buildings::BT_ENGINEERSGUILD) + return; + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) return; - int _siegeInfoIndex = 0; - int _incrementsBy5 = 0; - int _mappingOffset = 0; - int* _pDelay; - - do { - UnitType _unitType - = *(UnitType*)((int)&DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[0].unitType - + _mappingOffset); - int _tribeSize = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[*( - int*)((int)&DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[0].slot + _mappingOffset)]; - int _slotIndex = 0; - int _nextSlotIndex; + // The original also processes index 4, one past the end of SiegeEngineMetaInfoArray. + for (int siegeIndex = 0; siegeIndex < 5; siegeIndex++) { + UnitType unitType = (UnitType)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].unitType; + int slot = DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].slot; + int locationCount = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[slot]; + if (locationCount >= 4) + locationCount = 3; - if (_tribeSize >= 4) - _tribeSize = 3; + for (int i = 0; i < locationCount; i++) { + int location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[slot][i]; + if (location <= 0) + continue; - if (0 < _tribeSize) { - do { - _nextSlotIndex = _slotIndex + 1; - int _location = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[*( - int*)((int)&DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[0].slot - + _mappingOffset)][_slotIndex]; + int existingBuildingID = (short)DAT_TileMapState::instance.BuildingLayer[location]; + int unitID = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID; + int uid = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid; + int buildingID + = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID; - if (0 < _location) { - int _existingBuildingID = (int)(short)DAT_TileMapState::instance.BuildingLayer[_location]; - int _engineIndex = _incrementsBy5 + _slotIndex; - int _unitID = DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unitID; - int _uid = DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .uid; - int _tile = DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .buildingID; + if ((unitID != 0 && DAT_UnitsState::instance.units[unitID].uid != uid) + || (buildingID != 0 && DAT_BuildingsState::instance.buildings[buildingID].uid != uid)) { + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unknown = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID = 0; + continue; + } - if ((_unitID == 0) || (DAT_UnitsState::instance.units[_unitID].uid == _uid)) { - if ((_tile == 0) || (DAT_BuildingsState::instance.buildings[_tile].uid == _uid)) { - if (_unitID == 0) { - if (_tile == 0) { - bool _doPlace = false; - if (_existingBuildingID == 0) { - if (0x1f < _mappingOffset) - _doPlace = true; - } else if ((_mappingOffset < 0x20)) { - BuildingTypeShort _existingBuildingType - = DAT_BuildingsState::instance.buildings[_existingBuildingID] - .buildingType; - if (_existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER4 - || _existingBuildingType == OpenSHC::Map::Buildings::BT_TOWER5) - _doPlace = true; - } else { - _doPlace = true; - } + if (buildingID != 0) { + int requiredEngineers = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, + DAT_BuildingsState::ptr)(buildingID); + if (DAT_BuildingsState::instance.buildings[buildingID].currentEmployeeCount == requiredEngineers) + continue; + if (requiredEngineers > DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; + continue; + } + int tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)( + playerID, requiredEngineers); + DAT_TribesState::instance.tribes[tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( + tribeID, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, buildingID, + DAT_BuildingsState::instance.buildings[buildingID].uid, 0); + return; + } - if (_doPlace) { - int _requiredGold - = DAT_BuildingsState::instance - .buildingCosts[*(int*)((int)&DAT_SkirmishDefinedData::instance - .SiegeEngineMetaInfoArray[0] - .buildingType - + _mappingOffset)] - .requiredGold; - int _aicOffset = (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4; - _pDelay = &DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay; - *_pDelay = *_pDelay + 1; - if ((_requiredGold <= DAT_GameState::instance.playerDataArray[playerID] - .currentResources[0xf] - + *(int*)((int)this + _aicOffset + 0x118)) - && (*(int*)((int)this + _aicOffset + 0x11c) - <= DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay)) { - int _y = (int)DAT_ViewportRenderState::instance - .tileTranslationMatrix_YComponent[_location]; - int _placeTile = _location - - DAT_ViewportRenderState::instance.translationMatrix[_y] - .addXgetTile; - if (_siegeInfoIndex < 2) { - int _spawnedUnit = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::spawnUnit, - DAT_UnitsState::ptr)(playerID, playerID, _placeTile * 8 + 4, - _y * 8 + 4, - (int)((int)(DAT_BuildingsState::instance - .buildings[_existingBuildingID] - .terrainHeightUnk)), - _unitType); - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .unitID = _spawnedUnit; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .uid = DAT_UnitsState::instance.units[_spawnedUnit].uid; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .buildingID = 0; - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: - processPlacementResourceLossForBuildingType, - DAT_BuildingsState::ptr)(playerID, - (BuildingType)((int)(DAT_SkirmishDefinedData::instance - .SiegeEngineMetaInfoArray[_siegeInfoIndex] - .buildingType)), - 0); - } else { - MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, - DAT_TileMapState::ptr)(playerID, _placeTile, _y, - (MappersEnum)(( - int)((uint)(ushort)(short)DAT_SkirmishDefinedData::instance - .SiegeEngineMetaInfoArray[_siegeInfoIndex] - .commandBuildingType)), - 3, 0xf); - if (DAT_TileMapState::instance.buildingPlacementFail == FALSE) { - int* _pGold = DAT_GameState::instance.playerDataArray[playerID] - .currentResources - + 0xf; - *_pGold = *_pGold - _requiredGold; - int _newBuildingID - = DAT_TileMapState::instance.placedBuildingID; - int _newUID = DAT_BuildingsState::instance - .buildings[DAT_TileMapState::instance - .placedBuildingID] - .uid; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .unitID = 0; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .uid = _newUID; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[_siegeInfoIndex][_slotIndex] - .buildingID = _newBuildingID; - } - } - *(undefined4*)(playerID * 0x39f4 + 0x115f48c + _slotIndex * 20 - + _siegeInfoIndex * 100) = 0; - return; - } - } - } else { - int _requiredEngineerCount - = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: - getRequiredEngineerCountForSiegeBuilding, - DAT_BuildingsState::ptr)(_tile); - if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount - != _requiredEngineerCount) { - if (_requiredEngineerCount - <= DAT_GameState::instance.playerDataArray[playerID] - .engineerCountRelated) { - int _engineersTribe = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, - this)(playerID, _requiredEngineerCount); - DAT_TribesState::instance.tribes[_engineersTribe].tribeType - = OpenSHC::AI::Tribes::AITT_ENGINEERS; - DAT_TribesState::instance.tribes[_engineersTribe].tribeBehaviorType - = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, - DAT_TribesState::ptr)(_engineersTribe, - OpenSHC::Map::Units:: - UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, - _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); - return; - } - DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; - } - } - } else { - if (_tile != 0) { - int _requiredEngineerCount2 - = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func:: - getRequiredEngineerCountForSiegeBuilding, - DAT_BuildingsState::ptr)(_tile); - if (DAT_BuildingsState::instance.buildings[_tile].currentEmployeeCount - != _requiredEngineerCount2) { - if (_requiredEngineerCount2 - <= DAT_GameState::instance.playerDataArray[playerID] - .engineerCountRelated) { - int _engineersTribe2 = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, - this)(playerID, _requiredEngineerCount2); - DAT_TribesState::instance.tribes[_engineersTribe2].tribeType - = OpenSHC::AI::Tribes::AITT_ENGINEERS; - DAT_TribesState::instance.tribes[_engineersTribe2].tribeBehaviorType - = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, - DAT_TribesState::ptr)(_engineersTribe2, - OpenSHC::Map::Units:: - UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, - _tile, DAT_BuildingsState::instance.buildings[_tile].uid, 0); - return; - } - DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; - } - } else { - int _remainingRequiredEngineers = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, - DAT_UnitsState::ptr)(_unitID); - if (0 < _remainingRequiredEngineers) { - if (DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated - < _remainingRequiredEngineers) { - DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired - = TRUE; - } else { - int _tribeID = MACRO_CALL_MEMBER( - OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, - this)(playerID, _remainingRequiredEngineers); - int _targetUnitID = (int)DAT_TribesState::instance.tribes[_tribeID] - .selectionTargetUnitID; - if ((_targetUnitID != 0) - && (MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func:: - calculateCanPlayerUnitsNavigateToAreaFromArea, - DAT_PathFindingState::ptr)(playerID, - (dword)((int)((int)(short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_UnitsState::instance - .units[_unitID] - .tile])), - (dword)((int)((int)(short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_UnitsState::instance - .units[_targetUnitID] - .tile])), - 0) - != 0)) { - DAT_TribesState::instance.tribes[_tribeID].tribeType - = OpenSHC::AI::Tribes::AITT_ENGINEERS; - DAT_TribesState::instance.tribes[_tribeID].tribeBehaviorType - = OpenSHC::Map::Units::STBT_0x41c; - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, - DAT_UnitsState::ptr)(_tribeID, - OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, _unitID, - DAT_UnitsState::instance.units[_unitID].uid, 0); - return; - } - } - } - } - } - } else { - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unitID = 0; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .uid = 0; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay = 0; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unknown = 0; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .buildingID = 0; - } - } else { - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unitID = 0; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .uid = 0; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .delay = 0; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .unknown = 0; - DAT_GameState::instance.playerDataArray[playerID] - .aiSiegeCreationInformation[0][_engineIndex] - .buildingID = 0; - } + if (unitID != 0) { + int remainingEngineers = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, + DAT_UnitsState::ptr)(unitID); + if (remainingEngineers <= 0) + continue; + if (DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated < remainingEngineers) { + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; + continue; } + int tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)( + playerID, remainingEngineers); + int targetUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + if (targetUnitID == 0) + continue; + if (MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + DAT_PathFindingState::ptr)(playerID, + (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[unitID].tile], + (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[targetUnitID].tile], + 0) + == 0) + continue; + DAT_TribesState::instance.tribes[tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x41c; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(tribeID, + OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, unitID, DAT_UnitsState::instance.units[unitID].uid, 0); + return; + } - _slotIndex = _nextSlotIndex; - } while (_nextSlotIndex < _tribeSize); - } + if (existingBuildingID == 0) { + if (siegeIndex < 2) + continue; + } else if (siegeIndex < 2) { + if (DAT_BuildingsState::instance.buildings[existingBuildingID].buildingType != OpenSHC::Map::Buildings::BT_TOWER4 + && DAT_BuildingsState::instance.buildings[existingBuildingID].buildingType + != OpenSHC::Map::Buildings::BT_TOWER5) + continue; + } + + int requiredGold = DAT_BuildingsState::instance + .buildingCosts[DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].buildingType] + .requiredGold; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay++; + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] + + this->aics[aiType - 1].defSiegeEngineGoldThreshold + < requiredGold) + continue; + if (DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay + < this->aics[aiType - 1].defSiegeEngineBuildDelay) + continue; - _siegeInfoIndex = _siegeInfoIndex + 1; - _incrementsBy5 = _incrementsBy5 + 5; - _mappingOffset = _mappingOffset + 16; - if (64 < _mappingOffset) + int y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[location]; + int x = location - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; + if (siegeIndex < 2) { + int spawnedUnitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::spawnUnit, DAT_UnitsState::ptr)( + playerID, playerID, x * 8 + 4, y * 8 + 4, + DAT_BuildingsState::instance.buildings[existingBuildingID].terrainHeightUnk, unitType); + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID + = spawnedUnitID; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid + = DAT_UnitsState::instance.units[spawnedUnitID].uid; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processPlacementResourceLossForBuildingType, + DAT_BuildingsState::ptr)(playerID, + (BuildingType)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].buildingType, 0); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID, x, y, + (MappersEnum)(ushort)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex] + .commandBuildingType, + 3, 15); + if (DAT_TileMapState::instance.buildingPlacementFail == FALSE) { + DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] -= requiredGold; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid + = DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.placedBuildingID].uid; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID + = DAT_TileMapState::instance.placedBuildingID; + } + } + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay = 0; return; - } while (true); + } + } } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1541acdba..e0d15a2bc 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35479,7 +35479,7 @@ SHC_3BB0A8C1_0x004D1D60 | 52.5% | Stuck SHC_3BB0A8C1_0x004D1F00 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D2000 | 0.0% | Pending +SHC_3BB0A8C1_0x004D2000 | 13.9% | Branch order restructured SHC_3BB0A8C1_0x004D2080 | 0.0% | Pending From 9214be72fc91fdde26df798598c01b1843745cbe Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:47:18 +0200 Subject: [PATCH 200/242] reimplement: SHC_3BB0A8C1_0x004D2000 29.44% Register allocation differs --- .../AI/AICState/aiCreateSiegeUnits.cpp | 169 ++++++++++-------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 100 insertions(+), 71 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index c5536ffb4..ac16c8c01 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -62,8 +62,15 @@ namespace AI { int buildingID = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID; - if ((unitID != 0 && DAT_UnitsState::instance.units[unitID].uid != uid) - || (buildingID != 0 && DAT_BuildingsState::instance.buildings[buildingID].uid != uid)) { + if (unitID != 0 && DAT_UnitsState::instance.units[unitID].uid != uid) { + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unknown = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID = 0; + continue; + } + if (buildingID != 0 && DAT_BuildingsState::instance.buildings[buildingID].uid != uid) { DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID = 0; DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid = 0; DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay = 0; @@ -72,28 +79,103 @@ namespace AI { continue; } - if (buildingID != 0) { - int requiredEngineers = MACRO_CALL_MEMBER( - OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, - DAT_BuildingsState::ptr)(buildingID); - if (DAT_BuildingsState::instance.buildings[buildingID].currentEmployeeCount == requiredEngineers) + if (unitID == 0) { + if (buildingID != 0) { + int requiredEngineers = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, + DAT_BuildingsState::ptr)(buildingID); + if (DAT_BuildingsState::instance.buildings[buildingID].currentEmployeeCount == requiredEngineers) + continue; + if (requiredEngineers > DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; + continue; + } + int tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)( + playerID, requiredEngineers); + DAT_TribesState::instance.tribes[tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( + tribeID, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, buildingID, + DAT_BuildingsState::instance.buildings[buildingID].uid, 0); + return; + } + + if (existingBuildingID == 0) { + if (siegeIndex < 2) + continue; + } else if (siegeIndex < 2) { + if (DAT_BuildingsState::instance.buildings[existingBuildingID].buildingType != OpenSHC::Map::Buildings::BT_TOWER4 + && DAT_BuildingsState::instance.buildings[existingBuildingID].buildingType + != OpenSHC::Map::Buildings::BT_TOWER5) + continue; + } + + int requiredGold = DAT_BuildingsState::instance + .buildingCosts[DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].buildingType] + .requiredGold; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay++; + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] + + this->aics[aiType - 1].defSiegeEngineGoldThreshold + < requiredGold) continue; - if (requiredEngineers > DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { - DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; + if (DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay + < this->aics[aiType - 1].defSiegeEngineBuildDelay) continue; + + int y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[location]; + int x = location - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; + if (siegeIndex < 2) { + int spawnedUnitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::spawnUnit, DAT_UnitsState::ptr)( + playerID, playerID, x * 8 + 4, y * 8 + 4, + DAT_BuildingsState::instance.buildings[existingBuildingID].terrainHeightUnk, unitType); + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID + = spawnedUnitID; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid + = DAT_UnitsState::instance.units[spawnedUnitID].uid; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID = 0; + MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processPlacementResourceLossForBuildingType, + DAT_BuildingsState::ptr)(playerID, + (BuildingType)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].buildingType, 0); + } else { + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID, x, y, + (MappersEnum)(ushort)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex] + .commandBuildingType, + 3, 15); + if (DAT_TileMapState::instance.buildingPlacementFail == FALSE) { + DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] -= requiredGold; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid + = DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.placedBuildingID].uid; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID + = DAT_TileMapState::instance.placedBuildingID; + } } - int tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)( - playerID, requiredEngineers); - DAT_TribesState::instance.tribes[tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; - DAT_TribesState::instance.tribes[tribeID].tribeBehaviorType - = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( - tribeID, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, buildingID, - DAT_BuildingsState::instance.buildings[buildingID].uid, 0); + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay = 0; return; } if (unitID != 0) { + if (buildingID != 0) { + int requiredEngineers = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, + DAT_BuildingsState::ptr)(buildingID); + if (DAT_BuildingsState::instance.buildings[buildingID].currentEmployeeCount == requiredEngineers) + continue; + if (requiredEngineers > DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { + DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; + continue; + } + int tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)( + playerID, requiredEngineers); + DAT_TribesState::instance.tribes[tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[tribeID].tribeBehaviorType + = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( + tribeID, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, buildingID, + DAT_BuildingsState::instance.buildings[buildingID].uid, 0); + return; + } int remainingEngineers = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, DAT_UnitsState::ptr)(unitID); if (remainingEngineers <= 0) @@ -121,59 +203,6 @@ namespace AI { OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, unitID, DAT_UnitsState::instance.units[unitID].uid, 0); return; } - - if (existingBuildingID == 0) { - if (siegeIndex < 2) - continue; - } else if (siegeIndex < 2) { - if (DAT_BuildingsState::instance.buildings[existingBuildingID].buildingType != OpenSHC::Map::Buildings::BT_TOWER4 - && DAT_BuildingsState::instance.buildings[existingBuildingID].buildingType - != OpenSHC::Map::Buildings::BT_TOWER5) - continue; - } - - int requiredGold = DAT_BuildingsState::instance - .buildingCosts[DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].buildingType] - .requiredGold; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay++; - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] - + this->aics[aiType - 1].defSiegeEngineGoldThreshold - < requiredGold) - continue; - if (DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay - < this->aics[aiType - 1].defSiegeEngineBuildDelay) - continue; - - int y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[location]; - int x = location - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; - if (siegeIndex < 2) { - int spawnedUnitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::spawnUnit, DAT_UnitsState::ptr)( - playerID, playerID, x * 8 + 4, y * 8 + 4, - DAT_BuildingsState::instance.buildings[existingBuildingID].terrainHeightUnk, unitType); - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID - = spawnedUnitID; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid - = DAT_UnitsState::instance.units[spawnedUnitID].uid; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID = 0; - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processPlacementResourceLossForBuildingType, - DAT_BuildingsState::ptr)(playerID, - (BuildingType)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].buildingType, 0); - } else { - MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID, x, y, - (MappersEnum)(ushort)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex] - .commandBuildingType, - 3, 15); - if (DAT_TileMapState::instance.buildingPlacementFail == FALSE) { - DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] -= requiredGold; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid - = DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.placedBuildingID].uid; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID - = DAT_TileMapState::instance.placedBuildingID; - } - } - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay = 0; - return; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index e0d15a2bc..b595d17b9 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35479,7 +35479,7 @@ SHC_3BB0A8C1_0x004D1D60 | 52.5% | Stuck SHC_3BB0A8C1_0x004D1F00 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D2000 | 13.9% | Branch order restructured +SHC_3BB0A8C1_0x004D2000 | 29.4% | Register allocation differs SHC_3BB0A8C1_0x004D2080 | 0.0% | Pending From 59b864e0051ce7e7a18b04470fd536f09723ae19 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:47:18 +0200 Subject: [PATCH 201/242] reimplement: SHC_3BB0A8C1_0x004D2A70 30.02% Register allocation differs --- src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp | 5 +++-- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp index e772953e7..22f418b16 100644 --- a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -21,10 +21,11 @@ namespace AI { int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; if (aiType == 0) return; + int aicIndex = aiType - 1; DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter++; if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter - >= this->aics[aiType - 1].RaidRetargetDelay) + >= this->aics[aicIndex].RaidRetargetDelay) DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter = 0; if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk == 0) @@ -56,7 +57,7 @@ namespace AI { } else if (DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown == 0 && DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk < MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( - aiType - 1, playerID)) { + aicIndex, playerID)) { if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter != 0) continue; if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)(tribeID, i, TRUE) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b595d17b9..fc37273f2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35501,7 +35501,7 @@ SHC_3BB0A8C1_0x004D2870 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D28B0 | 73.0% | Register allocation differs -SHC_3BB0A8C1_0x004D2A70 | 29.9% | Orig duplicates move blocks +SHC_3BB0A8C1_0x004D2A70 | 30.0% | Register allocation differs SHC_3BB0A8C1_0x004D2E00 | 100.0% | Reimplemented From eb7abcb08dc073f2928413963188e5592b946ef6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:57:59 +0200 Subject: [PATCH 202/242] reimplement: SHC_3BB0A8C1_0x004CB180 100.00% Reimplemented --- src/OpenSHC/AI/AICState/aiFarmChoice.cpp | 10 +++------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiFarmChoice.cpp b/src/OpenSHC/AI/AICState/aiFarmChoice.cpp index ca1d6515f..46898001b 100644 --- a/src/OpenSHC/AI/AICState/aiFarmChoice.cpp +++ b/src/OpenSHC/AI/AICState/aiFarmChoice.cpp @@ -8,15 +8,11 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB180 int AICState::aiFarmChoice(PlayerID playerID) - { - int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (aiType == AITA_NULL) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) return 0; - } - - /* ugly because EAX is always 1 or higher */ - return (&this->aics[(aiType - 1)].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + return (&this->aics[aiType - 1].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index fc37273f2..7f94b39bd 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34205,7 +34205,7 @@ SHC_3BB0A8C1_0x004CB120 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB150 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CB180 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB180 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB1B0 | 0.0% | Pending From e22e8ad32269a67661e2c90f3a5d83ab16666b0b Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:57:59 +0200 Subject: [PATCH 203/242] reimplement: SHC_3BB0A8C1_0x004CB220 97.83% Reimplemented --- src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp | 24 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp index 8f0775778..02ab1e06c 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildFarm.cpp @@ -11,21 +11,19 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB220 BOOLEnum AICState::aiShouldBuildFarm(int playerID) { - unsigned int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (aiType == AITA_NULL) { - return (BOOLEnum)aiType; - } - aiType -= 1; - int const _farmCount + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) + return FALSE; + int aicIndex = aiType - 1; + + int farmCount = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countFarms, DAT_BuildingsState::ptr)(playerID, 1); - if (_farmCount <= 0) { + if (farmCount <= 0) return TRUE; - } - if (_farmCount < (int)this->aics[aiType].maxFarms) { - return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / _farmCount - >= (int)this->aics[aiType].populationPerFarm; - } - return FALSE; + if (farmCount >= this->aics[aicIndex].maxFarms) + return FALSE; + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / farmCount + >= this->aics[aicIndex].populationPerFarm; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 7f94b39bd..f164e0b5f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34209,7 +34209,7 @@ SHC_3BB0A8C1_0x004CB180 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB1B0 | 0.0% | Pending -SHC_3BB0A8C1_0x004CB220 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB220 | 97.8% | Reimplemented SHC_3BB0A8C1_0x004CB290 | 0.0% | Pending From 0b1598b594efb4f63ddfa0f66a0b9317cb290301 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:58:00 +0200 Subject: [PATCH 204/242] reimplement: SHC_3BB0A8C1_0x004CB290 98.11% Reimplemented --- .../AI/AICState/aiShouldBuildWoodcutter.cpp | 34 ++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp index 221047ca9..79564b50f 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp @@ -13,35 +13,29 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB290 BOOLEnum AICState::aiShouldBuildWoodcutter(int playerID) { - if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0) { + if (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 0) return FALSE; - } int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (aiType == AITA_NULL) { + if (aiType == AITA_NULL) return FALSE; - } - aiType -= 1; - // AICSpecification const* spec = &this->aics[aiType]; - if ((int)this->aics[aiType].populationPerWoodcutter <= 0) { + int aicIndex = aiType - 1; + if (this->aics[aicIndex].populationPerWoodcutter <= 0) return FALSE; - } - int iVar3 = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, - DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT, 1); - if (iVar3 <= 0) { - iVar3 = 1; + + int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)( + playerID, Map::Buildings::BT_WOODCUTTERSHUT, 1); + if (count <= 0) { + count = 1; } else { - if (iVar3 >= (int)this->aics[aiType].maxWoodcutters) { + if (count >= this->aics[aicIndex].maxWoodcutters) return FALSE; - } - if ((6 <= iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 90)) { + if (count >= 6 && DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 90) return FALSE; - } - if ((3 <= iVar3) && (DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 30)) { + if (count >= 3 && DAT_AIVState::instance.mapExtraInfo.totalWoodAvailable <= 30) return FALSE; - } } - return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / iVar3 - >= (int)this->aics[aiType].populationPerWoodcutter; + return DAT_GameState::instance.playerDataArray[playerID].currentPopulation / count + >= this->aics[aicIndex].populationPerWoodcutter; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index f164e0b5f..a986ec0ec 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34211,7 +34211,7 @@ SHC_3BB0A8C1_0x004CB1B0 | 0.0% | Pending SHC_3BB0A8C1_0x004CB220 | 97.8% | Reimplemented -SHC_3BB0A8C1_0x004CB290 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB290 | 98.1% | Reimplemented SHC_3BB0A8C1_0x004CB330 | 97.5% | Reimplemented From 623a583618dac5d4ccccb2f2902393214201dced Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:58:00 +0200 Subject: [PATCH 205/242] reimplement: SHC_3BB0A8C1_0x004CF470 56.00% Orig recomputes player offset --- .../aiCommandTribe11StandGroundToGate.cpp | 31 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp index ffd86e8ba..5d8597354 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp @@ -13,33 +13,20 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF470 void AICState::aiCommandTribe11StandGroundToGate(int playerID) { - if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) return; - } - - int const iVar2 = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xb]; - - if (iVar2 == 0) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[11]; + if (tribeID == 0) return; - } - - if (DAT_TribesState::instance.tribes[iVar2].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xb]) { + if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[11]) return; - } - - if (DAT_TribesState::instance.tribes[iVar2].selectionTargetUnitID == 0) { + if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) return; - } - - DAT_TribesState::instance.tribes[iVar2].unitStance = Map::Units::Behavior::USE_STAND_GROUND; - if (MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)( - iVar2) - == 0) { - MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)( - iVar2); - } + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_STAND_GROUND; + if (MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)(tribeID) + == 0) + MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)(tribeID); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a986ec0ec..5306e0577 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35359,7 +35359,7 @@ SHC_3BB0A8C1_0x004CF2E0 | 0.0% | Pending SHC_3BB0A8C1_0x004CF400 | 62.22% | Reimplemented functionally, our compiler improves on original by avoiding recomputations -SHC_3BB0A8C1_0x004CF470 | 0.0% | Pending +SHC_3BB0A8C1_0x004CF470 | 56.0% | Orig recomputes player offset SHC_3BB0A8C1_0x004CF4F0 | 57.10% | Reimplemented functionally, our compiler improves on original by avoiding recomputations From c1d9ea137797b07e246ce83b08ccc5edd7d09388 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:58:00 +0200 Subject: [PATCH 206/242] reimplement: SHC_3BB0A8C1_0x004CF2E0 46.81% Orig recomputes player offset --- .../aiCommandTribe12AggressiveApproach.cpp | 76 ++++++------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 26 insertions(+), 52 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp index a3e1f3237..c217fd2e4 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp @@ -5,7 +5,6 @@ #include "OpenSHC/AI/AIType.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" -#include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" #include "OpenSHC/Globals/DAT_PathFindingState.hpp" @@ -15,68 +14,43 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CF2E0 - void AICState ::aiCommandTribe12AggressiveApproach(int playerID) + void AICState::aiCommandTribe12AggressiveApproach(int playerID) { - if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_NULL) return; - } - - int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xc]; - - if (tribeID == 0) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[12]; + if (tribeID == 0) return; - } - - if (DAT_TribesState::instance.tribes[tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xc]) { + if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[12]) return; - } - - int targetUnitID = (int)DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; - - if (targetUnitID == 0) { + int targetUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; + if (targetUnitID == 0) return; - } MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, - DAT_PathFindingState::ptr)((int)DAT_UnitsState::instance.units[targetUnitID].x, - (uint)((int)((int)DAT_UnitsState::instance.units[targetUnitID].y)), -1, -1, 10000, FALSE); - + DAT_PathFindingState::ptr)(DAT_UnitsState::instance.units[targetUnitID].x, + DAT_UnitsState::instance.units[targetUnitID].y, -1, -1, 10000, FALSE); int attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID; - DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - // Try progressively smaller search costs; stop at the first one that finds a destination. - // The later probes deliberately re-read attackedPlayerID, as the calls may update it. - if ((MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)(attackedPlayerID, 200) - != FALSE) - || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 150) - != FALSE) - || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 100) - != FALSE) - || (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, - DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 50) - != FALSE)) { - - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - tribeID, (uint)((int)(DAT_PathFindingState::instance.ALG_ResultX)), - (uint)((int)(DAT_PathFindingState::instance.ALG_ResultY)), 0, 0, - OpenSHC::Map::Units::Instructions::UMSE_0); - } + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)(attackedPlayerID, 200) + == FALSE + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 150) + == FALSE + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 100) + == FALSE + && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findDestinationCostLowerThan6, + DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 50) + == FALSE) + return; - return; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(tribeID, + DAT_PathFindingState::instance.ALG_ResultX, DAT_PathFindingState::instance.ALG_ResultY, 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5306e0577..4bf3d7c3a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35355,7 +35355,7 @@ SHC_3BB0A8C1_0x004CF180 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CF270 | 0.0% | Pending -SHC_3BB0A8C1_0x004CF2E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CF2E0 | 46.8% | Orig recomputes player offset SHC_3BB0A8C1_0x004CF400 | 62.22% | Reimplemented functionally, our compiler improves on original by avoiding recomputations From b937ed053fb020d17d187ef2a98cf6daf3cce9b2 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 16:58:01 +0200 Subject: [PATCH 207/242] reimplement: SHC_3BB0A8C1_0x004CF270 62.22% Orig recomputes player offset --- .../aiCommandTribe13DefensiveWave.cpp | 20 +++++-------------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp index bf47a5dfa..37cd28012 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp @@ -13,27 +13,17 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CF270 void AICState::aiCommandTribe13DefensiveWave(int playerID) { - if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) { + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) return; - } - - int tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0xd]; - - if (tribeID == 0) { + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[13]; + if (tribeID == 0) return; - } - - if (DAT_TribesState::instance.tribes[tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xd]) { + if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[13]) return; - } - - if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) { + if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) return; - } DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( tribeID, Map::Units::STBT_0x3f4); } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4bf3d7c3a..d588ce188 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35353,7 +35353,7 @@ SHC_3BB0A8C1_0x004CF060 | 0.0% | Pending SHC_3BB0A8C1_0x004CF180 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CF270 | 0.0% | Pending +SHC_3BB0A8C1_0x004CF270 | 62.2% | Orig recomputes player offset SHC_3BB0A8C1_0x004CF2E0 | 46.8% | Orig recomputes player offset From 4a5694b962ff4629bfd03d61efcd5865499b2468 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:07:03 +0200 Subject: [PATCH 208/242] reimplement: SHC_3BB0A8C1_0x004D3F20 97.40% Reimplemented --- .../AI/AICState/aiAssignMoatDiggers.cpp | 65 ++++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp index d0bfecd84..ea2a93c40 100644 --- a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp +++ b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp @@ -10,40 +10,41 @@ namespace OpenSHC { namespace AI { - // FUNCTION: STRONGHOLDCRUSADER 0x004D3F70 + using namespace OpenSHC::Map::Units; + + // FUNCTION: STRONGHOLDCRUSADER 0x004D3F20 void AICState::aiAssignMoatDiggers(int playerID) { - int _unitID; - int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - Map::Units::UnitTypeShort _unitType; - if (((_aiType != AITA_NULL) && (0 < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType0)) - && (_unitID = 1, 1 < (int)DAT_UnitsState::instance.maxUnitCount)) { - Map::Units::Unit* _ptrUnit = &DAT_UnitsState::instance.units[1]; - do { - if ((((((_ptrUnit->logicalState != Map::Units::ULS_INVISIBLE) && (_ptrUnit->owner == playerID)) - && ((_ptrUnit->isSelectable_OR_matchTime != 0 - && ((_ptrUnit->aiUnitBehaviourType == 0 && (_ptrUnit->dying == 0)))))) - && (_unitType = _ptrUnit->unitType, _unitType != Map::Units::UT_LORD)) - && ((((_unitType != Map::Units::UT_E_ENGINEER && (_unitType != Map::Units::UT_TUNNELER)) - && (_unitType != Map::Units::UT_S_CATAPULT)) - && (( - _unitType != Map::Units::UT_S_TREBUCHET && (_unitType != Map::Units::UT_S_MANGONEL)))))) - && (( - (_unitType != Map::Units::UT_S_TOWER - && ((_unitType != Map::Units::UT_S_BATTERINGRAM && (_unitType != Map::Units::UT_S_SHIELD)))) - && ((_unitType != Map::Units::UT_S_BALLISTA && (_unitType != Map::Units::UT_S_FBALLISTA)))))) { - if (((((int)this->aics[_aiType - 1].DefDiggingUnitMax == 0) - || (_unitType == Map::Units::UT_E_ARCHER)) - || (_unitType == Map::Units::UT_E_XBOW)) - || (_ptrUnit->someUnitStat4 == 0)) { - MACRO_CALL_MEMBER(AICState_Func::assignUnitToATribe, this)(_unitID); - } else { - MACRO_CALL_MEMBER(AICState_Func::aiAddUnitToMoatDiggerTribe, this)(_unitID); - } - } - _unitID = _unitID + 1; - _ptrUnit = _ptrUnit + 1; - } while (_unitID < (int)DAT_UnitsState::instance.maxUnitCount); + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) + return; + int aicIndex = aiType - 1; + if (DAT_GameState::instance.playerDataArray[playerID].totalTroopsType0 <= 0) + return; + + for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { + if (DAT_UnitsState::instance.units[unitID].logicalState == ULS_INVISIBLE) + continue; + if (DAT_UnitsState::instance.units[unitID].owner != playerID) + continue; + if (DAT_UnitsState::instance.units[unitID].isSelectable_OR_matchTime == 0) + continue; + if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType != 0) + continue; + if (DAT_UnitsState::instance.units[unitID].dying != 0) + continue; + + if (DAT_UnitsState::instance.units[unitID].unitType == UT_LORD || DAT_UnitsState::instance.units[unitID].unitType == UT_E_ENGINEER || DAT_UnitsState::instance.units[unitID].unitType == UT_TUNNELER || DAT_UnitsState::instance.units[unitID].unitType == UT_S_CATAPULT + || DAT_UnitsState::instance.units[unitID].unitType == UT_S_TREBUCHET || DAT_UnitsState::instance.units[unitID].unitType == UT_S_MANGONEL || DAT_UnitsState::instance.units[unitID].unitType == UT_S_TOWER + || DAT_UnitsState::instance.units[unitID].unitType == UT_S_BATTERINGRAM || DAT_UnitsState::instance.units[unitID].unitType == UT_S_SHIELD || DAT_UnitsState::instance.units[unitID].unitType == UT_S_BALLISTA + || DAT_UnitsState::instance.units[unitID].unitType == UT_S_FBALLISTA) + continue; + + if (this->aics[aicIndex].DefDiggingUnitMax == 0 || DAT_UnitsState::instance.units[unitID].unitType == UT_E_ARCHER || DAT_UnitsState::instance.units[unitID].unitType == UT_E_XBOW + || DAT_UnitsState::instance.units[unitID].someUnitStat4 == 0) + MACRO_CALL_MEMBER(AICState_Func::assignUnitToATribe, this)(unitID); + else + MACRO_CALL_MEMBER(AICState_Func::aiAddUnitToMoatDiggerTribe, this)(unitID); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index d588ce188..9885b0fb8 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35529,7 +35529,7 @@ SHC_3BB0A8C1_0x004D39F0 | 0.0% | Pending SHC_3BB0A8C1_0x004D3AE0 | 35.8% | Block layout differs -SHC_3BB0A8C1_0x004D3F20 | 0.0% | Pending +SHC_3BB0A8C1_0x004D3F20 | 97.4% | Reimplemented SHC_3BB0A8C1_0x004D4040 | 97.0% | Reimplemented From bf1b58c8b9d932f8741e1ecdff405307db9d4970 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:07:03 +0200 Subject: [PATCH 209/242] reimplement: SHC_3BB0A8C1_0x004CC910 97.06% Reimplemented --- .../AI/AICState/createTribeForUnitType.cpp | 25 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp b/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp index f161e8f1d..4395e208d 100644 --- a/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp +++ b/src/OpenSHC/AI/AICState/createTribeForUnitType.cpp @@ -7,21 +7,20 @@ namespace OpenSHC { namespace AI { - // FUNCTION: STRONGHOLDCRUSADER 0x004CC960 + // FUNCTION: STRONGHOLDCRUSADER 0x004CC910 int AICState::createTribeForUnitType(int playerID, int unitSelectionTypeIndex) { - short* psVar1 = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs + unitSelectionTypeIndex; - int _tribeID = (int)*psVar1; - if ((_tribeID == 0) - || (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex])) { - _tribeID - = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); - int _tribeUID = DAT_TribesState::instance.tribes[_tribeID].uid; - *psVar1 = (short)_tribeID; - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex] = _tribeUID; - } - return _tribeID; + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[unitSelectionTypeIndex]; + if (tribeID != 0 + && DAT_TribesState::instance.tribes[tribeID].uid + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex]) + return tribeID; + + tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[unitSelectionTypeIndex] = tribeID; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[unitSelectionTypeIndex] + = DAT_TribesState::instance.tribes[tribeID].uid; + return tribeID; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9885b0fb8..72e57b7e2 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34885,7 +34885,7 @@ SHC_3BB0A8C1_0x004CC840 | 94.3% | Reimplemented SHC_3BB0A8C1_0x004CC8D0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CC910 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC910 | 97.1% | Reimplemented SHC_3BB0A8C1_0x004CC990 | 40.90% | Reimplemented functionally, different register usage From 12dc75828b2fe66a177cfc32f0d4e73134cf5cee Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:07:04 +0200 Subject: [PATCH 210/242] reimplement: SHC_3BB0A8C1_0x004CCBE0 99.01% Reimplemented --- src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp | 2 +- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp index 5d2c6f9a5..eb72c6142 100644 --- a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp +++ b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp @@ -9,7 +9,7 @@ namespace OpenSHC { namespace AI { - // FUNCTION: STRONGHOLDCRUSADER 0x004CCBF0 + // FUNCTION: STRONGHOLDCRUSADER 0x004CCBE0 int AICState::getDefensiveTribeForUnit(int playerID, int unitID) { int index; diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 72e57b7e2..14a19c5bb 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34891,7 +34891,7 @@ SHC_3BB0A8C1_0x004CC990 | 40.90% | Reimplemented functionally, different registe SHC_3BB0A8C1_0x004CCAF0 | 68.1% | Register allocation differs -SHC_3BB0A8C1_0x004CCBE0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CCBE0 | 99.0% | Reimplemented SHC_3BB0A8C1_0x004CCD20 | 63.9% | Loop register allocation diff From 6ab977c9cfacb3a08b8933cb6153de35c64bc3bb Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:07:04 +0200 Subject: [PATCH 211/242] reimplement: SHC_3BB0A8C1_0x004D2500 94.57% Reimplemented --- .../AICState/aiRecruitEngineerForOilDuty.cpp | 94 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 46 insertions(+), 50 deletions(-) diff --git a/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp index c96ca96b9..8970c828b 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp @@ -1,7 +1,6 @@ -#include "OpenSHC/Global.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" -#include "OpenSHC/AI/AICState.hpp" +#include "OpenSHC/AI/AICState.func.hpp" #include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" @@ -18,56 +17,53 @@ namespace OpenSHC { namespace AI { - // FUNCTION: STRONGHOLDCRUSADER 0x004D2610 + // FUNCTION: STRONGHOLDCRUSADER 0x004D2500 void AICState::aiRecruitEngineerForOilDuty(int playerID) { - BOOLEnum _hasTribes; - int _newTribe; - int _unitID; - int _amount; - int _oilSmelter; - int _buildingUID; - if (((((DAT_GameState::instance.playerDataArray[playerID].aiType != AITA_NULL) - && (_newTribe = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, - DAT_GameState::instance.playerDataArray[playerID].canStartSpending != 0)) - && (29 < DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf])) - && ((0 < _newTribe - && (DAT_BuildingsState::instance.buildings[_newTribe].buildingType - == Map::Buildings::BT_ENGINEERSGUILD)))) - && ((_oilSmelter = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id, - 0 < _oilSmelter - && ((DAT_BuildingsState::instance.buildings[_oilSmelter].buildingType - == Map::Buildings::BT_OILSMELTER - && (_amount - = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1] + 1, - 1 < _amount)))))) { - if ((DAT_BuildingsState::instance.buildings[_oilSmelter].resourcePitch < 1) - && (DAT_GameState::instance.playerDataArray[playerID].currentResources[7] < 1)) { - DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[7] = 4; - return; - } - _hasTribes - = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)(playerID, _amount, TRUE); - if (_hasTribes != FALSE) { - _newTribe = MACRO_CALL(Global_Func::ChecksAndGenerateAITribesForPlayerIfNotExisting)( - playerID, _amount, FALSE); - _unitID = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( - Map::Units::UT_E_ENGINEER, DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, - playerID, 0); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( - _unitID, _newTribe); - if (_unitID != 0) { - DAT_UnitsState::instance.units[_unitID].engineerRelatedUnk = 1; - DAT_TribesState::instance.tribes[_newTribe].unitStance = Map::Units::Behavior::USE_DEFENSIVE; - _buildingUID = DAT_BuildingsState::instance.buildings[_oilSmelter].uid; - DAT_TribesState::instance.tribes[_newTribe].tribeType = Tribes::AITT_ENGINEERS; - DAT_TribesState::instance.tribes[_newTribe].tribeBehaviorType = Map::Units::STBT_0x41d; - MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( - _newTribe, Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, _oilSmelter, - _buildingUID, 0); - } - } + if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL) + return; + int guildID = DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id; + if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) + return; + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] < 30) + return; + if (guildID <= 0) + return; + if (DAT_BuildingsState::instance.buildings[guildID].buildingType != Map::Buildings::BT_ENGINEERSGUILD) + return; + int smelterID = DAT_GameState::instance.playerDataArray[playerID].oilSmelter.id; + if (smelterID <= 0) + return; + if (DAT_BuildingsState::instance.buildings[smelterID].buildingType != Map::Buildings::BT_OILSMELTER) + return; + int amount = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[1] + 1; + if (amount <= 1) + return; + + if (DAT_BuildingsState::instance.buildings[smelterID].resources[Game::Resources::RT_PITCH] <= 0 + && DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_PITCH] <= 0) { + DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[Game::Resources::RT_PITCH] = 4; + return; } + if (MACRO_CALL_MEMBER(AICState_Func::checksAndGenerateAITribesForPlayerIfNotExisting, this)(playerID, amount, TRUE) + == FALSE) + return; + + int tribeID + = MACRO_CALL_MEMBER(AICState_Func::checksAndGenerateAITribesForPlayerIfNotExisting, this)(playerID, amount, FALSE); + int unitID = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( + Map::Units::UT_E_ENGINEER, DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, playerID, 0); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); + if (unitID == 0) + return; + + DAT_UnitsState::instance.units[unitID].engineerRelatedUnk = 1; + DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; + DAT_TribesState::instance.tribes[tribeID].tribeType = Tribes::AITT_ENGINEERS; + DAT_TribesState::instance.tribes[tribeID].tribeBehaviorType = Map::Units::STBT_0x41d; + MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(tribeID, + Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, smelterID, + DAT_BuildingsState::instance.buildings[smelterID].uid, 0); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 14a19c5bb..9b813fbc7 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35485,7 +35485,7 @@ SHC_3BB0A8C1_0x004D2080 | 0.0% | Pending SHC_3BB0A8C1_0x004D20C0 | 0.0% | Pending -SHC_3BB0A8C1_0x004D2500 | 0.0% | Pending +SHC_3BB0A8C1_0x004D2500 | 94.6% | Reimplemented SHC_3BB0A8C1_0x004D2660 | 59.6% | Branch layout differs From 9f75ddac7734d6400d370f00a301edcae868e0f9 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:12:43 +0200 Subject: [PATCH 212/242] reimplement: SHC_3BB0A8C1_0x004CEEA0 100.00% Reimplemented --- status/addresses-SHC-3BB0A8C1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 9b813fbc7..6d2232123 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35345,7 +35345,7 @@ SHC_3BB0A8C1_0x004CEC80 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CED90 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CEEA0 | 100.0% | Pending +SHC_3BB0A8C1_0x004CEEA0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CEFD0 | 100.0% | Reimplemented From 96bc5e747da5cb8f57689e813dd9526686b439d3 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:13:14 +0200 Subject: [PATCH 213/242] reimplement: SHC_3BB0A8C1_0x004CFF60 100.00% Reimplemented --- src/OpenSHC/AI/AICState/yieldCowThrow.cpp | 24 ++++++++++++----------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/OpenSHC/AI/AICState/yieldCowThrow.cpp b/src/OpenSHC/AI/AICState/yieldCowThrow.cpp index 16c993e2f..c381e7b3e 100644 --- a/src/OpenSHC/AI/AICState/yieldCowThrow.cpp +++ b/src/OpenSHC/AI/AICState/yieldCowThrow.cpp @@ -9,17 +9,19 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CFF60 BOOLEnum AICState::yieldCowThrow(int playerID) { - int* _pCounter; - int const _ai = DAT_GameState::instance.playerDataArray[playerID].aiType; - if ((((_ai != AITA_NULL) && (DAT_GameState::instance.mapAndTime.noCowThrowing == 0)) - && (this->aics[_ai - 1].CowThrowInterval != 0)) - && ((0 < DAT_GameState::instance.playerDataArray[playerID].counter - && (_pCounter = &DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter, - *_pCounter = *_pCounter + 1, - (int)this->aics[_ai - 1].CowThrowInterval - < DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter)))) { - DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter = 0; - return TRUE; + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType != AITA_NULL) { + int aicIndex = aiType - 1; + if (DAT_GameState::instance.mapAndTime.skirmishNoCowThrowing == 0 + && this->aics[aicIndex].CowThrowInterval != 0 + && DAT_GameState::instance.playerDataArray[playerID].counter > 0) { + DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter++; + if (DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter + > this->aics[aicIndex].CowThrowInterval) { + DAT_GameState::instance.playerDataArray[playerID].aiCowThrowCounter = 0; + return TRUE; + } + } } return FALSE; } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 6d2232123..c4511c783 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35389,7 +35389,7 @@ SHC_3BB0A8C1_0x004CFBC0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CFCD0 | 56.0% | Unresolved attackInfo offsets -SHC_3BB0A8C1_0x004CFF60 | 0.0% | Pending +SHC_3BB0A8C1_0x004CFF60 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CFFD0 | 100.0% | Reimplemented From 80489327d6e50b71f37a6ab615719dc258fc8504 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:24 +0200 Subject: [PATCH 214/242] reimplement: SHC_3BB0A8C1_0x004C6D60 92.16% Constant store order differs --- .../AI/AICState/setAICParameters_01.cpp | 266 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 134 insertions(+), 134 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_01.cpp b/src/OpenSHC/AI/AICState/setAICParameters_01.cpp index d085d91ae..dc4631bf4 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_01.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_01.cpp @@ -11,140 +11,140 @@ namespace AI { using AIC::AITC_PLAYER; // FUNCTION: STRONGHOLDCRUSADER 0x004C6D60 - void AICState::setAICParameters_01(int aicID) + void AICState::setAICParameters_01(int aicIndex) { - this->aics[aicID].minimumCheese = -1; - this->aics[aicID].minimumBread = -1; - this->aics[aicID].minimumWheat = -1; - this->aics[aicID].minimumHop = -1; - this->aics[aicID].aiRequestDelay = 0x12; - this->aics[aicID].populationPerQuarry = 0x12; - this->aics[aicID].populationPerFarm = 6; - this->aics[aicID].maxWoodcutters = 6; - this->aics[aicID].maxFarms = 6; - this->aics[aicID].flagType = 0xc; - this->aics[aicID].unknown002 = 0; - this->aics[aicID].unknown001 = 0; - this->aics[aicID].unknown003 = 0; - this->aics[aicID].unknown004 = 0; - this->aics[aicID].unknown005 = 0; - this->aics[aicID].criticalPopularity = 4000; - this->aics[aicID].lowestPopularity = 5500; - this->aics[aicID].highestPopularity = 7500; - this->aics[aicID].taxesMin = 3; - this->aics[aicID].taxesMax = 10; - this->aics[aicID].farm1 = 0x20; - this->aics[aicID].unknown011 = 0x14; - this->aics[aicID].maxFood = 100; - this->aics[aicID].minimumApples = 10; - this->aics[aicID].tradeAmountFood = 10; - this->aics[aicID].tradeAmountEquipment = 2; - this->aics[aicID].minimumGoodsRequiredAfterTrade = 0; - this->aics[aicID].doubleRationsFoodThreshold = 0; - this->aics[aicID].maxWood = 0x1e; - this->aics[aicID].maxStone = 0x28; - this->aics[aicID].maxResourceOther = 0x14; - this->aics[aicID].maxEquipment = 0x14; - this->aics[aicID].maxBeer = 0x14; - this->aics[aicID].maxResourceVariance = 5; - this->aics[aicID].recruitGoldThreshold = 200; - this->aics[aicID].populationPerWoodcutter = 8; - this->aics[aicID].populationPerIronmine = 0; - this->aics[aicID].populationPerPitchrig = 0; - this->aics[aicID].maxQuarries = 1; - this->aics[aicID].maxIronmines = 1; - this->aics[aicID].maxPitchrigs = 1; - this->aics[aicID].buildInterval = 1; - this->aics[aicID].resourceRebuildDelay = 10; - this->aics[aicID].blacksmithSetting = 0x16; - this->aics[aicID].fletcherSetting = 0x11; - this->aics[aicID].poleturnerSetting = 0x13; - this->aics[aicID].sellResource02 = 3; - this->aics[aicID].sellResource03 = 6; - this->aics[aicID].sellResource04 = 7; - this->aics[aicID].sellResource05 = 9; - this->aics[aicID].sellResource06 = 0xe; - this->aics[aicID].sellResource07 = 0x10; - this->aics[aicID].sellResource09 = 0x12; - this->aics[aicID].sellResource11 = 0x14; - this->aics[aicID].sellResource12 = 0x15; - this->aics[aicID].sellResource13 = 0x16; - this->aics[aicID].sellResource14 = 0x17; - this->aics[aicID].sellResource15 = 0x18; - this->aics[aicID].defWallPatrolRallyTime = 0x14; - this->aics[aicID].defWallPatrolGroups = 1; - this->aics[aicID].defSiegeEngineGoldThreshold = 200; - this->aics[aicID].defSiegeEngineBuildDelay = 0x14; - this->aics[aicID].unknown072 = 800; - this->aics[aicID].unknown073 = 0x50; - this->aics[aicID].recruitProbDefWeak = 0x32; - this->aics[aicID].RecruitIntervalWeak = 1; - this->aics[aicID].RecruitInterval = 1; - this->aics[aicID].RecruitIntervalStrong = 1; - this->aics[aicID].SortieUnitRanged = 0x16; - this->aics[aicID].SortieUnitMelee = 0x18; - this->aics[aicID].DefDiggingUnit = 0x18; - this->aics[aicID].OuterPatrolGroupsCount = 1; - this->aics[aicID].OuterPatrolRallyDelay = 10; - this->aics[aicID].DefUnit1 = 0x18; - this->aics[aicID].DefUnit2 = 0x18; - this->aics[aicID].DefUnit3 = 0x16; - this->aics[aicID].DefUnit4 = 0x16; - this->aics[aicID].RaidUnitsBase = 10; - this->aics[aicID].RaidUnit1 = 0x18; - this->aics[aicID].RaidUnit2 = 0x18; - this->aics[aicID].RaidUnit3 = 0x16; - this->aics[aicID].recruitProbDefDefault = 0; - this->aics[aicID].recruitProbDefStrong = 0; - this->aics[aicID].recruitProbRaidWeak = 0x32; - this->aics[aicID].recruitProbRaidDefault = 0x32; - this->aics[aicID].recruitProbRaidStrong = 0; - this->aics[aicID].recruitProbAttackWeak = 0; - this->aics[aicID].recruitProbAttackDefault = 0x32; - this->aics[aicID].recruitProbAttackStrong = 100; - this->aics[aicID].SortieUnitRangedMin = 5; - this->aics[aicID].SortieUnitMeleeMin = 6; - this->aics[aicID].DefDiggingUnitMax = 0; - this->aics[aicID].DefWalls = 0x14; - this->aics[aicID].DefTotal = 0x1e; - this->aics[aicID].OuterPatrolGroupsMove = 0; - this->aics[aicID].RaidUnitsRandom = 0xf; - this->aics[aicID].HarassingSiegeEnginesMax = 0; - this->aics[aicID].HarassingSiegeEngine1 = 0xbe; - this->aics[aicID].RaidRetargetDelay = 3; - this->aics[aicID].AttForceBase = 0x14; - this->aics[aicID].AttForceRandom = 10; - this->aics[aicID].AttForceSupportAllyThreshold = 0xf; - this->aics[aicID].AttForceRallyPercentage = 0x32; - this->aics[aicID].AttMovingTribesThreshold = 100; - this->aics[aicID].AttAssaultDelay = 0; - this->aics[aicID].AttUnitPatrolRecommandDelay = 0x19; - this->aics[aicID].AttCoordinationPreference = 0x14; - this->aics[aicID].SiegeEngine1 = 0; - this->aics[aicID].CowThrowInterval = 1000; - this->aics[aicID].AttMaxEngineers = 0; - this->aics[aicID].AttDiggingUnit = 0x18; - this->aics[aicID].AttDiggingUnitMax = 0x14; - this->aics[aicID].AttMaxAssassins = 0; - this->aics[aicID].AttUnit2 = 0x16; - this->aics[aicID].AttUnit2Max = 0; - this->aics[aicID].AttMaxLaddermen = 0; - this->aics[aicID].AttMaxTunnelers = 0; - this->aics[aicID].AttUnitPatrol = 0x16; - this->aics[aicID].AttUnitPatrolMax = 0; - this->aics[aicID].AttUnitPatrolGroupsCount = 0; - this->aics[aicID].AttUnitBackup = 0x16; - this->aics[aicID].AttUnitBackupMax = 0x10; - this->aics[aicID].AttUnitBackupGroupsCount = 0; - this->aics[aicID].AttUnitEngageMax = 0; - this->aics[aicID].AttUnitEngage = 0; - this->aics[aicID].AttUnitSiegeDef = 0x18; - this->aics[aicID].AttUnitSiegeDefMax = 0; - this->aics[aicID].AttUnitSiegeDefGroupsCount = 0; - this->aics[aicID].AttUnitMain1 = 0x18; - this->aics[aicID].AttMaxDefault = 200; - this->aics[aicID].AttMainGroupsCount = 1; - this->aics[aicID].TargetChoice = AITC_PLAYER; + this->aics[aicIndex].minimumCheese = -1; + this->aics[aicIndex].minimumBread = -1; + this->aics[aicIndex].minimumWheat = -1; + this->aics[aicIndex].minimumHop = -1; + this->aics[aicIndex].aiRequestDelay = 0x12; + this->aics[aicIndex].populationPerQuarry = 0x12; + this->aics[aicIndex].populationPerFarm = 6; + this->aics[aicIndex].maxWoodcutters = 6; + this->aics[aicIndex].maxFarms = 6; + this->aics[aicIndex].flagType = 0xc; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 0; + this->aics[aicIndex].unknown005 = 0; + this->aics[aicIndex].criticalPopularity = 4000; + this->aics[aicIndex].lowestPopularity = 5500; + this->aics[aicIndex].highestPopularity = 7500; + this->aics[aicIndex].taxesMin = 3; + this->aics[aicIndex].taxesMax = 10; + this->aics[aicIndex].farm1 = 0x20; + this->aics[aicIndex].unknown011 = 0x14; + this->aics[aicIndex].maxFood = 100; + this->aics[aicIndex].minimumApples = 10; + this->aics[aicIndex].tradeAmountFood = 10; + this->aics[aicIndex].tradeAmountEquipment = 2; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 0; + this->aics[aicIndex].doubleRationsFoodThreshold = 0; + this->aics[aicIndex].maxWood = 0x1e; + this->aics[aicIndex].maxStone = 0x28; + this->aics[aicIndex].maxResourceOther = 0x14; + this->aics[aicIndex].maxEquipment = 0x14; + this->aics[aicIndex].maxBeer = 0x14; + this->aics[aicIndex].maxResourceVariance = 5; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].populationPerWoodcutter = 8; + this->aics[aicIndex].populationPerIronmine = 0; + this->aics[aicIndex].populationPerPitchrig = 0; + this->aics[aicIndex].maxQuarries = 1; + this->aics[aicIndex].maxIronmines = 1; + this->aics[aicIndex].maxPitchrigs = 1; + this->aics[aicIndex].buildInterval = 1; + this->aics[aicIndex].resourceRebuildDelay = 10; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x11; + this->aics[aicIndex].poleturnerSetting = 0x13; + this->aics[aicIndex].sellResource02 = 3; + this->aics[aicIndex].sellResource03 = 6; + this->aics[aicIndex].sellResource04 = 7; + this->aics[aicIndex].sellResource05 = 9; + this->aics[aicIndex].sellResource06 = 0xe; + this->aics[aicIndex].sellResource07 = 0x10; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource13 = 0x16; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].sellResource15 = 0x18; + this->aics[aicIndex].defWallPatrolRallyTime = 0x14; + this->aics[aicIndex].defWallPatrolGroups = 1; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 200; + this->aics[aicIndex].defSiegeEngineBuildDelay = 0x14; + this->aics[aicIndex].unknown072 = 800; + this->aics[aicIndex].unknown073 = 0x50; + this->aics[aicIndex].recruitProbDefWeak = 0x32; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].RecruitInterval = 1; + this->aics[aicIndex].RecruitIntervalStrong = 1; + this->aics[aicIndex].SortieUnitRanged = 0x16; + this->aics[aicIndex].SortieUnitMelee = 0x18; + this->aics[aicIndex].DefDiggingUnit = 0x18; + this->aics[aicIndex].OuterPatrolGroupsCount = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 10; + this->aics[aicIndex].DefUnit1 = 0x18; + this->aics[aicIndex].DefUnit2 = 0x18; + this->aics[aicIndex].DefUnit3 = 0x16; + this->aics[aicIndex].DefUnit4 = 0x16; + this->aics[aicIndex].RaidUnitsBase = 10; + this->aics[aicIndex].RaidUnit1 = 0x18; + this->aics[aicIndex].RaidUnit2 = 0x18; + this->aics[aicIndex].RaidUnit3 = 0x16; + this->aics[aicIndex].recruitProbDefDefault = 0; + this->aics[aicIndex].recruitProbDefStrong = 0; + this->aics[aicIndex].recruitProbRaidWeak = 0x32; + this->aics[aicIndex].recruitProbRaidDefault = 0x32; + this->aics[aicIndex].recruitProbRaidStrong = 0; + this->aics[aicIndex].recruitProbAttackWeak = 0; + this->aics[aicIndex].recruitProbAttackDefault = 0x32; + this->aics[aicIndex].recruitProbAttackStrong = 100; + this->aics[aicIndex].SortieUnitRangedMin = 5; + this->aics[aicIndex].SortieUnitMeleeMin = 6; + this->aics[aicIndex].DefDiggingUnitMax = 0; + this->aics[aicIndex].DefWalls = 0x14; + this->aics[aicIndex].DefTotal = 0x1e; + this->aics[aicIndex].OuterPatrolGroupsMove = 0; + this->aics[aicIndex].RaidUnitsRandom = 0xf; + this->aics[aicIndex].HarassingSiegeEnginesMax = 0; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].RaidRetargetDelay = 3; + this->aics[aicIndex].AttForceBase = 0x14; + this->aics[aicIndex].AttForceRandom = 10; + this->aics[aicIndex].AttForceSupportAllyThreshold = 0xf; + this->aics[aicIndex].AttForceRallyPercentage = 0x32; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 0; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 0x19; + this->aics[aicIndex].AttCoordinationPreference = 0x14; + this->aics[aicIndex].SiegeEngine1 = 0; + this->aics[aicIndex].CowThrowInterval = 1000; + this->aics[aicIndex].AttMaxEngineers = 0; + this->aics[aicIndex].AttDiggingUnit = 0x18; + this->aics[aicIndex].AttDiggingUnitMax = 0x14; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttUnit2 = 0x16; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0x16; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x16; + this->aics[aicIndex].AttUnitBackupMax = 0x10; + this->aics[aicIndex].AttUnitBackupGroupsCount = 0; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0x18; + this->aics[aicIndex].AttUnitSiegeDefMax = 0; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicIndex].AttUnitMain1 = 0x18; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 1; + this->aics[aicIndex].TargetChoice = AITC_PLAYER; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c4511c783..5d24801c3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34157,7 +34157,7 @@ SHC_3BB0A8C1_0x004C6CD0 | 0.0% | Pending SHC_3BB0A8C1_0x004C6D30 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004C6D60 | 0.0% | Pending +SHC_3BB0A8C1_0x004C6D60 | 92.2% | Constant store order differs SHC_3BB0A8C1_0x004C7120 | 0.0% | Pending From 83fbd5f4651ddfe1a5eff811aa957a91b1c72b00 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:25 +0200 Subject: [PATCH 215/242] reimplement: SHC_3BB0A8C1_0x004C7120 83.72% Constant store order differs --- .../AI/AICState/setAICParameters_02.cpp | 262 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 132 insertions(+), 132 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_02.cpp b/src/OpenSHC/AI/AICState/setAICParameters_02.cpp index c3e0c0b69..281539c43 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_02.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_02.cpp @@ -11,138 +11,138 @@ namespace AI { using AIC::AITC_PLAYER; // FUNCTION: STRONGHOLDCRUSADER 0x004C7120 - void AICState::setAICParameters_02(int param_1) + void AICState::setAICParameters_02(int aicIndex) { - this->aics[param_1].minimumBread = 0xffffffff; - this->aics[param_1].minimumWheat = 0xffffffff; - this->aics[param_1].minimumHop = 0xffffffff; - this->aics[param_1].populationPerFarm = 5; - this->aics[param_1].unknown011 = 0xf; - this->aics[param_1].tradeAmountFood = 5; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].maxResourceOther = 0xf; - this->aics[param_1].maxEquipment = 0xc; - this->aics[param_1].maxBeer = 5; - this->aics[param_1].maxResourceVariance = 5; - this->aics[param_1].populationPerWoodcutter = 5; - this->aics[param_1].populationPerQuarry = 0xf; - this->aics[param_1].resourceRebuildDelay = 0xc; - this->aics[param_1].flagType = 0xc; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 0; - this->aics[param_1].unknown005 = 0; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMin = 3; - this->aics[param_1].taxesMax = 0xb; - this->aics[param_1].farm1 = 0x20; - this->aics[param_1].maxFood = 0x96; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumCheese = 0x14; - this->aics[param_1].tradeAmountEquipment = 6; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x50; - this->aics[param_1].maxWood = 0x30; - this->aics[param_1].maxStone = 0x28; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerIronmine = 0; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 2; - this->aics[param_1].maxIronmines = 1; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 10; - this->aics[param_1].buildInterval = 2; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource02 = 3; - this->aics[param_1].sellResource03 = 6; - this->aics[param_1].sellResource04 = 7; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource06 = 0xe; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 4; - this->aics[param_1].defSiegeEngineGoldThreshold = 500; - this->aics[param_1].defSiegeEngineBuildDelay = 0x14; - this->aics[param_1].unknown072 = 400; - this->aics[param_1].unknown073 = 0x3c; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].DefDiggingUnitMax = 0x14; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].RaidUnitsRandom = 10; - this->aics[param_1].recruitProbDefWeak = 0x46; - this->aics[param_1].recruitProbRaidDefault = 0x28; - this->aics[param_1].recruitProbRaidStrong = 0x28; - this->aics[param_1].recruitProbAttackWeak = 0; - this->aics[param_1].recruitProbAttackStrong = 0x28; - this->aics[param_1].RecruitIntervalWeak = 0; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].SortieUnitRangedMin = 2; - this->aics[param_1].SortieUnitMeleeMin = 8; - this->aics[param_1].SortieUnitMelee = 0x18; - this->aics[param_1].DefDiggingUnit = 0x18; - this->aics[param_1].DefWalls = 0x32; - this->aics[param_1].DefTotal = 0x50; - this->aics[param_1].OuterPatrolGroupsCount = 3; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].RaidUnit1 = 0x47; - this->aics[param_1].RaidUnit2 = 0x47; - this->aics[param_1].RaidUnit3 = 0x47; - this->aics[param_1].RaidUnit4 = 0x48; - this->aics[param_1].HarassingSiegeEnginesMax = 1; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].recruitProbDefDefault = 0x1e; - this->aics[param_1].recruitProbRaidWeak = 0x1e; - this->aics[param_1].recruitProbAttackDefault = 0x1e; - this->aics[param_1].RaidUnitsBase = 0x1e; - this->aics[param_1].RaidRetargetDelay = 3; - this->aics[param_1].AttForceBase = 0x1e; - this->aics[param_1].AttForceRandom = 10; - this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; - this->aics[param_1].AttForceRallyPercentage = 0x32; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 0x19; - this->aics[param_1].AttCoordinationPreference = 0x28; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].CowThrowInterval = 1000; - this->aics[param_1].AttMaxEngineers = 2; - this->aics[param_1].AttDiggingUnit = 0x18; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0x16; - this->aics[param_1].AttUnit2Max = 0x14; - this->aics[param_1].AttMaxLaddermen = 10; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0x48; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x46; - this->aics[param_1].AttUnitBackupMax = 0x32; - this->aics[param_1].AttUnitBackupGroupsCount = 1; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0x16; - this->aics[param_1].AttUnitSiegeDefMax = 0x1e; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x18; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 1; - this->aics[param_1].TargetChoice = AITC_BALANCED; + this->aics[aicIndex].minimumBread = 0xffffffff; + this->aics[aicIndex].minimumWheat = 0xffffffff; + this->aics[aicIndex].minimumHop = 0xffffffff; + this->aics[aicIndex].populationPerFarm = 5; + this->aics[aicIndex].unknown011 = 0xf; + this->aics[aicIndex].tradeAmountFood = 5; + this->aics[aicIndex].aiRequestDelay = 0xc; + this->aics[aicIndex].maxResourceOther = 0xf; + this->aics[aicIndex].maxEquipment = 0xc; + this->aics[aicIndex].maxBeer = 5; + this->aics[aicIndex].maxResourceVariance = 5; + this->aics[aicIndex].populationPerWoodcutter = 5; + this->aics[aicIndex].populationPerQuarry = 0xf; + this->aics[aicIndex].resourceRebuildDelay = 0xc; + this->aics[aicIndex].flagType = 0xc; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 0; + this->aics[aicIndex].unknown005 = 0; + this->aics[aicIndex].criticalPopularity = 4000; + this->aics[aicIndex].lowestPopularity = 5000; + this->aics[aicIndex].highestPopularity = 8000; + this->aics[aicIndex].taxesMin = 3; + this->aics[aicIndex].taxesMax = 0xb; + this->aics[aicIndex].farm1 = 0x20; + this->aics[aicIndex].maxFood = 0x96; + this->aics[aicIndex].minimumApples = 10; + this->aics[aicIndex].minimumCheese = 0x14; + this->aics[aicIndex].tradeAmountEquipment = 6; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 10; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x50; + this->aics[aicIndex].maxWood = 0x30; + this->aics[aicIndex].maxStone = 0x28; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].populationPerIronmine = 0; + this->aics[aicIndex].populationPerPitchrig = 0; + this->aics[aicIndex].maxQuarries = 2; + this->aics[aicIndex].maxIronmines = 1; + this->aics[aicIndex].maxWoodcutters = 10; + this->aics[aicIndex].maxPitchrigs = 1; + this->aics[aicIndex].maxFarms = 10; + this->aics[aicIndex].buildInterval = 2; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x11; + this->aics[aicIndex].poleturnerSetting = 0x13; + this->aics[aicIndex].sellResource02 = 3; + this->aics[aicIndex].sellResource03 = 6; + this->aics[aicIndex].sellResource04 = 7; + this->aics[aicIndex].sellResource05 = 9; + this->aics[aicIndex].sellResource06 = 0xe; + this->aics[aicIndex].sellResource07 = 0x10; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource13 = 0x16; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].sellResource15 = 0x18; + this->aics[aicIndex].defWallPatrolRallyTime = 2; + this->aics[aicIndex].defWallPatrolGroups = 4; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 500; + this->aics[aicIndex].defSiegeEngineBuildDelay = 0x14; + this->aics[aicIndex].unknown072 = 400; + this->aics[aicIndex].unknown073 = 0x3c; + this->aics[aicIndex].recruitProbDefStrong = 0x14; + this->aics[aicIndex].SortieUnitRanged = 0x16; + this->aics[aicIndex].DefDiggingUnitMax = 0x14; + this->aics[aicIndex].DefUnit1 = 0x16; + this->aics[aicIndex].RaidUnitsRandom = 10; + this->aics[aicIndex].recruitProbDefWeak = 0x46; + this->aics[aicIndex].recruitProbRaidDefault = 0x28; + this->aics[aicIndex].recruitProbRaidStrong = 0x28; + this->aics[aicIndex].recruitProbAttackWeak = 0; + this->aics[aicIndex].recruitProbAttackStrong = 0x28; + this->aics[aicIndex].RecruitIntervalWeak = 0; + this->aics[aicIndex].RecruitInterval = 1; + this->aics[aicIndex].RecruitIntervalStrong = 1; + this->aics[aicIndex].SortieUnitRangedMin = 2; + this->aics[aicIndex].SortieUnitMeleeMin = 8; + this->aics[aicIndex].SortieUnitMelee = 0x18; + this->aics[aicIndex].DefDiggingUnit = 0x18; + this->aics[aicIndex].DefWalls = 0x32; + this->aics[aicIndex].DefTotal = 0x50; + this->aics[aicIndex].OuterPatrolGroupsCount = 3; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 2; + this->aics[aicIndex].RaidUnit1 = 0x47; + this->aics[aicIndex].RaidUnit2 = 0x47; + this->aics[aicIndex].RaidUnit3 = 0x47; + this->aics[aicIndex].RaidUnit4 = 0x48; + this->aics[aicIndex].HarassingSiegeEnginesMax = 1; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].recruitProbDefDefault = 0x1e; + this->aics[aicIndex].recruitProbRaidWeak = 0x1e; + this->aics[aicIndex].recruitProbAttackDefault = 0x1e; + this->aics[aicIndex].RaidUnitsBase = 0x1e; + this->aics[aicIndex].RaidRetargetDelay = 3; + this->aics[aicIndex].AttForceBase = 0x1e; + this->aics[aicIndex].AttForceRandom = 10; + this->aics[aicIndex].AttForceSupportAllyThreshold = 0x1e; + this->aics[aicIndex].AttForceRallyPercentage = 0x32; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 0; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 0x19; + this->aics[aicIndex].AttCoordinationPreference = 0x28; + this->aics[aicIndex].SiegeEngine1 = 0x27; + this->aics[aicIndex].CowThrowInterval = 1000; + this->aics[aicIndex].AttMaxEngineers = 2; + this->aics[aicIndex].AttDiggingUnit = 0x18; + this->aics[aicIndex].AttDiggingUnitMax = 0x14; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttUnit2 = 0x16; + this->aics[aicIndex].AttUnit2Max = 0x14; + this->aics[aicIndex].AttMaxLaddermen = 10; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0x48; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x46; + this->aics[aicIndex].AttUnitBackupMax = 0x32; + this->aics[aicIndex].AttUnitBackupGroupsCount = 1; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0x16; + this->aics[aicIndex].AttUnitSiegeDefMax = 0x1e; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicIndex].AttUnitMain1 = 0x18; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 1; + this->aics[aicIndex].TargetChoice = AITC_BALANCED; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5d24801c3..1f5481e78 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34159,7 +34159,7 @@ SHC_3BB0A8C1_0x004C6D30 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004C6D60 | 92.2% | Constant store order differs -SHC_3BB0A8C1_0x004C7120 | 0.0% | Pending +SHC_3BB0A8C1_0x004C7120 | 83.7% | Constant store order differs SHC_3BB0A8C1_0x004C7520 | 0.0% | Pending From dc003957a740fb33d217a8d19810dc0b7839079f Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:25 +0200 Subject: [PATCH 216/242] reimplement: SHC_3BB0A8C1_0x004C7520 94.08% Constant store order differs --- .../AI/AICState/setAICParameters_03.cpp | 262 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 132 insertions(+), 132 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_03.cpp b/src/OpenSHC/AI/AICState/setAICParameters_03.cpp index 7f8f963a3..83053911a 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_03.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_03.cpp @@ -11,138 +11,138 @@ namespace AI { using AIC::AITC_PLAYER; // FUNCTION: STRONGHOLDCRUSADER 0x004C7520 - void AICState::setAICParameters_03(int param_1) + void AICState::setAICParameters_03(int aicIndex) { - this->aics[param_1].minimumWheat = -1; - this->aics[param_1].minimumHop = -1; - this->aics[param_1].flagType = 0xc; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 0; - this->aics[param_1].unknown005 = 0; - this->aics[param_1].criticalPopularity = 5000; - this->aics[param_1].lowestPopularity = 7000; - this->aics[param_1].highestPopularity = 0x2134; - this->aics[param_1].taxesMin = 3; - this->aics[param_1].taxesMax = 0xb; - this->aics[param_1].farm1 = 0x21; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 0x14; - this->aics[param_1].maxFood = 400; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumCheese = 10; - this->aics[param_1].minimumBread = 10; - this->aics[param_1].tradeAmountFood = 5; - this->aics[param_1].tradeAmountEquipment = 4; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 100; - this->aics[param_1].doubleRationsFoodThreshold = 0x3c; - this->aics[param_1].maxWood = 0x46; - this->aics[param_1].maxStone = 0x28; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 10; - this->aics[param_1].maxBeer = 5; - this->aics[param_1].maxResourceVariance = 5; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 6; - this->aics[param_1].populationPerQuarry = 0x19; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0x14; - this->aics[param_1].maxQuarries = 2; - this->aics[param_1].maxIronmines = 4; - this->aics[param_1].maxWoodcutters = 8; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 0xc; - this->aics[param_1].buildInterval = 3; - this->aics[param_1].resourceRebuildDelay = 0x32; - this->aics[param_1].blacksmithSetting = 0x15; - this->aics[param_1].fletcherSetting = 0x12; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource02 = 3; - this->aics[param_1].sellResource04 = 7; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource06 = 0xe; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource08 = 0x11; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 10; - this->aics[param_1].defWallPatrolGroups = 4; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 0x14; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x28; - this->aics[param_1].recruitProbDefWeak = 100; - this->aics[param_1].recruitProbDefDefault = 0x3c; - this->aics[param_1].recruitProbDefStrong = 0x1e; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbRaidDefault = 0; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 4; - this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].SortieUnitMeleeMin = 5; - this->aics[param_1].SortieUnitRanged = 0x17; - this->aics[param_1].SortieUnitMelee = 0x1a; - this->aics[param_1].OuterPatrolRallyDelay = 0x14; - this->aics[param_1].RaidUnitsRandom = 5; - this->aics[param_1].recruitProbRaidStrong = 0; - this->aics[param_1].recruitProbAttackWeak = 0; - this->aics[param_1].recruitProbAttackDefault = 0x28; - this->aics[param_1].recruitProbAttackStrong = 0x46; - this->aics[param_1].DefDiggingUnitMax = 0; - this->aics[param_1].DefDiggingUnit = 0x18; - this->aics[param_1].DefWalls = 0x1e; - this->aics[param_1].DefTotal = 0x28; - this->aics[param_1].OuterPatrolGroupsCount = 2; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].RaidUnitsBase = 10; - this->aics[param_1].HarassingSiegeEnginesMax = 2; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RaidRetargetDelay = 3; - this->aics[param_1].AttForceBase = 10; - this->aics[param_1].AttForceRandom = 10; - this->aics[param_1].AttForceSupportAllyThreshold = 10; - this->aics[param_1].AttForceRallyPercentage = 0x3c; - this->aics[param_1].DefUnit1 = 0x17; - this->aics[param_1].DefUnit2 = 0x17; - this->aics[param_1].DefUnit3 = 0x17; - this->aics[param_1].RaidUnit1 = 0x1a; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 5; - this->aics[param_1].AttUnitPatrolRecommandDelay = 0xf; - this->aics[param_1].AttCoordinationPreference = 0x14; - this->aics[param_1].CowThrowInterval = 0x1e; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].SiegeEngine2 = 0x27; - this->aics[param_1].SiegeEngine3 = 0x27; - this->aics[param_1].SiegeEngine4 = 0x3b; - this->aics[param_1].AttMaxEngineers = 10; - this->aics[param_1].AttDiggingUnit = 0x1a; - this->aics[param_1].AttDiggingUnitMax = 10; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x17; - this->aics[param_1].AttUnitBackupMax = 5; - this->aics[param_1].AttUnitBackupGroupsCount = 1; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0x1a; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x1a; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = AITC_GOLD; + this->aics[aicIndex].minimumWheat = -1; + this->aics[aicIndex].minimumHop = -1; + this->aics[aicIndex].flagType = 0xc; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 0; + this->aics[aicIndex].unknown005 = 0; + this->aics[aicIndex].criticalPopularity = 5000; + this->aics[aicIndex].lowestPopularity = 7000; + this->aics[aicIndex].highestPopularity = 0x2134; + this->aics[aicIndex].taxesMin = 3; + this->aics[aicIndex].taxesMax = 0xb; + this->aics[aicIndex].farm1 = 0x21; + this->aics[aicIndex].populationPerFarm = 4; + this->aics[aicIndex].unknown011 = 0x14; + this->aics[aicIndex].maxFood = 400; + this->aics[aicIndex].minimumApples = 10; + this->aics[aicIndex].minimumCheese = 10; + this->aics[aicIndex].minimumBread = 10; + this->aics[aicIndex].tradeAmountFood = 5; + this->aics[aicIndex].tradeAmountEquipment = 4; + this->aics[aicIndex].aiRequestDelay = 0xc; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 100; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x3c; + this->aics[aicIndex].maxWood = 0x46; + this->aics[aicIndex].maxStone = 0x28; + this->aics[aicIndex].maxResourceOther = 10; + this->aics[aicIndex].maxEquipment = 10; + this->aics[aicIndex].maxBeer = 5; + this->aics[aicIndex].maxResourceVariance = 5; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].populationPerWoodcutter = 6; + this->aics[aicIndex].populationPerQuarry = 0x19; + this->aics[aicIndex].populationPerIronmine = 10; + this->aics[aicIndex].populationPerPitchrig = 0x14; + this->aics[aicIndex].maxQuarries = 2; + this->aics[aicIndex].maxIronmines = 4; + this->aics[aicIndex].maxWoodcutters = 8; + this->aics[aicIndex].maxPitchrigs = 1; + this->aics[aicIndex].maxFarms = 0xc; + this->aics[aicIndex].buildInterval = 3; + this->aics[aicIndex].resourceRebuildDelay = 0x32; + this->aics[aicIndex].blacksmithSetting = 0x15; + this->aics[aicIndex].fletcherSetting = 0x12; + this->aics[aicIndex].poleturnerSetting = 0x13; + this->aics[aicIndex].sellResource02 = 3; + this->aics[aicIndex].sellResource04 = 7; + this->aics[aicIndex].sellResource05 = 9; + this->aics[aicIndex].sellResource06 = 0xe; + this->aics[aicIndex].sellResource07 = 0x10; + this->aics[aicIndex].sellResource08 = 0x11; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource13 = 0x16; + this->aics[aicIndex].sellResource15 = 0x18; + this->aics[aicIndex].defWallPatrolRallyTime = 10; + this->aics[aicIndex].defWallPatrolGroups = 4; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 100; + this->aics[aicIndex].defSiegeEngineBuildDelay = 0x14; + this->aics[aicIndex].unknown072 = 200; + this->aics[aicIndex].unknown073 = 0x28; + this->aics[aicIndex].recruitProbDefWeak = 100; + this->aics[aicIndex].recruitProbDefDefault = 0x3c; + this->aics[aicIndex].recruitProbDefStrong = 0x1e; + this->aics[aicIndex].recruitProbRaidWeak = 0; + this->aics[aicIndex].recruitProbRaidDefault = 0; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].RecruitInterval = 1; + this->aics[aicIndex].RecruitIntervalStrong = 4; + this->aics[aicIndex].SortieUnitRangedMin = 4; + this->aics[aicIndex].SortieUnitMeleeMin = 5; + this->aics[aicIndex].SortieUnitRanged = 0x17; + this->aics[aicIndex].SortieUnitMelee = 0x1a; + this->aics[aicIndex].OuterPatrolRallyDelay = 0x14; + this->aics[aicIndex].RaidUnitsRandom = 5; + this->aics[aicIndex].recruitProbRaidStrong = 0; + this->aics[aicIndex].recruitProbAttackWeak = 0; + this->aics[aicIndex].recruitProbAttackDefault = 0x28; + this->aics[aicIndex].recruitProbAttackStrong = 0x46; + this->aics[aicIndex].DefDiggingUnitMax = 0; + this->aics[aicIndex].DefDiggingUnit = 0x18; + this->aics[aicIndex].DefWalls = 0x1e; + this->aics[aicIndex].DefTotal = 0x28; + this->aics[aicIndex].OuterPatrolGroupsCount = 2; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].RaidUnitsBase = 10; + this->aics[aicIndex].HarassingSiegeEnginesMax = 2; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].RaidRetargetDelay = 3; + this->aics[aicIndex].AttForceBase = 10; + this->aics[aicIndex].AttForceRandom = 10; + this->aics[aicIndex].AttForceSupportAllyThreshold = 10; + this->aics[aicIndex].AttForceRallyPercentage = 0x3c; + this->aics[aicIndex].DefUnit1 = 0x17; + this->aics[aicIndex].DefUnit2 = 0x17; + this->aics[aicIndex].DefUnit3 = 0x17; + this->aics[aicIndex].RaidUnit1 = 0x1a; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 5; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 0xf; + this->aics[aicIndex].AttCoordinationPreference = 0x14; + this->aics[aicIndex].CowThrowInterval = 0x1e; + this->aics[aicIndex].SiegeEngine1 = 0x27; + this->aics[aicIndex].SiegeEngine2 = 0x27; + this->aics[aicIndex].SiegeEngine3 = 0x27; + this->aics[aicIndex].SiegeEngine4 = 0x3b; + this->aics[aicIndex].AttMaxEngineers = 10; + this->aics[aicIndex].AttDiggingUnit = 0x1a; + this->aics[aicIndex].AttDiggingUnitMax = 10; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttUnit2 = 0; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x17; + this->aics[aicIndex].AttUnitBackupMax = 5; + this->aics[aicIndex].AttUnitBackupGroupsCount = 1; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0x1a; + this->aics[aicIndex].AttUnitSiegeDefMax = 0; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicIndex].AttUnitMain1 = 0x1a; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 2; + this->aics[aicIndex].TargetChoice = AITC_GOLD; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1f5481e78..b02ec3f2e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34161,7 +34161,7 @@ SHC_3BB0A8C1_0x004C6D60 | 92.2% | Constant store order differs SHC_3BB0A8C1_0x004C7120 | 83.7% | Constant store order differs -SHC_3BB0A8C1_0x004C7520 | 0.0% | Pending +SHC_3BB0A8C1_0x004C7520 | 94.1% | Constant store order differs SHC_3BB0A8C1_0x004C7910 | 0.0% | Pending From 86971553d118339b2f5e7cee4769c3389cdd3fa5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:26 +0200 Subject: [PATCH 217/242] reimplement: SHC_3BB0A8C1_0x004C7910 81.94% Constant store order differs --- .../AI/AICState/setAICParameters_04.cpp | 264 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 133 insertions(+), 133 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_04.cpp b/src/OpenSHC/AI/AICState/setAICParameters_04.cpp index 913127402..f2043fc77 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_04.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_04.cpp @@ -11,139 +11,139 @@ namespace AI { using AIC::AITC_PLAYER; // FUNCTION: STRONGHOLDCRUSADER 0x004C7910 - void AICState::setAICParameters_04(int param_1) + void AICState::setAICParameters_04(int aicIndex) { - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].farm4 = 0x20; - this->aics[param_1].minimumWheat = -1; - this->aics[param_1].minimumHop = -1; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 6000; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 3; - this->aics[param_1].taxesMax = 0xb; - this->aics[param_1].farm1 = 0x21; - this->aics[param_1].farm3 = 0x1f; - this->aics[param_1].populationPerFarm = 5; - this->aics[param_1].unknown011 = 0xc; - this->aics[param_1].maxFood = 200; - this->aics[param_1].minimumApples = 5; - this->aics[param_1].minimumCheese = 5; - this->aics[param_1].minimumBread = 5; - this->aics[param_1].tradeAmountFood = 10; - this->aics[param_1].tradeAmountEquipment = 4; - this->aics[param_1].aiRequestDelay = 0x14; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x28; - this->aics[param_1].doubleRationsFoodThreshold = 0x1e; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x32; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 10; - this->aics[param_1].maxBeer = 0xf; - this->aics[param_1].maxResourceVariance = 5; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 4; - this->aics[param_1].populationPerQuarry = 9; - this->aics[param_1].populationPerIronmine = 0xd; - this->aics[param_1].populationPerPitchrig = 0xf; - this->aics[param_1].maxQuarries = 6; - this->aics[param_1].maxIronmines = 3; - this->aics[param_1].maxWoodcutters = 0xc; - this->aics[param_1].maxPitchrigs = 2; - this->aics[param_1].maxFarms = 10; - this->aics[param_1].buildInterval = 3; - this->aics[param_1].resourceRebuildDelay = 0x14; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x12; - this->aics[param_1].poleturnerSetting = 0x14; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].defWallPatrolRallyTime = 4; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 0xfa; - this->aics[param_1].defSiegeEngineBuildDelay = 2; - this->aics[param_1].unknown072 = 100; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x5a; - this->aics[param_1].recruitProbDefDefault = 0x3c; - this->aics[param_1].recruitProbDefStrong = 0x1e; - this->aics[param_1].recruitProbRaidWeak = 10; - this->aics[param_1].recruitProbRaidDefault = 0x1e; - this->aics[param_1].recruitProbRaidStrong = 10; - this->aics[param_1].recruitProbAttackDefault = 10; - this->aics[param_1].RecruitInterval = 4; - this->aics[param_1].RecruitIntervalStrong = 4; - this->aics[param_1].OuterPatrolGroupsCount = 4; - this->aics[param_1].HarassingSiegeEnginesMax = 4; - this->aics[param_1].recruitProbAttackWeak = 0; - this->aics[param_1].OuterPatrolRallyDelay = 3; - this->aics[param_1].RaidUnitsRandom = 0x14; - this->aics[param_1].recruitProbAttackStrong = 0x3c; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].SortieUnitRangedMin = 8; - this->aics[param_1].SortieUnitRanged = 0x46; - this->aics[param_1].SortieUnitMeleeMin = 6; - this->aics[param_1].SortieUnitMelee = 0x19; - this->aics[param_1].DefDiggingUnitMax = 8; - this->aics[param_1].DefDiggingUnit = 0x19; - this->aics[param_1].DefWalls = 0x50; - this->aics[param_1].DefTotal = 100; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].DefUnit1 = 0x17; - this->aics[param_1].DefUnit2 = 0x17; - this->aics[param_1].DefUnit3 = 0x16; - this->aics[param_1].DefUnit4 = 0x16; - this->aics[param_1].RaidUnitsBase = 5; - this->aics[param_1].RaidUnit1 = 0x4a; - this->aics[param_1].RaidUnit2 = 0x4a; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RaidRetargetDelay = 5; - this->aics[param_1].AttForceBase = 0x28; - this->aics[param_1].AttForceRandom = 0xf; - this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; - this->aics[param_1].AttForceRallyPercentage = 0x50; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0xc; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x32; - this->aics[param_1].CowThrowInterval = 8; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].SiegeEngine2 = 0x28; - this->aics[param_1].SiegeEngine3 = 0x4d; - this->aics[param_1].SiegeEngine4 = 0x28; - this->aics[param_1].AttMaxEngineers = 0xc; - this->aics[param_1].AttDiggingUnit = 0x19; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x17; - this->aics[param_1].AttUnitBackupMax = 0x1e; - this->aics[param_1].AttUnitBackupGroupsCount = 3; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0x1b; - this->aics[param_1].AttUnitSiegeDefMax = 5; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; - this->aics[param_1].AttUnitMain1 = 0x1b; - this->aics[param_1].AttUnitMain2 = 0x19; - this->aics[param_1].AttUnitMain3 = 0x19; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 3; - this->aics[param_1].TargetChoice = AITC_CLOSEST; + this->aics[aicIndex].unknown004 = 1; + this->aics[aicIndex].unknown005 = 1; + this->aics[aicIndex].farm2 = 0x20; + this->aics[aicIndex].farm4 = 0x20; + this->aics[aicIndex].minimumWheat = -1; + this->aics[aicIndex].minimumHop = -1; + this->aics[aicIndex].flagType = 0xd; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].criticalPopularity = 0x1194; + this->aics[aicIndex].lowestPopularity = 6000; + this->aics[aicIndex].highestPopularity = 9000; + this->aics[aicIndex].taxesMin = 3; + this->aics[aicIndex].taxesMax = 0xb; + this->aics[aicIndex].farm1 = 0x21; + this->aics[aicIndex].farm3 = 0x1f; + this->aics[aicIndex].populationPerFarm = 5; + this->aics[aicIndex].unknown011 = 0xc; + this->aics[aicIndex].maxFood = 200; + this->aics[aicIndex].minimumApples = 5; + this->aics[aicIndex].minimumCheese = 5; + this->aics[aicIndex].minimumBread = 5; + this->aics[aicIndex].tradeAmountFood = 10; + this->aics[aicIndex].tradeAmountEquipment = 4; + this->aics[aicIndex].aiRequestDelay = 0x14; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 0x28; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x1e; + this->aics[aicIndex].maxWood = 0x3c; + this->aics[aicIndex].maxStone = 0x32; + this->aics[aicIndex].maxResourceOther = 10; + this->aics[aicIndex].maxEquipment = 10; + this->aics[aicIndex].maxBeer = 0xf; + this->aics[aicIndex].maxResourceVariance = 5; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].populationPerWoodcutter = 4; + this->aics[aicIndex].populationPerQuarry = 9; + this->aics[aicIndex].populationPerIronmine = 0xd; + this->aics[aicIndex].populationPerPitchrig = 0xf; + this->aics[aicIndex].maxQuarries = 6; + this->aics[aicIndex].maxIronmines = 3; + this->aics[aicIndex].maxWoodcutters = 0xc; + this->aics[aicIndex].maxPitchrigs = 2; + this->aics[aicIndex].maxFarms = 10; + this->aics[aicIndex].buildInterval = 3; + this->aics[aicIndex].resourceRebuildDelay = 0x14; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x12; + this->aics[aicIndex].poleturnerSetting = 0x14; + this->aics[aicIndex].sellResource05 = 9; + this->aics[aicIndex].sellResource07 = 0x10; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].defWallPatrolRallyTime = 4; + this->aics[aicIndex].defWallPatrolGroups = 3; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 0xfa; + this->aics[aicIndex].defSiegeEngineBuildDelay = 2; + this->aics[aicIndex].unknown072 = 100; + this->aics[aicIndex].unknown073 = 0x14; + this->aics[aicIndex].recruitProbDefWeak = 0x5a; + this->aics[aicIndex].recruitProbDefDefault = 0x3c; + this->aics[aicIndex].recruitProbDefStrong = 0x1e; + this->aics[aicIndex].recruitProbRaidWeak = 10; + this->aics[aicIndex].recruitProbRaidDefault = 0x1e; + this->aics[aicIndex].recruitProbRaidStrong = 10; + this->aics[aicIndex].recruitProbAttackDefault = 10; + this->aics[aicIndex].RecruitInterval = 4; + this->aics[aicIndex].RecruitIntervalStrong = 4; + this->aics[aicIndex].OuterPatrolGroupsCount = 4; + this->aics[aicIndex].HarassingSiegeEnginesMax = 4; + this->aics[aicIndex].recruitProbAttackWeak = 0; + this->aics[aicIndex].OuterPatrolRallyDelay = 3; + this->aics[aicIndex].RaidUnitsRandom = 0x14; + this->aics[aicIndex].recruitProbAttackStrong = 0x3c; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].SortieUnitRangedMin = 8; + this->aics[aicIndex].SortieUnitRanged = 0x46; + this->aics[aicIndex].SortieUnitMeleeMin = 6; + this->aics[aicIndex].SortieUnitMelee = 0x19; + this->aics[aicIndex].DefDiggingUnitMax = 8; + this->aics[aicIndex].DefDiggingUnit = 0x19; + this->aics[aicIndex].DefWalls = 0x50; + this->aics[aicIndex].DefTotal = 100; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].DefUnit1 = 0x17; + this->aics[aicIndex].DefUnit2 = 0x17; + this->aics[aicIndex].DefUnit3 = 0x16; + this->aics[aicIndex].DefUnit4 = 0x16; + this->aics[aicIndex].RaidUnitsBase = 5; + this->aics[aicIndex].RaidUnit1 = 0x4a; + this->aics[aicIndex].RaidUnit2 = 0x4a; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].RaidRetargetDelay = 5; + this->aics[aicIndex].AttForceBase = 0x28; + this->aics[aicIndex].AttForceRandom = 0xf; + this->aics[aicIndex].AttForceSupportAllyThreshold = 0x1e; + this->aics[aicIndex].AttForceRallyPercentage = 0x50; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 0xc; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 5; + this->aics[aicIndex].AttCoordinationPreference = 0x32; + this->aics[aicIndex].CowThrowInterval = 8; + this->aics[aicIndex].SiegeEngine1 = 0x27; + this->aics[aicIndex].SiegeEngine2 = 0x28; + this->aics[aicIndex].SiegeEngine3 = 0x4d; + this->aics[aicIndex].SiegeEngine4 = 0x28; + this->aics[aicIndex].AttMaxEngineers = 0xc; + this->aics[aicIndex].AttDiggingUnit = 0x19; + this->aics[aicIndex].AttDiggingUnitMax = 0x14; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttUnit2 = 0; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x17; + this->aics[aicIndex].AttUnitBackupMax = 0x1e; + this->aics[aicIndex].AttUnitBackupGroupsCount = 3; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0x1b; + this->aics[aicIndex].AttUnitSiegeDefMax = 5; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 1; + this->aics[aicIndex].AttUnitMain1 = 0x1b; + this->aics[aicIndex].AttUnitMain2 = 0x19; + this->aics[aicIndex].AttUnitMain3 = 0x19; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 3; + this->aics[aicIndex].TargetChoice = AITC_CLOSEST; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b02ec3f2e..975438ff5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34163,7 +34163,7 @@ SHC_3BB0A8C1_0x004C7120 | 83.7% | Constant store order differs SHC_3BB0A8C1_0x004C7520 | 94.1% | Constant store order differs -SHC_3BB0A8C1_0x004C7910 | 0.0% | Pending +SHC_3BB0A8C1_0x004C7910 | 81.9% | Constant store order differs SHC_3BB0A8C1_0x004C7D20 | 0.0% | Pending From 4879caa82ed7e58d0e1b3b1d3277b6f1fad10cee Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:26 +0200 Subject: [PATCH 218/242] reimplement: SHC_3BB0A8C1_0x004C7D20 81.53% Constant store order differs --- .../AI/AICState/setAICParameters_05.cpp | 262 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 132 insertions(+), 132 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_05.cpp b/src/OpenSHC/AI/AICState/setAICParameters_05.cpp index ad9eb85f1..52b7ad888 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_05.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_05.cpp @@ -11,138 +11,138 @@ namespace AI { using AIC::AITC_PLAYER; // FUNCTION: STRONGHOLDCRUSADER 0x004C7D20 - void AICState::setAICParameters_05(int param_1) + void AICState::setAICParameters_05(int aicIndex) { - this->aics[param_1].maxFood = 0x32; - this->aics[param_1].maxStone = 0x32; - this->aics[param_1].taxesMin = 3; - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm2 = 0x1e; - this->aics[param_1].farm3 = 0x1e; - this->aics[param_1].populationPerFarm = 3; - this->aics[param_1].populationPerIronmine = 0xc; - this->aics[param_1].maxQuarries = 4; - this->aics[param_1].maxIronmines = 4; - this->aics[param_1].defWallPatrolGroups = 4; - this->aics[param_1].flagType = 10; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 0; - this->aics[param_1].unknown005 = 0; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].farm1 = 0x1f; - this->aics[param_1].farm4 = 0x20; - this->aics[param_1].unknown011 = 0x14; - this->aics[param_1].minimumApples = 5; - this->aics[param_1].minimumCheese = 5; - this->aics[param_1].minimumBread = 5; - this->aics[param_1].minimumWheat = 5; - this->aics[param_1].minimumHop = 5; - this->aics[param_1].tradeAmountFood = 10; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0x28; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x14; - this->aics[param_1].doubleRationsFoodThreshold = 0x14; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 5; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 2; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 6; - this->aics[param_1].populationPerQuarry = 10; - this->aics[param_1].populationPerPitchrig = 0x14; - this->aics[param_1].maxWoodcutters = 0xe; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 0xf; - this->aics[param_1].buildInterval = 2; - this->aics[param_1].resourceRebuildDelay = 0x28; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x12; - this->aics[param_1].poleturnerSetting = 0x14; - this->aics[param_1].defWallPatrolRallyTime = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 0x14; - this->aics[param_1].defSiegeEngineBuildDelay = 8; - this->aics[param_1].sellResource08 = 0x11; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].unknown072 = 100; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 100; - this->aics[param_1].recruitProbDefDefault = 0x22; - this->aics[param_1].recruitProbDefStrong = 0x19; - this->aics[param_1].RaidUnitsRandom = 5; - this->aics[param_1].HarassingSiegeEnginesMax = 5; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].SortieUnitRangedMin = 10; - this->aics[param_1].SortieUnitMeleeMin = 7; - this->aics[param_1].SortieUnitMelee = 0x4b; - this->aics[param_1].SortieUnitRanged = 0x46; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 10; - this->aics[param_1].RaidUnitsBase = 10; - this->aics[param_1].AttForceRandom = 10; - this->aics[param_1].AttForceBase = 0x32; - this->aics[param_1].AttForceSupportAllyThreshold = 8; - this->aics[param_1].AttForceRallyPercentage = 0x50; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbRaidStrong = 0x19; - this->aics[param_1].recruitProbAttackWeak = 0; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].DefDiggingUnit = 0x47; - this->aics[param_1].DefWalls = 0x32; - this->aics[param_1].OuterPatrolGroupsCount = 2; - this->aics[param_1].DefUnit1 = 0x4b; - this->aics[param_1].DefUnit2 = 0x46; - this->aics[param_1].DefUnit3 = 0x46; - this->aics[param_1].DefUnit4 = 0x46; - this->aics[param_1].DefUnit5 = 0x4c; - this->aics[param_1].RaidUnit1 = 0x4a; - this->aics[param_1].RaidRetargetDelay = 3; - this->aics[param_1].recruitProbRaidDefault = 0x21; - this->aics[param_1].recruitProbAttackDefault = 0x21; - this->aics[param_1].DefTotal = 0x46; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 4; - this->aics[param_1].AttUnitPatrolRecommandDelay = 1; - this->aics[param_1].AttCoordinationPreference = 0x3c; - this->aics[param_1].CowThrowInterval = 2000; - this->aics[param_1].SiegeEngine1 = 0x4d; - this->aics[param_1].SiegeEngine2 = 0x4d; - this->aics[param_1].SiegeEngine3 = 0x27; - this->aics[param_1].SiegeEngine4 = 0x27; - this->aics[param_1].AttMaxEngineers = 10; - this->aics[param_1].AttDiggingUnit = 0x47; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 5; - this->aics[param_1].AttUnit2 = 0x4a; - this->aics[param_1].AttUnit2Max = 0x14; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0x4a; - this->aics[param_1].AttUnitPatrolMax = 0x14; - this->aics[param_1].AttUnitPatrolGroupsCount = 1; - this->aics[param_1].AttUnitBackup = 0x46; - this->aics[param_1].AttUnitBackupMax = 0x14; - this->aics[param_1].AttUnitBackupGroupsCount = 3; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0x4c; - this->aics[param_1].AttUnitSiegeDef = 0x4c; - this->aics[param_1].AttUnitSiegeDefMax = 6; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; - this->aics[param_1].AttUnitMain1 = 0x4b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 3; - this->aics[param_1].TargetChoice = AITC_GOLD; + this->aics[aicIndex].maxFood = 0x32; + this->aics[aicIndex].maxStone = 0x32; + this->aics[aicIndex].taxesMin = 3; + this->aics[aicIndex].taxesMax = 0xc; + this->aics[aicIndex].farm2 = 0x1e; + this->aics[aicIndex].farm3 = 0x1e; + this->aics[aicIndex].populationPerFarm = 3; + this->aics[aicIndex].populationPerIronmine = 0xc; + this->aics[aicIndex].maxQuarries = 4; + this->aics[aicIndex].maxIronmines = 4; + this->aics[aicIndex].defWallPatrolGroups = 4; + this->aics[aicIndex].flagType = 10; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 0; + this->aics[aicIndex].unknown005 = 0; + this->aics[aicIndex].criticalPopularity = 4000; + this->aics[aicIndex].lowestPopularity = 5000; + this->aics[aicIndex].highestPopularity = 8000; + this->aics[aicIndex].farm1 = 0x1f; + this->aics[aicIndex].farm4 = 0x20; + this->aics[aicIndex].unknown011 = 0x14; + this->aics[aicIndex].minimumApples = 5; + this->aics[aicIndex].minimumCheese = 5; + this->aics[aicIndex].minimumBread = 5; + this->aics[aicIndex].minimumWheat = 5; + this->aics[aicIndex].minimumHop = 5; + this->aics[aicIndex].tradeAmountFood = 10; + this->aics[aicIndex].tradeAmountEquipment = 0; + this->aics[aicIndex].aiRequestDelay = 0x28; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 0x14; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x14; + this->aics[aicIndex].maxWood = 0x3c; + this->aics[aicIndex].maxResourceOther = 10; + this->aics[aicIndex].maxEquipment = 5; + this->aics[aicIndex].maxBeer = 10; + this->aics[aicIndex].maxResourceVariance = 2; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].populationPerWoodcutter = 6; + this->aics[aicIndex].populationPerQuarry = 10; + this->aics[aicIndex].populationPerPitchrig = 0x14; + this->aics[aicIndex].maxWoodcutters = 0xe; + this->aics[aicIndex].maxPitchrigs = 1; + this->aics[aicIndex].maxFarms = 0xf; + this->aics[aicIndex].buildInterval = 2; + this->aics[aicIndex].resourceRebuildDelay = 0x28; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x12; + this->aics[aicIndex].poleturnerSetting = 0x14; + this->aics[aicIndex].defWallPatrolRallyTime = 3; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 0x14; + this->aics[aicIndex].defSiegeEngineBuildDelay = 8; + this->aics[aicIndex].sellResource08 = 0x11; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].unknown072 = 100; + this->aics[aicIndex].unknown073 = 0x14; + this->aics[aicIndex].recruitProbDefWeak = 100; + this->aics[aicIndex].recruitProbDefDefault = 0x22; + this->aics[aicIndex].recruitProbDefStrong = 0x19; + this->aics[aicIndex].RaidUnitsRandom = 5; + this->aics[aicIndex].HarassingSiegeEnginesMax = 5; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].RecruitInterval = 1; + this->aics[aicIndex].RecruitIntervalStrong = 1; + this->aics[aicIndex].SortieUnitRangedMin = 10; + this->aics[aicIndex].SortieUnitMeleeMin = 7; + this->aics[aicIndex].SortieUnitMelee = 0x4b; + this->aics[aicIndex].SortieUnitRanged = 0x46; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 10; + this->aics[aicIndex].RaidUnitsBase = 10; + this->aics[aicIndex].AttForceRandom = 10; + this->aics[aicIndex].AttForceBase = 0x32; + this->aics[aicIndex].AttForceSupportAllyThreshold = 8; + this->aics[aicIndex].AttForceRallyPercentage = 0x50; + this->aics[aicIndex].recruitProbRaidWeak = 0; + this->aics[aicIndex].recruitProbRaidStrong = 0x19; + this->aics[aicIndex].recruitProbAttackWeak = 0; + this->aics[aicIndex].recruitProbAttackStrong = 0x32; + this->aics[aicIndex].DefDiggingUnitMax = 4; + this->aics[aicIndex].DefDiggingUnit = 0x47; + this->aics[aicIndex].DefWalls = 0x32; + this->aics[aicIndex].OuterPatrolGroupsCount = 2; + this->aics[aicIndex].DefUnit1 = 0x4b; + this->aics[aicIndex].DefUnit2 = 0x46; + this->aics[aicIndex].DefUnit3 = 0x46; + this->aics[aicIndex].DefUnit4 = 0x46; + this->aics[aicIndex].DefUnit5 = 0x4c; + this->aics[aicIndex].RaidUnit1 = 0x4a; + this->aics[aicIndex].RaidRetargetDelay = 3; + this->aics[aicIndex].recruitProbRaidDefault = 0x21; + this->aics[aicIndex].recruitProbAttackDefault = 0x21; + this->aics[aicIndex].DefTotal = 0x46; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 4; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 1; + this->aics[aicIndex].AttCoordinationPreference = 0x3c; + this->aics[aicIndex].CowThrowInterval = 2000; + this->aics[aicIndex].SiegeEngine1 = 0x4d; + this->aics[aicIndex].SiegeEngine2 = 0x4d; + this->aics[aicIndex].SiegeEngine3 = 0x27; + this->aics[aicIndex].SiegeEngine4 = 0x27; + this->aics[aicIndex].AttMaxEngineers = 10; + this->aics[aicIndex].AttDiggingUnit = 0x47; + this->aics[aicIndex].AttDiggingUnitMax = 0x14; + this->aics[aicIndex].AttMaxAssassins = 5; + this->aics[aicIndex].AttUnit2 = 0x4a; + this->aics[aicIndex].AttUnit2Max = 0x14; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0x4a; + this->aics[aicIndex].AttUnitPatrolMax = 0x14; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 1; + this->aics[aicIndex].AttUnitBackup = 0x46; + this->aics[aicIndex].AttUnitBackupMax = 0x14; + this->aics[aicIndex].AttUnitBackupGroupsCount = 3; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0x4c; + this->aics[aicIndex].AttUnitSiegeDef = 0x4c; + this->aics[aicIndex].AttUnitSiegeDefMax = 6; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 1; + this->aics[aicIndex].AttUnitMain1 = 0x4b; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 3; + this->aics[aicIndex].TargetChoice = AITC_GOLD; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 975438ff5..75fc441c4 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34165,7 +34165,7 @@ SHC_3BB0A8C1_0x004C7520 | 94.1% | Constant store order differs SHC_3BB0A8C1_0x004C7910 | 81.9% | Constant store order differs -SHC_3BB0A8C1_0x004C7D20 | 0.0% | Pending +SHC_3BB0A8C1_0x004C7D20 | 81.5% | Constant store order differs SHC_3BB0A8C1_0x004C8110 | 0.0% | Pending From e374dbaa8c1f6220f70ebeb714fdd9da624f7a86 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:26 +0200 Subject: [PATCH 219/242] reimplement: SHC_3BB0A8C1_0x004C8110 84.28% Constant store order differs --- .../AI/AICState/setAICParameters_06.cpp | 410 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 136 insertions(+), 276 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_06.cpp b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp index 281b9ba61..cd71250b5 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_06.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_06.cpp @@ -7,283 +7,143 @@ namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C8110 - void AICState ::setAICParameters_06(int param_1) - + void AICState::setAICParameters_06(int aicIndex) { - - this->aics[param_1].minimumCheese = -1; - - this->aics[param_1].minimumBread = -1; - - this->aics[param_1].minimumWheat = -1; - - this->aics[param_1].minimumHop = -1; - - this->aics[param_1].taxesMax = 0xc; - - this->aics[param_1].farm1 = 0x20; - - this->aics[param_1].farm3 = 0x20; - - this->aics[param_1].unknown011 = 0xc; - - this->aics[param_1].aiRequestDelay = 0xc; - - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x32; - - this->aics[param_1].doubleRationsFoodThreshold = 0x32; - - this->aics[param_1].maxWood = 0x32; - - this->aics[param_1].maxStone = 0x32; - - this->aics[param_1].populationPerIronmine = 0xc; - - this->aics[param_1].flagType = 10; - - this->aics[param_1].unknown002 = 0; - - this->aics[param_1].unknown001 = 0; - - this->aics[param_1].unknown003 = 0; - - this->aics[param_1].unknown004 = 0; - - this->aics[param_1].unknown005 = 1; - - this->aics[param_1].criticalPopularity = 4000; - - this->aics[param_1].lowestPopularity = 5000; - - this->aics[param_1].highestPopularity = 9000; - - this->aics[param_1].taxesMin = 3; - - this->aics[param_1].farm2 = 0x1f; - - this->aics[param_1].populationPerFarm = 5; - - this->aics[param_1].maxFood = 100; - - this->aics[param_1].minimumApples = 10; - - this->aics[param_1].tradeAmountFood = 10; - - this->aics[param_1].tradeAmountEquipment = 0; - - this->aics[param_1].maxResourceOther = 10; - - this->aics[param_1].maxEquipment = 5; - - this->aics[param_1].maxBeer = 0xf; - - this->aics[param_1].maxResourceVariance = 5; - - this->aics[param_1].recruitGoldThreshold = 200; - - this->aics[param_1].populationPerWoodcutter = 7; - - this->aics[param_1].populationPerQuarry = 10; - - this->aics[param_1].populationPerPitchrig = 7; - - this->aics[param_1].maxQuarries = 2; - - this->aics[param_1].maxIronmines = 1; - - this->aics[param_1].maxWoodcutters = 8; - - this->aics[param_1].maxPitchrigs = 10; - - this->aics[param_1].maxFarms = 10; - - this->aics[param_1].buildInterval = 3; - - this->aics[param_1].resourceRebuildDelay = 0x3c; - - this->aics[param_1].blacksmithSetting = 0x16; - - this->aics[param_1].fletcherSetting = 0x12; - - this->aics[param_1].poleturnerSetting = 0x14; - - this->aics[param_1].defWallPatrolRallyTime = 5; - - this->aics[param_1].defWallPatrolGroups = 2; - - this->aics[param_1].defSiegeEngineGoldThreshold = 0x78; - - this->aics[param_1].defSiegeEngineBuildDelay = 8; - - this->aics[param_1].sellResource03 = 6; - - this->aics[param_1].sellResource05 = 9; - - this->aics[param_1].sellResource07 = 0x10; - - this->aics[param_1].sellResource08 = 0x11; - - this->aics[param_1].sellResource09 = 0x12; - - this->aics[param_1].sellResource10 = 0x13; - - this->aics[param_1].sellResource11 = 0x14; - - this->aics[param_1].sellResource12 = 0x15; - - this->aics[param_1].sellResource13 = 0x16; - - this->aics[param_1].sellResource14 = 0x17; - - this->aics[param_1].sellResource15 = 0x18; - - this->aics[param_1].unknown072 = 100; - - this->aics[param_1].unknown073 = 0x14; - - this->aics[param_1].recruitProbRaidWeak = 0x14; - - this->aics[param_1].recruitProbAttackDefault = 0x14; - - this->aics[param_1].recruitProbAttackWeak = 0; - - this->aics[param_1].RecruitInterval = 0; - - this->aics[param_1].RecruitIntervalStrong = 0; - - this->aics[param_1].SortieUnitRangedMin = 7; - - this->aics[param_1].SortieUnitMeleeMin = 5; - - this->aics[param_1].SortieUnitRanged = 0x46; - - this->aics[param_1].SortieUnitMelee = 0x4b; - - this->aics[param_1].OuterPatrolGroupsCount = 2; - - this->aics[param_1].HarassingSiegeEnginesMax = 2; - - this->aics[param_1].recruitProbDefWeak = 0x50; - - this->aics[param_1].recruitProbDefDefault = 0x28; - - this->aics[param_1].recruitProbDefStrong = 0x28; - - this->aics[param_1].recruitProbRaidDefault = 0x28; - - this->aics[param_1].recruitProbRaidStrong = 0x1e; - - this->aics[param_1].recruitProbAttackStrong = 0x1e; - - this->aics[param_1].RecruitIntervalWeak = 1; - - this->aics[param_1].DefDiggingUnitMax = 4; - - this->aics[param_1].DefDiggingUnit = 0x47; - - this->aics[param_1].DefWalls = 0x3c; - - this->aics[param_1].DefTotal = 0x3c; - - this->aics[param_1].OuterPatrolGroupsMove = 1; - - this->aics[param_1].OuterPatrolRallyDelay = 10; - - this->aics[param_1].DefUnit1 = 0x4c; - - this->aics[param_1].DefUnit2 = 0x46; - - this->aics[param_1].DefUnit3 = 0x46; - - this->aics[param_1].DefUnit4 = 0x46; - - this->aics[param_1].RaidUnitsBase = 0x1e; - - this->aics[param_1].RaidUnitsRandom = 0x1e; - - this->aics[param_1].RaidUnit1 = 0x47; - - this->aics[param_1].HarassingSiegeEngine1 = 0x166; - - this->aics[param_1].HarassingSiegeEngine2 = 0xbe; - - this->aics[param_1].RaidRetargetDelay = 3; - - this->aics[param_1].AttForceBase = 0xf; - - this->aics[param_1].AttForceRandom = 10; - - this->aics[param_1].AttForceSupportAllyThreshold = 0x46; - - this->aics[param_1].AttForceRallyPercentage = 100; - - this->aics[param_1].AttMovingTribesThreshold = 100; - - this->aics[param_1].AttAssaultDelay = 2; - - this->aics[param_1].AttUnitPatrolRecommandDelay = 10; - - this->aics[param_1].AttCoordinationPreference = 0x32; - - this->aics[param_1].CowThrowInterval = 7; - - this->aics[param_1].SiegeEngine1 = 0x4d; - - this->aics[param_1].SiegeEngine2 = 0x4d; - - this->aics[param_1].SiegeEngine3 = 0x4d; - - this->aics[param_1].AttMaxEngineers = 6; - - this->aics[param_1].AttDiggingUnit = 0x47; - - this->aics[param_1].AttDiggingUnitMax = 0x14; - - this->aics[param_1].AttMaxAssassins = 0; - - this->aics[param_1].AttUnit2 = 0x4b; - - this->aics[param_1].AttUnit2Max = 0; - - this->aics[param_1].AttMaxLaddermen = 0; - - this->aics[param_1].AttMaxTunnelers = 0; - - this->aics[param_1].AttUnitPatrol = 0x4a; - - this->aics[param_1].AttUnitPatrolMax = 0; - - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - - this->aics[param_1].AttUnitBackup = 0x4a; - - this->aics[param_1].AttUnitBackupMax = 0x28; - - this->aics[param_1].AttUnitBackupGroupsCount = 2; - - this->aics[param_1].AttUnitEngageMax = 0; - - this->aics[param_1].AttUnitEngage = 0; - - this->aics[param_1].AttUnitSiegeDef = 0x46; - - this->aics[param_1].AttUnitSiegeDefMax = 10; - - this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; - - this->aics[param_1].AttUnitMain1 = 0x4b; - - this->aics[param_1].AttMaxDefault = 200; - - this->aics[param_1].AttMainGroupsCount = 5; - - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; - - return; + this->aics[aicIndex].minimumCheese = -1; + this->aics[aicIndex].minimumBread = -1; + this->aics[aicIndex].minimumWheat = -1; + this->aics[aicIndex].minimumHop = -1; + this->aics[aicIndex].taxesMax = 0xc; + this->aics[aicIndex].farm1 = 0x20; + this->aics[aicIndex].farm3 = 0x20; + this->aics[aicIndex].unknown011 = 0xc; + this->aics[aicIndex].aiRequestDelay = 0xc; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 0x32; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x32; + this->aics[aicIndex].maxWood = 0x32; + this->aics[aicIndex].maxStone = 0x32; + this->aics[aicIndex].populationPerIronmine = 0xc; + this->aics[aicIndex].flagType = 10; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 0; + this->aics[aicIndex].unknown005 = 1; + this->aics[aicIndex].criticalPopularity = 4000; + this->aics[aicIndex].lowestPopularity = 5000; + this->aics[aicIndex].highestPopularity = 9000; + this->aics[aicIndex].taxesMin = 3; + this->aics[aicIndex].farm2 = 0x1f; + this->aics[aicIndex].populationPerFarm = 5; + this->aics[aicIndex].maxFood = 100; + this->aics[aicIndex].minimumApples = 10; + this->aics[aicIndex].tradeAmountFood = 10; + this->aics[aicIndex].tradeAmountEquipment = 0; + this->aics[aicIndex].maxResourceOther = 10; + this->aics[aicIndex].maxEquipment = 5; + this->aics[aicIndex].maxBeer = 0xf; + this->aics[aicIndex].maxResourceVariance = 5; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].populationPerWoodcutter = 7; + this->aics[aicIndex].populationPerQuarry = 10; + this->aics[aicIndex].populationPerPitchrig = 7; + this->aics[aicIndex].maxQuarries = 2; + this->aics[aicIndex].maxIronmines = 1; + this->aics[aicIndex].maxWoodcutters = 8; + this->aics[aicIndex].maxPitchrigs = 10; + this->aics[aicIndex].maxFarms = 10; + this->aics[aicIndex].buildInterval = 3; + this->aics[aicIndex].resourceRebuildDelay = 0x3c; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x12; + this->aics[aicIndex].poleturnerSetting = 0x14; + this->aics[aicIndex].defWallPatrolRallyTime = 5; + this->aics[aicIndex].defWallPatrolGroups = 2; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 0x78; + this->aics[aicIndex].defSiegeEngineBuildDelay = 8; + this->aics[aicIndex].sellResource03 = 6; + this->aics[aicIndex].sellResource05 = 9; + this->aics[aicIndex].sellResource07 = 0x10; + this->aics[aicIndex].sellResource08 = 0x11; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource13 = 0x16; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].sellResource15 = 0x18; + this->aics[aicIndex].unknown072 = 100; + this->aics[aicIndex].unknown073 = 0x14; + this->aics[aicIndex].recruitProbRaidWeak = 0x14; + this->aics[aicIndex].recruitProbAttackDefault = 0x14; + this->aics[aicIndex].recruitProbAttackWeak = 0; + this->aics[aicIndex].RecruitInterval = 0; + this->aics[aicIndex].RecruitIntervalStrong = 0; + this->aics[aicIndex].SortieUnitRangedMin = 7; + this->aics[aicIndex].SortieUnitMeleeMin = 5; + this->aics[aicIndex].SortieUnitRanged = 0x46; + this->aics[aicIndex].SortieUnitMelee = 0x4b; + this->aics[aicIndex].OuterPatrolGroupsCount = 2; + this->aics[aicIndex].HarassingSiegeEnginesMax = 2; + this->aics[aicIndex].recruitProbDefWeak = 0x50; + this->aics[aicIndex].recruitProbDefDefault = 0x28; + this->aics[aicIndex].recruitProbDefStrong = 0x28; + this->aics[aicIndex].recruitProbRaidDefault = 0x28; + this->aics[aicIndex].recruitProbRaidStrong = 0x1e; + this->aics[aicIndex].recruitProbAttackStrong = 0x1e; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].DefDiggingUnitMax = 4; + this->aics[aicIndex].DefDiggingUnit = 0x47; + this->aics[aicIndex].DefWalls = 0x3c; + this->aics[aicIndex].DefTotal = 0x3c; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 10; + this->aics[aicIndex].DefUnit1 = 0x4c; + this->aics[aicIndex].DefUnit2 = 0x46; + this->aics[aicIndex].DefUnit3 = 0x46; + this->aics[aicIndex].DefUnit4 = 0x46; + this->aics[aicIndex].RaidUnitsBase = 0x1e; + this->aics[aicIndex].RaidUnitsRandom = 0x1e; + this->aics[aicIndex].RaidUnit1 = 0x47; + this->aics[aicIndex].HarassingSiegeEngine1 = 0x166; + this->aics[aicIndex].HarassingSiegeEngine2 = 0xbe; + this->aics[aicIndex].RaidRetargetDelay = 3; + this->aics[aicIndex].AttForceBase = 0xf; + this->aics[aicIndex].AttForceRandom = 10; + this->aics[aicIndex].AttForceSupportAllyThreshold = 0x46; + this->aics[aicIndex].AttForceRallyPercentage = 100; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 2; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 10; + this->aics[aicIndex].AttCoordinationPreference = 0x32; + this->aics[aicIndex].CowThrowInterval = 7; + this->aics[aicIndex].SiegeEngine1 = 0x4d; + this->aics[aicIndex].SiegeEngine2 = 0x4d; + this->aics[aicIndex].SiegeEngine3 = 0x4d; + this->aics[aicIndex].AttMaxEngineers = 6; + this->aics[aicIndex].AttDiggingUnit = 0x47; + this->aics[aicIndex].AttDiggingUnitMax = 0x14; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttUnit2 = 0x4b; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0x4a; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x4a; + this->aics[aicIndex].AttUnitBackupMax = 0x28; + this->aics[aicIndex].AttUnitBackupGroupsCount = 2; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0x46; + this->aics[aicIndex].AttUnitSiegeDefMax = 10; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 1; + this->aics[aicIndex].AttUnitMain1 = 0x4b; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 5; + this->aics[aicIndex].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 75fc441c4..1fc112128 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34167,7 +34167,7 @@ SHC_3BB0A8C1_0x004C7910 | 81.9% | Constant store order differs SHC_3BB0A8C1_0x004C7D20 | 81.5% | Constant store order differs -SHC_3BB0A8C1_0x004C8110 | 0.0% | Pending +SHC_3BB0A8C1_0x004C8110 | 84.3% | Constant store order differs SHC_3BB0A8C1_0x004C8530 | 0.0% | Pending From 6da6b1ac6c593c961d264a046968f1d46dc77b2a Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:27 +0200 Subject: [PATCH 220/242] reimplement: SHC_3BB0A8C1_0x004C8530 94.70% Constant store order differs --- .../AI/AICState/setAICParameters_07.cpp | 401 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 133 insertions(+), 270 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp index 7f7a8b4fa..eb1dbdaa2 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_07.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_07.cpp @@ -7,277 +7,140 @@ namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004C8530 - void AICState ::setAICParameters_07(int param_1) - + void AICState::setAICParameters_07(int aicIndex) { - - this->aics[param_1].minimumCheese = -1; - - this->aics[param_1].minimumBread = -1; - - this->aics[param_1].minimumWheat = -1; - - this->aics[param_1].minimumHop = -1; - - this->aics[param_1].flagType = 10; - - this->aics[param_1].unknown002 = 0; - - this->aics[param_1].unknown001 = 0; - - this->aics[param_1].unknown003 = 0; - - this->aics[param_1].unknown004 = 0; - - this->aics[param_1].unknown005 = 0; - - this->aics[param_1].criticalPopularity = 5000; - - this->aics[param_1].lowestPopularity = 6000; - - this->aics[param_1].highestPopularity = 9000; - - this->aics[param_1].taxesMin = 1; - - this->aics[param_1].taxesMax = 8; - - this->aics[param_1].farm1 = 0; - - this->aics[param_1].populationPerFarm = 100; - - this->aics[param_1].unknown011 = 0x14; - - this->aics[param_1].maxFood = 500; - - this->aics[param_1].minimumApples = 0x14; - - this->aics[param_1].tradeAmountFood = 10; - - this->aics[param_1].tradeAmountEquipment = 0; - - this->aics[param_1].aiRequestDelay = 0x1e; - - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0; - - this->aics[param_1].doubleRationsFoodThreshold = 0; - - this->aics[param_1].maxWood = 0x1e; - - this->aics[param_1].maxStone = 0x14; - - this->aics[param_1].maxResourceOther = 10; - - this->aics[param_1].maxEquipment = 5; - - this->aics[param_1].maxBeer = 0x14; - - this->aics[param_1].maxResourceVariance = 5; - - this->aics[param_1].recruitGoldThreshold = 200; - - this->aics[param_1].populationPerWoodcutter = 2; - - this->aics[param_1].populationPerQuarry = 5; - - this->aics[param_1].populationPerIronmine = 0; - - this->aics[param_1].populationPerPitchrig = 0; - - this->aics[param_1].maxQuarries = 2; - - this->aics[param_1].maxIronmines = 1; - - this->aics[param_1].maxWoodcutters = 0xf; - - this->aics[param_1].maxPitchrigs = 1; - - this->aics[param_1].maxFarms = 6; - - this->aics[param_1].buildInterval = 5; - - this->aics[param_1].resourceRebuildDelay = 0x50; - - this->aics[param_1].blacksmithSetting = 0x16; - - this->aics[param_1].fletcherSetting = 0x11; - - this->aics[param_1].poleturnerSetting = 0x13; - - this->aics[param_1].sellResource02 = 3; - - this->aics[param_1].sellResource03 = 6; - - this->aics[param_1].sellResource04 = 7; - - this->aics[param_1].sellResource05 = 9; - - this->aics[param_1].sellResource06 = 0xe; - - this->aics[param_1].sellResource07 = 0x10; - - this->aics[param_1].sellResource08 = 0x11; - - this->aics[param_1].sellResource09 = 0x12; - - this->aics[param_1].sellResource10 = 0x13; - - this->aics[param_1].sellResource11 = 0x14; - - this->aics[param_1].sellResource12 = 0x15; - - this->aics[param_1].sellResource13 = 0x16; - - this->aics[param_1].sellResource14 = 0x17; - - this->aics[param_1].sellResource15 = 0x18; - - this->aics[param_1].defWallPatrolRallyTime = 10; - - this->aics[param_1].defWallPatrolGroups = 2; - - this->aics[param_1].defSiegeEngineGoldThreshold = 200; - - this->aics[param_1].defSiegeEngineBuildDelay = 0x14; - - this->aics[param_1].unknown072 = 800; - - this->aics[param_1].unknown073 = 0x50; - - this->aics[param_1].recruitProbDefStrong = 0x1e; - - this->aics[param_1].recruitProbRaidWeak = 10; - - this->aics[param_1].recruitProbRaidStrong = 0x1e; - - this->aics[param_1].recruitProbAttackDefault = 0x1e; - - this->aics[param_1].DefDiggingUnitMax = 2; - - this->aics[param_1].OuterPatrolGroupsCount = 1; - - this->aics[param_1].OuterPatrolRallyDelay = 10; - - this->aics[param_1].RaidUnitsRandom = 10; - - this->aics[param_1].recruitProbDefWeak = 0x46; - - this->aics[param_1].recruitProbDefDefault = 0x32; - - this->aics[param_1].recruitProbRaidDefault = 0x14; - - this->aics[param_1].recruitProbAttackWeak = 0x14; - - this->aics[param_1].recruitProbAttackStrong = 0x28; - - this->aics[param_1].RecruitIntervalWeak = 8; - - this->aics[param_1].RecruitInterval = 8; - - this->aics[param_1].RecruitIntervalStrong = 4; - - this->aics[param_1].SortieUnitRangedMin = 0; - - this->aics[param_1].SortieUnitRanged = 0x48; - - this->aics[param_1].SortieUnitMeleeMin = 3; - - this->aics[param_1].SortieUnitMelee = 0x4b; - - this->aics[param_1].DefDiggingUnit = 0x47; - - this->aics[param_1].DefWalls = 0x28; - - this->aics[param_1].DefTotal = 0x32; - - this->aics[param_1].OuterPatrolGroupsMove = 0; - - this->aics[param_1].DefUnit1 = 0x48; - - this->aics[param_1].DefUnit2 = 0x48; - - this->aics[param_1].DefUnit3 = 0x4b; - - this->aics[param_1].RaidUnitsBase = 0x14; - - this->aics[param_1].RaidUnit1 = 0x48; - - this->aics[param_1].HarassingSiegeEnginesMax = 0; - - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - - this->aics[param_1].RaidRetargetDelay = 3; - - this->aics[param_1].AttForceBase = 10; - - this->aics[param_1].AttForceRandom = 0x14; - - this->aics[param_1].AttForceSupportAllyThreshold = 5; - - this->aics[param_1].AttForceRallyPercentage = 0x1e; - - this->aics[param_1].AttMovingTribesThreshold = 100; - - this->aics[param_1].AttAssaultDelay = 0; - - this->aics[param_1].AttUnitPatrolRecommandDelay = 0x28; - - this->aics[param_1].AttCoordinationPreference = 0x14; - - this->aics[param_1].CowThrowInterval = 10000; - - this->aics[param_1].SiegeEngine1 = 0; - - this->aics[param_1].AttMaxEngineers = 0; - - this->aics[param_1].AttDiggingUnit = 0; - - this->aics[param_1].AttDiggingUnitMax = 0; - - this->aics[param_1].AttMaxAssassins = 0; - - this->aics[param_1].AttUnit2 = 0; - - this->aics[param_1].AttUnit2Max = 0; - - this->aics[param_1].AttMaxLaddermen = 0; - - this->aics[param_1].AttMaxTunnelers = 0; - - this->aics[param_1].AttUnitPatrol = 0; - - this->aics[param_1].AttUnitPatrolMax = 0; - - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - - this->aics[param_1].AttUnitBackup = 0x46; - - this->aics[param_1].AttUnitBackupMax = 0x78; - - this->aics[param_1].AttUnitBackupGroupsCount = 1; - - this->aics[param_1].AttUnitEngageMax = 0; - - this->aics[param_1].AttUnitEngage = 0; - - this->aics[param_1].AttUnitSiegeDef = 0; - - this->aics[param_1].AttUnitSiegeDefMax = 0; - - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - - this->aics[param_1].AttUnitMain1 = 0x4b; - - this->aics[param_1].AttMaxDefault = 200; - - this->aics[param_1].AttMainGroupsCount = 1; - - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; - - return; + this->aics[aicIndex].minimumCheese = -1; + this->aics[aicIndex].minimumBread = -1; + this->aics[aicIndex].minimumWheat = -1; + this->aics[aicIndex].minimumHop = -1; + this->aics[aicIndex].flagType = 10; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 0; + this->aics[aicIndex].unknown005 = 0; + this->aics[aicIndex].criticalPopularity = 5000; + this->aics[aicIndex].lowestPopularity = 6000; + this->aics[aicIndex].highestPopularity = 9000; + this->aics[aicIndex].taxesMin = 1; + this->aics[aicIndex].taxesMax = 8; + this->aics[aicIndex].farm1 = 0; + this->aics[aicIndex].populationPerFarm = 100; + this->aics[aicIndex].unknown011 = 0x14; + this->aics[aicIndex].maxFood = 500; + this->aics[aicIndex].minimumApples = 0x14; + this->aics[aicIndex].tradeAmountFood = 10; + this->aics[aicIndex].tradeAmountEquipment = 0; + this->aics[aicIndex].aiRequestDelay = 0x1e; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 0; + this->aics[aicIndex].doubleRationsFoodThreshold = 0; + this->aics[aicIndex].maxWood = 0x1e; + this->aics[aicIndex].maxStone = 0x14; + this->aics[aicIndex].maxResourceOther = 10; + this->aics[aicIndex].maxEquipment = 5; + this->aics[aicIndex].maxBeer = 0x14; + this->aics[aicIndex].maxResourceVariance = 5; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].populationPerWoodcutter = 2; + this->aics[aicIndex].populationPerQuarry = 5; + this->aics[aicIndex].populationPerIronmine = 0; + this->aics[aicIndex].populationPerPitchrig = 0; + this->aics[aicIndex].maxQuarries = 2; + this->aics[aicIndex].maxIronmines = 1; + this->aics[aicIndex].maxWoodcutters = 0xf; + this->aics[aicIndex].maxPitchrigs = 1; + this->aics[aicIndex].maxFarms = 6; + this->aics[aicIndex].buildInterval = 5; + this->aics[aicIndex].resourceRebuildDelay = 0x50; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x11; + this->aics[aicIndex].poleturnerSetting = 0x13; + this->aics[aicIndex].sellResource02 = 3; + this->aics[aicIndex].sellResource03 = 6; + this->aics[aicIndex].sellResource04 = 7; + this->aics[aicIndex].sellResource05 = 9; + this->aics[aicIndex].sellResource06 = 0xe; + this->aics[aicIndex].sellResource07 = 0x10; + this->aics[aicIndex].sellResource08 = 0x11; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource13 = 0x16; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].sellResource15 = 0x18; + this->aics[aicIndex].defWallPatrolRallyTime = 10; + this->aics[aicIndex].defWallPatrolGroups = 2; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 200; + this->aics[aicIndex].defSiegeEngineBuildDelay = 0x14; + this->aics[aicIndex].unknown072 = 800; + this->aics[aicIndex].unknown073 = 0x50; + this->aics[aicIndex].recruitProbDefStrong = 0x1e; + this->aics[aicIndex].recruitProbRaidWeak = 10; + this->aics[aicIndex].recruitProbRaidStrong = 0x1e; + this->aics[aicIndex].recruitProbAttackDefault = 0x1e; + this->aics[aicIndex].DefDiggingUnitMax = 2; + this->aics[aicIndex].OuterPatrolGroupsCount = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 10; + this->aics[aicIndex].RaidUnitsRandom = 10; + this->aics[aicIndex].recruitProbDefWeak = 0x46; + this->aics[aicIndex].recruitProbDefDefault = 0x32; + this->aics[aicIndex].recruitProbRaidDefault = 0x14; + this->aics[aicIndex].recruitProbAttackWeak = 0x14; + this->aics[aicIndex].recruitProbAttackStrong = 0x28; + this->aics[aicIndex].RecruitIntervalWeak = 8; + this->aics[aicIndex].RecruitInterval = 8; + this->aics[aicIndex].RecruitIntervalStrong = 4; + this->aics[aicIndex].SortieUnitRangedMin = 0; + this->aics[aicIndex].SortieUnitRanged = 0x48; + this->aics[aicIndex].SortieUnitMeleeMin = 3; + this->aics[aicIndex].SortieUnitMelee = 0x4b; + this->aics[aicIndex].DefDiggingUnit = 0x47; + this->aics[aicIndex].DefWalls = 0x28; + this->aics[aicIndex].DefTotal = 0x32; + this->aics[aicIndex].OuterPatrolGroupsMove = 0; + this->aics[aicIndex].DefUnit1 = 0x48; + this->aics[aicIndex].DefUnit2 = 0x48; + this->aics[aicIndex].DefUnit3 = 0x4b; + this->aics[aicIndex].RaidUnitsBase = 0x14; + this->aics[aicIndex].RaidUnit1 = 0x48; + this->aics[aicIndex].HarassingSiegeEnginesMax = 0; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].RaidRetargetDelay = 3; + this->aics[aicIndex].AttForceBase = 10; + this->aics[aicIndex].AttForceRandom = 0x14; + this->aics[aicIndex].AttForceSupportAllyThreshold = 5; + this->aics[aicIndex].AttForceRallyPercentage = 0x1e; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 0; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 0x28; + this->aics[aicIndex].AttCoordinationPreference = 0x14; + this->aics[aicIndex].CowThrowInterval = 10000; + this->aics[aicIndex].SiegeEngine1 = 0; + this->aics[aicIndex].AttMaxEngineers = 0; + this->aics[aicIndex].AttDiggingUnit = 0; + this->aics[aicIndex].AttDiggingUnitMax = 0; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttUnit2 = 0; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x46; + this->aics[aicIndex].AttUnitBackupMax = 0x78; + this->aics[aicIndex].AttUnitBackupGroupsCount = 1; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0; + this->aics[aicIndex].AttUnitSiegeDefMax = 0; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicIndex].AttUnitMain1 = 0x4b; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 1; + this->aics[aicIndex].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1fc112128..af1bf64ca 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34169,7 +34169,7 @@ SHC_3BB0A8C1_0x004C7D20 | 81.5% | Constant store order differs SHC_3BB0A8C1_0x004C8110 | 84.3% | Constant store order differs -SHC_3BB0A8C1_0x004C8530 | 0.0% | Pending +SHC_3BB0A8C1_0x004C8530 | 94.7% | Constant store order differs SHC_3BB0A8C1_0x004C8920 | 0.0% | Pending From 9621b2c0c36636a12efc8e80b3d602863c62389f Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:27 +0200 Subject: [PATCH 221/242] reimplement: SHC_3BB0A8C1_0x004C8920 87.50% Constant store order differs --- .../AI/AICState/setAICParameters_08.cpp | 273 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 136 insertions(+), 139 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_08.cpp b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp index db18a5d39..020f996a2 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_08.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_08.cpp @@ -6,146 +6,143 @@ namespace OpenSHC { namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004C8920 - void AICState ::setAICParameters_08(int param_1) + void AICState::setAICParameters_08(int aicIndex) { - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].farm3 = 0x20; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].minimumApples = 5; - this->aics[param_1].minimumCheese = 5; - this->aics[param_1].minimumBread = -1; - this->aics[param_1].minimumWheat = -1; - this->aics[param_1].minimumHop = -1; - this->aics[param_1].tradeAmountFood = 5; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown005 = 0; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMin = 3; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].farm1 = 0x21; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 0xc; - this->aics[param_1].maxFood = 200; - this->aics[param_1].tradeAmountEquipment = 2; - this->aics[param_1].aiRequestDelay = 0x16; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxWood = 0x32; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 10; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 10; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 3; - this->aics[param_1].maxIronmines = 4; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxFarms = 0xf; - this->aics[param_1].buildInterval = 4; - this->aics[param_1].resourceRebuildDelay = 0x14; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x14; - this->aics[param_1].sellResource02 = 3; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource06 = 0xe; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].defWallPatrolRallyTime = 8; - this->aics[param_1].defWallPatrolGroups = 4; - this->aics[param_1].defSiegeEngineGoldThreshold = 200; - this->aics[param_1].defSiegeEngineBuildDelay = 2; - this->aics[param_1].unknown072 = 100; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x5a; - this->aics[param_1].recruitProbDefDefault = 0x1e; - this->aics[param_1].recruitProbDefStrong = 10; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].RaidUnitsBase = 10; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbRaidDefault = 0; - this->aics[param_1].recruitProbRaidStrong = 0; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].DefDiggingUnitMax = 0; - this->aics[param_1].DefWalls = 0x14; - this->aics[param_1].OuterPatrolGroupsCount = 2; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].DefUnit2 = 0x16; - this->aics[param_1].RaidUnitsRandom = 4; - this->aics[param_1].RaidUnit1 = 0x16; - this->aics[param_1].HarassingSiegeEnginesMax = 2; - this->aics[param_1].AttForceBase = 0x14; - this->aics[param_1].recruitProbAttackDefault = 0x46; - this->aics[param_1].recruitProbAttackStrong = 0x5a; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].SortieUnitRangedMin = 6; - this->aics[param_1].SortieUnitMeleeMin = 6; - this->aics[param_1].SortieUnitMelee = 0x19; - this->aics[param_1].DefDiggingUnit = 0x19; - this->aics[param_1].DefTotal = 0x28; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 5; - this->aics[param_1].DefUnit3 = 0x19; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RaidRetargetDelay = 5; - this->aics[param_1].AttForceRandom = 5; - this->aics[param_1].AttForceSupportAllyThreshold = 10; - this->aics[param_1].AttForceRallyPercentage = 10; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0x14; - this->aics[param_1].AttUnitPatrolRecommandDelay = 2; - this->aics[param_1].AttCoordinationPreference = 10; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].SiegeEngine2 = 0x27; - this->aics[param_1].SiegeEngine3 = 0x27; - this->aics[param_1].SiegeEngine4 = 0x3b; - this->aics[param_1].SiegeEngine5 = 0x28; - this->aics[param_1].SiegeEngine6 = 0x28; - this->aics[param_1].AttMaxEngineers = 0x10; - this->aics[param_1].AttDiggingUnit = 0x19; - this->aics[param_1].AttDiggingUnitMax = 6; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 3; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x14; - this->aics[param_1].AttUnitBackupGroupsCount = 2; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0x1b; - this->aics[param_1].AttUnitSiegeDefMax = 4; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 2; - this->aics[param_1].AttUnitMain1 = 0x1b; - this->aics[param_1].AttUnitMain2 = 0x19; - this->aics[param_1].AttUnitMain3 = 0x19; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 3; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; + this->aics[aicIndex].farm2 = 0x20; + this->aics[aicIndex].farm3 = 0x20; + this->aics[aicIndex].unknown004 = 1; + this->aics[aicIndex].minimumApples = 5; + this->aics[aicIndex].minimumCheese = 5; + this->aics[aicIndex].minimumBread = -1; + this->aics[aicIndex].minimumWheat = -1; + this->aics[aicIndex].minimumHop = -1; + this->aics[aicIndex].tradeAmountFood = 5; + this->aics[aicIndex].maxPitchrigs = 1; + this->aics[aicIndex].flagType = 0xd; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown005 = 0; + this->aics[aicIndex].criticalPopularity = 4000; + this->aics[aicIndex].lowestPopularity = 5000; + this->aics[aicIndex].highestPopularity = 8000; + this->aics[aicIndex].taxesMin = 3; + this->aics[aicIndex].taxesMax = 10; + this->aics[aicIndex].farm1 = 0x21; + this->aics[aicIndex].populationPerFarm = 4; + this->aics[aicIndex].unknown011 = 0xc; + this->aics[aicIndex].maxFood = 200; + this->aics[aicIndex].tradeAmountEquipment = 2; + this->aics[aicIndex].aiRequestDelay = 0x16; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 10; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x28; + this->aics[aicIndex].maxWood = 0x32; + this->aics[aicIndex].maxStone = 0x3c; + this->aics[aicIndex].maxResourceOther = 10; + this->aics[aicIndex].maxEquipment = 10; + this->aics[aicIndex].maxBeer = 10; + this->aics[aicIndex].maxResourceVariance = 4; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].populationPerWoodcutter = 7; + this->aics[aicIndex].populationPerQuarry = 10; + this->aics[aicIndex].populationPerIronmine = 10; + this->aics[aicIndex].populationPerPitchrig = 0; + this->aics[aicIndex].maxQuarries = 3; + this->aics[aicIndex].maxIronmines = 4; + this->aics[aicIndex].maxWoodcutters = 10; + this->aics[aicIndex].maxFarms = 0xf; + this->aics[aicIndex].buildInterval = 4; + this->aics[aicIndex].resourceRebuildDelay = 0x14; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x11; + this->aics[aicIndex].poleturnerSetting = 0x14; + this->aics[aicIndex].sellResource02 = 3; + this->aics[aicIndex].sellResource05 = 9; + this->aics[aicIndex].sellResource06 = 0xe; + this->aics[aicIndex].sellResource07 = 0x10; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].defWallPatrolRallyTime = 8; + this->aics[aicIndex].defWallPatrolGroups = 4; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 200; + this->aics[aicIndex].defSiegeEngineBuildDelay = 2; + this->aics[aicIndex].unknown072 = 100; + this->aics[aicIndex].unknown073 = 0x14; + this->aics[aicIndex].recruitProbDefWeak = 0x5a; + this->aics[aicIndex].recruitProbDefDefault = 0x1e; + this->aics[aicIndex].recruitProbDefStrong = 10; + this->aics[aicIndex].recruitProbAttackWeak = 10; + this->aics[aicIndex].RaidUnitsBase = 10; + this->aics[aicIndex].recruitProbRaidWeak = 0; + this->aics[aicIndex].recruitProbRaidDefault = 0; + this->aics[aicIndex].recruitProbRaidStrong = 0; + this->aics[aicIndex].SortieUnitRanged = 0x16; + this->aics[aicIndex].DefDiggingUnitMax = 0; + this->aics[aicIndex].DefWalls = 0x14; + this->aics[aicIndex].OuterPatrolGroupsCount = 2; + this->aics[aicIndex].DefUnit1 = 0x16; + this->aics[aicIndex].DefUnit2 = 0x16; + this->aics[aicIndex].RaidUnitsRandom = 4; + this->aics[aicIndex].RaidUnit1 = 0x16; + this->aics[aicIndex].HarassingSiegeEnginesMax = 2; + this->aics[aicIndex].AttForceBase = 0x14; + this->aics[aicIndex].recruitProbAttackDefault = 0x46; + this->aics[aicIndex].recruitProbAttackStrong = 0x5a; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].RecruitInterval = 1; + this->aics[aicIndex].RecruitIntervalStrong = 1; + this->aics[aicIndex].SortieUnitRangedMin = 6; + this->aics[aicIndex].SortieUnitMeleeMin = 6; + this->aics[aicIndex].SortieUnitMelee = 0x19; + this->aics[aicIndex].DefDiggingUnit = 0x19; + this->aics[aicIndex].DefTotal = 0x28; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 5; + this->aics[aicIndex].DefUnit3 = 0x19; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].RaidRetargetDelay = 5; + this->aics[aicIndex].AttForceRandom = 5; + this->aics[aicIndex].AttForceSupportAllyThreshold = 10; + this->aics[aicIndex].AttForceRallyPercentage = 10; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 0x14; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 2; + this->aics[aicIndex].AttCoordinationPreference = 10; + this->aics[aicIndex].CowThrowInterval = 10000; + this->aics[aicIndex].SiegeEngine1 = 0x27; + this->aics[aicIndex].SiegeEngine2 = 0x27; + this->aics[aicIndex].SiegeEngine3 = 0x27; + this->aics[aicIndex].SiegeEngine4 = 0x3b; + this->aics[aicIndex].SiegeEngine5 = 0x28; + this->aics[aicIndex].SiegeEngine6 = 0x28; + this->aics[aicIndex].AttMaxEngineers = 0x10; + this->aics[aicIndex].AttDiggingUnit = 0x19; + this->aics[aicIndex].AttDiggingUnitMax = 6; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttUnit2 = 0; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 3; + this->aics[aicIndex].AttUnitPatrol = 0; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x16; + this->aics[aicIndex].AttUnitBackupMax = 0x14; + this->aics[aicIndex].AttUnitBackupGroupsCount = 2; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0x1b; + this->aics[aicIndex].AttUnitSiegeDefMax = 4; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 2; + this->aics[aicIndex].AttUnitMain1 = 0x1b; + this->aics[aicIndex].AttUnitMain2 = 0x19; + this->aics[aicIndex].AttUnitMain3 = 0x19; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 3; + this->aics[aicIndex].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index af1bf64ca..b15da19b5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34171,7 +34171,7 @@ SHC_3BB0A8C1_0x004C8110 | 84.3% | Constant store order differs SHC_3BB0A8C1_0x004C8530 | 94.7% | Constant store order differs -SHC_3BB0A8C1_0x004C8920 | 0.0% | Pending +SHC_3BB0A8C1_0x004C8920 | 87.5% | Constant store order differs SHC_3BB0A8C1_0x004C8D20 | 0.0% | Pending From c22af97311b0f1242ef567149fdab2d2042b6a27 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:28 +0200 Subject: [PATCH 222/242] reimplement: SHC_3BB0A8C1_0x004C8D20 90.38% Constant store order differs --- .../AI/AICState/setAICParameters_09.cpp | 267 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 133 insertions(+), 136 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_09.cpp b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp index 1bc8d92f8..3c462c06b 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_09.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_09.cpp @@ -6,143 +6,140 @@ namespace OpenSHC { namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004C8D20 - void AICState ::setAICParameters_09(int param_1) + void AICState::setAICParameters_09(int aicIndex) { - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].minimumApples = 5; - this->aics[param_1].minimumCheese = 5; - this->aics[param_1].minimumBread = -1; - this->aics[param_1].minimumWheat = -1; - this->aics[param_1].minimumHop = -1; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 0x157c; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 3; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].farm1 = 0x21; - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].farm3 = 0x1f; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 0xc; - this->aics[param_1].maxFood = 200; - this->aics[param_1].tradeAmountFood = 10; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0x16; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxResourceOther = 0xf; - this->aics[param_1].maxEquipment = 0x14; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 0xc; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 4; - this->aics[param_1].maxIronmines = 5; - this->aics[param_1].maxWoodcutters = 0xc; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 0xc; - this->aics[param_1].buildInterval = 4; - this->aics[param_1].resourceRebuildDelay = 0x1e; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = -999; - this->aics[param_1].poleturnerSetting = 0x14; - this->aics[param_1].sellResource04 = 7; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].defWallPatrolRallyTime = 8; - this->aics[param_1].defWallPatrolGroups = 2; - this->aics[param_1].defSiegeEngineGoldThreshold = 200; - this->aics[param_1].defSiegeEngineBuildDelay = 2; - this->aics[param_1].unknown072 = 100; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 100; - this->aics[param_1].recruitProbDefDefault = 0x32; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].AttForceSupportAllyThreshold = 0x14; - this->aics[param_1].RecruitInterval = 4; - this->aics[param_1].RecruitIntervalStrong = 4; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].SortieUnitMeleeMin = 4; - this->aics[param_1].DefDiggingUnitMax = 10; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].OuterPatrolRallyDelay = 10; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].DefUnit2 = 0x16; - this->aics[param_1].RaidUnitsBase = 4; - this->aics[param_1].AttForceRandom = 4; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackWeak = 0; - this->aics[param_1].recruitProbAttackDefault = 0x1e; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].SortieUnitRangedMin = 0xc; - this->aics[param_1].SortieUnitMelee = 0x1b; - this->aics[param_1].DefWalls = 0x32; - this->aics[param_1].DefTotal = 0x50; - this->aics[param_1].OuterPatrolGroupsCount = 2; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].DefUnit3 = 0x17; - this->aics[param_1].RaidUnitsRandom = 0; - this->aics[param_1].RaidUnit1 = 0x1c; - this->aics[param_1].HarassingSiegeEnginesMax = 2; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RaidRetargetDelay = 6; - this->aics[param_1].AttForceBase = 0x1e; - this->aics[param_1].AttForceRallyPercentage = 0x32; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0x14; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x32; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x28; - this->aics[param_1].SiegeEngine2 = 0x28; - this->aics[param_1].SiegeEngine3 = 0x28; - this->aics[param_1].SiegeEngine4 = 0x28; - this->aics[param_1].SiegeEngine5 = 0x28; - this->aics[param_1].SiegeEngine6 = 0x28; - this->aics[param_1].AttMaxEngineers = 0x12; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0x17; - this->aics[param_1].AttUnitPatrolMax = 0x14; - this->aics[param_1].AttUnitPatrolGroupsCount = 1; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x1e; - this->aics[param_1].AttUnitBackupGroupsCount = 2; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0x17; - this->aics[param_1].AttUnitSiegeDefMax = 10; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; - this->aics[param_1].AttUnitMain1 = 0x1b; - this->aics[param_1].AttUnitMain2 = 0x1b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 4; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; + this->aics[aicIndex].unknown004 = 1; + this->aics[aicIndex].unknown005 = 1; + this->aics[aicIndex].minimumApples = 5; + this->aics[aicIndex].minimumCheese = 5; + this->aics[aicIndex].minimumBread = -1; + this->aics[aicIndex].minimumWheat = -1; + this->aics[aicIndex].minimumHop = -1; + this->aics[aicIndex].maxWood = 0x3c; + this->aics[aicIndex].maxStone = 0x3c; + this->aics[aicIndex].flagType = 0xd; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].criticalPopularity = 4000; + this->aics[aicIndex].lowestPopularity = 0x157c; + this->aics[aicIndex].highestPopularity = 9000; + this->aics[aicIndex].taxesMin = 3; + this->aics[aicIndex].taxesMax = 10; + this->aics[aicIndex].farm1 = 0x21; + this->aics[aicIndex].farm2 = 0x20; + this->aics[aicIndex].farm3 = 0x1f; + this->aics[aicIndex].populationPerFarm = 4; + this->aics[aicIndex].unknown011 = 0xc; + this->aics[aicIndex].maxFood = 200; + this->aics[aicIndex].tradeAmountFood = 10; + this->aics[aicIndex].tradeAmountEquipment = 0; + this->aics[aicIndex].aiRequestDelay = 0x16; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 10; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x28; + this->aics[aicIndex].maxResourceOther = 0xf; + this->aics[aicIndex].maxEquipment = 0x14; + this->aics[aicIndex].maxBeer = 10; + this->aics[aicIndex].maxResourceVariance = 4; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].populationPerWoodcutter = 7; + this->aics[aicIndex].populationPerQuarry = 0xc; + this->aics[aicIndex].populationPerIronmine = 10; + this->aics[aicIndex].populationPerPitchrig = 0; + this->aics[aicIndex].maxQuarries = 4; + this->aics[aicIndex].maxIronmines = 5; + this->aics[aicIndex].maxWoodcutters = 0xc; + this->aics[aicIndex].maxPitchrigs = 1; + this->aics[aicIndex].maxFarms = 0xc; + this->aics[aicIndex].buildInterval = 4; + this->aics[aicIndex].resourceRebuildDelay = 0x1e; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = -999; + this->aics[aicIndex].poleturnerSetting = 0x14; + this->aics[aicIndex].sellResource04 = 7; + this->aics[aicIndex].sellResource05 = 9; + this->aics[aicIndex].sellResource07 = 0x10; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].defWallPatrolRallyTime = 8; + this->aics[aicIndex].defWallPatrolGroups = 2; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 200; + this->aics[aicIndex].defSiegeEngineBuildDelay = 2; + this->aics[aicIndex].unknown072 = 100; + this->aics[aicIndex].unknown073 = 0x14; + this->aics[aicIndex].recruitProbDefWeak = 100; + this->aics[aicIndex].recruitProbDefDefault = 0x32; + this->aics[aicIndex].recruitProbDefStrong = 0x14; + this->aics[aicIndex].recruitProbRaidWeak = 0; + this->aics[aicIndex].recruitProbRaidDefault = 0x14; + this->aics[aicIndex].AttForceSupportAllyThreshold = 0x14; + this->aics[aicIndex].RecruitInterval = 4; + this->aics[aicIndex].RecruitIntervalStrong = 4; + this->aics[aicIndex].SortieUnitRanged = 0x16; + this->aics[aicIndex].SortieUnitMeleeMin = 4; + this->aics[aicIndex].DefDiggingUnitMax = 10; + this->aics[aicIndex].DefDiggingUnit = 0x16; + this->aics[aicIndex].OuterPatrolRallyDelay = 10; + this->aics[aicIndex].DefUnit1 = 0x16; + this->aics[aicIndex].DefUnit2 = 0x16; + this->aics[aicIndex].RaidUnitsBase = 4; + this->aics[aicIndex].AttForceRandom = 4; + this->aics[aicIndex].recruitProbRaidStrong = 0x1e; + this->aics[aicIndex].recruitProbAttackWeak = 0; + this->aics[aicIndex].recruitProbAttackDefault = 0x1e; + this->aics[aicIndex].recruitProbAttackStrong = 0x32; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].SortieUnitRangedMin = 0xc; + this->aics[aicIndex].SortieUnitMelee = 0x1b; + this->aics[aicIndex].DefWalls = 0x32; + this->aics[aicIndex].DefTotal = 0x50; + this->aics[aicIndex].OuterPatrolGroupsCount = 2; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].DefUnit3 = 0x17; + this->aics[aicIndex].RaidUnitsRandom = 0; + this->aics[aicIndex].RaidUnit1 = 0x1c; + this->aics[aicIndex].HarassingSiegeEnginesMax = 2; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].RaidRetargetDelay = 6; + this->aics[aicIndex].AttForceBase = 0x1e; + this->aics[aicIndex].AttForceRallyPercentage = 0x32; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 0x14; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 5; + this->aics[aicIndex].AttCoordinationPreference = 0x32; + this->aics[aicIndex].CowThrowInterval = 10000; + this->aics[aicIndex].SiegeEngine1 = 0x28; + this->aics[aicIndex].SiegeEngine2 = 0x28; + this->aics[aicIndex].SiegeEngine3 = 0x28; + this->aics[aicIndex].SiegeEngine4 = 0x28; + this->aics[aicIndex].SiegeEngine5 = 0x28; + this->aics[aicIndex].SiegeEngine6 = 0x28; + this->aics[aicIndex].AttMaxEngineers = 0x12; + this->aics[aicIndex].AttDiggingUnit = 0x16; + this->aics[aicIndex].AttDiggingUnitMax = 0x14; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttUnit2 = 0; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0x17; + this->aics[aicIndex].AttUnitPatrolMax = 0x14; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 1; + this->aics[aicIndex].AttUnitBackup = 0x16; + this->aics[aicIndex].AttUnitBackupMax = 0x1e; + this->aics[aicIndex].AttUnitBackupGroupsCount = 2; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0x17; + this->aics[aicIndex].AttUnitSiegeDefMax = 10; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 1; + this->aics[aicIndex].AttUnitMain1 = 0x1b; + this->aics[aicIndex].AttUnitMain2 = 0x1b; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 4; + this->aics[aicIndex].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b15da19b5..b35ec462b 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34173,7 +34173,7 @@ SHC_3BB0A8C1_0x004C8530 | 94.7% | Constant store order differs SHC_3BB0A8C1_0x004C8920 | 87.5% | Constant store order differs -SHC_3BB0A8C1_0x004C8D20 | 0.0% | Pending +SHC_3BB0A8C1_0x004C8D20 | 90.4% | Constant store order differs SHC_3BB0A8C1_0x004C9120 | 0.0% | Pending From 620fbe492c27dcdc0df8bed8c5c3f23788e6a0c6 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:28 +0200 Subject: [PATCH 223/242] reimplement: SHC_3BB0A8C1_0x004C9120 80.00% Constant store order differs --- .../AI/AICState/setAICParameters_10.cpp | 270 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 135 insertions(+), 137 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp index 8a11823fe..c730d59b1 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp @@ -1,148 +1,146 @@ #include "../AICState.func.hpp" - #include "OpenSHC/AI/AIC/AITargetChoice.hpp" + namespace OpenSHC { namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004C9120 - void AICState ::setAICParameters_10(int param_1) + void AICState::setAICParameters_10(int aicIndex) { - this->aics[param_1].taxesMin = 2; - this->aics[param_1].farm1 = 0x20; - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].tradeAmountEquipment = 2; - this->aics[param_1].minimumWheat = -1; - this->aics[param_1].minimumHop = -1; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].resourceRebuildDelay = 0x3c; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].populationPerFarm = 5; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumCheese = 10; - this->aics[param_1].minimumBread = 10; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x32; - this->aics[param_1].maxResourceOther = 0xf; - this->aics[param_1].maxEquipment = 6; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 0; - this->aics[param_1].populationPerIronmine = 7; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 1; - this->aics[param_1].maxIronmines = 3; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 8; - this->aics[param_1].buildInterval = 4; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource02 = 3; - this->aics[param_1].sellResource04 = 7; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource06 = 0xe; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x46; - this->aics[param_1].recruitProbDefDefault = 0x28; - this->aics[param_1].RecruitIntervalWeak = 4; - this->aics[param_1].RecruitInterval = 4; - this->aics[param_1].RecruitIntervalStrong = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].DefWalls = 4; - this->aics[param_1].OuterPatrolGroupsCount = 4; - this->aics[param_1].RaidUnitsBase = 4; - this->aics[param_1].RaidUnitsRandom = 4; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x14; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].recruitProbAttackDefault = 0x14; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].SortieUnitMeleeMin = 0x14; - this->aics[param_1].DefTotal = 0x14; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].DefUnit2 = 0x16; - this->aics[param_1].DefUnit3 = 0x16; - this->aics[param_1].DefUnit4 = 0x16; - this->aics[param_1].DefUnit5 = 0x16; - this->aics[param_1].DefUnit6 = 0x16; - this->aics[param_1].HarassingSiegeEnginesMax = 1; - this->aics[param_1].recruitProbRaidDefault = 0x28; - this->aics[param_1].recruitProbAttackStrong = 0x3c; - this->aics[param_1].SortieUnitRangedMin = 2; - this->aics[param_1].SortieUnitMelee = 0x18; - this->aics[param_1].DefDiggingUnit = 0x18; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x1c; - this->aics[param_1].RaidUnit1 = 0x1c; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].AttForceBase = 10; - this->aics[param_1].AttForceRandom = 0x14; - this->aics[param_1].AttForceSupportAllyThreshold = 0x28; - this->aics[param_1].AttForceRallyPercentage = 0x28; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x46; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0; - this->aics[param_1].AttMaxEngineers = 0; - this->aics[param_1].AttDiggingUnit = 0x18; - this->aics[param_1].AttDiggingUnitMax = 0x3c; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0x18; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0; - this->aics[param_1].AttUnitBackupMax = 0; - this->aics[param_1].AttUnitBackupGroupsCount = 0; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x18; - this->aics[param_1].AttUnitMain2 = 0x18; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; - return; + this->aics[aicIndex].flagType = 0xd; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 1; + this->aics[aicIndex].unknown005 = 1; + this->aics[aicIndex].criticalPopularity = 4000; + this->aics[aicIndex].lowestPopularity = 5000; + this->aics[aicIndex].highestPopularity = 8000; + this->aics[aicIndex].taxesMin = 2; + this->aics[aicIndex].taxesMax = 10; + this->aics[aicIndex].unknown011 = 10; + this->aics[aicIndex].farm1 = 0x20; + this->aics[aicIndex].farm2 = 0x20; + this->aics[aicIndex].populationPerFarm = 5; + this->aics[aicIndex].populationPerWoodcutter = 7; + this->aics[aicIndex].populationPerQuarry = 0; + this->aics[aicIndex].populationPerIronmine = 7; + this->aics[aicIndex].populationPerPitchrig = 0; + this->aics[aicIndex].maxQuarries = 1; + this->aics[aicIndex].maxIronmines = 3; + this->aics[aicIndex].maxWoodcutters = 10; + this->aics[aicIndex].maxPitchrigs = 1; + this->aics[aicIndex].maxFarms = 8; + this->aics[aicIndex].buildInterval = 4; + this->aics[aicIndex].resourceRebuildDelay = 0x3c; + this->aics[aicIndex].maxFood = 100; + this->aics[aicIndex].minimumApples = 10; + this->aics[aicIndex].minimumCheese = 10; + this->aics[aicIndex].minimumBread = 10; + this->aics[aicIndex].minimumWheat = -1; + this->aics[aicIndex].minimumHop = -1; + this->aics[aicIndex].tradeAmountFood = 0x14; + this->aics[aicIndex].tradeAmountEquipment = 2; + this->aics[aicIndex].aiRequestDelay = 0xc; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 10; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x32; + this->aics[aicIndex].maxWood = 0x3c; + this->aics[aicIndex].maxStone = 0x3c; + this->aics[aicIndex].maxResourceOther = 0xf; + this->aics[aicIndex].maxEquipment = 6; + this->aics[aicIndex].maxBeer = 10; + this->aics[aicIndex].maxResourceVariance = 4; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x11; + this->aics[aicIndex].poleturnerSetting = 0x13; + this->aics[aicIndex].sellResource02 = 3; + this->aics[aicIndex].sellResource04 = 7; + this->aics[aicIndex].sellResource05 = 9; + this->aics[aicIndex].sellResource06 = 0xe; + this->aics[aicIndex].sellResource07 = 0x10; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].defWallPatrolRallyTime = 2; + this->aics[aicIndex].defWallPatrolGroups = 3; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 100; + this->aics[aicIndex].defSiegeEngineBuildDelay = 4; + this->aics[aicIndex].unknown072 = 200; + this->aics[aicIndex].unknown073 = 0x14; + this->aics[aicIndex].recruitProbDefDefault = 0x28; + this->aics[aicIndex].recruitProbDefWeak = 0x46; + this->aics[aicIndex].recruitProbDefStrong = 0x14; + this->aics[aicIndex].recruitProbRaidDefault = 0x28; + this->aics[aicIndex].recruitProbRaidWeak = 0x14; + this->aics[aicIndex].recruitProbRaidStrong = 0x14; + this->aics[aicIndex].recruitProbAttackDefault = 0x14; + this->aics[aicIndex].recruitProbAttackWeak = 10; + this->aics[aicIndex].recruitProbAttackStrong = 0x3c; + this->aics[aicIndex].SortieUnitRangedMin = 2; + this->aics[aicIndex].SortieUnitRanged = 0x16; + this->aics[aicIndex].SortieUnitMeleeMin = 0x14; + this->aics[aicIndex].SortieUnitMelee = 0x18; + this->aics[aicIndex].DefDiggingUnitMax = 4; + this->aics[aicIndex].DefDiggingUnit = 0x18; + this->aics[aicIndex].RecruitInterval = 4; + this->aics[aicIndex].RecruitIntervalWeak = 4; + this->aics[aicIndex].RecruitIntervalStrong = 4; + this->aics[aicIndex].DefTotal = 0x14; + this->aics[aicIndex].OuterPatrolGroupsCount = 4; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 2; + this->aics[aicIndex].DefWalls = 4; + this->aics[aicIndex].DefUnit1 = 0x1c; + this->aics[aicIndex].DefUnit2 = 0x16; + this->aics[aicIndex].DefUnit3 = 0x16; + this->aics[aicIndex].DefUnit4 = 0x16; + this->aics[aicIndex].DefUnit5 = 0x16; + this->aics[aicIndex].DefUnit6 = 0x16; + this->aics[aicIndex].RaidUnitsBase = 4; + this->aics[aicIndex].RaidUnitsRandom = 4; + this->aics[aicIndex].RaidUnit1 = 0x1c; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].HarassingSiegeEnginesMax = 1; + this->aics[aicIndex].RaidRetargetDelay = 4; + this->aics[aicIndex].AttForceBase = 10; + this->aics[aicIndex].AttForceRandom = 0x14; + this->aics[aicIndex].AttForceSupportAllyThreshold = 0x28; + this->aics[aicIndex].AttForceRallyPercentage = 0x28; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 0; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 5; + this->aics[aicIndex].AttCoordinationPreference = 0x46; + this->aics[aicIndex].SiegeEngine1 = 0; + this->aics[aicIndex].CowThrowInterval = 10000; + this->aics[aicIndex].AttMaxEngineers = 0; + this->aics[aicIndex].AttDiggingUnit = 0x18; + this->aics[aicIndex].AttDiggingUnitMax = 0x3c; + this->aics[aicIndex].AttUnit2 = 0; + this->aics[aicIndex].AttUnit2Max = 0x18; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0; + this->aics[aicIndex].AttUnitBackupMax = 0; + this->aics[aicIndex].AttUnitBackupGroupsCount = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0; + this->aics[aicIndex].AttUnitSiegeDefMax = 0; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicIndex].AttUnitMain1 = 0x18; + this->aics[aicIndex].AttUnitMain2 = 0x18; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 2; + this->aics[aicIndex].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; } + } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b35ec462b..6f14a6c71 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34175,7 +34175,7 @@ SHC_3BB0A8C1_0x004C8920 | 87.5% | Constant store order differs SHC_3BB0A8C1_0x004C8D20 | 90.4% | Constant store order differs -SHC_3BB0A8C1_0x004C9120 | 0.0% | Pending +SHC_3BB0A8C1_0x004C9120 | 80.0% | Constant store order differs SHC_3BB0A8C1_0x004C94F0 | 0.0% | Pending From c14c5155c63fc99dd707c2bae21b7f3209e8b415 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:28 +0200 Subject: [PATCH 224/242] reimplement: SHC_3BB0A8C1_0x004C94F0 89.54% Constant store order differs --- .../AI/AICState/setAICParameters_11.cpp | 265 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 132 insertions(+), 135 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_11.cpp b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp index 3eda72d0b..36c716dd8 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_11.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_11.cpp @@ -6,142 +6,139 @@ namespace OpenSHC { namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004C94F0 - void AICState ::setAICParameters_11(int param_1) + void AICState::setAICParameters_11(int aicIndex) { - this->aics[param_1].taxesMin = 2; - this->aics[param_1].minimumApples = -1; - this->aics[param_1].minimumCheese = -1; - this->aics[param_1].minimumBread = -1; - this->aics[param_1].minimumWheat = 2; - this->aics[param_1].minimumHop = -1; - this->aics[param_1].flagType = 10; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm1 = 0x1e; - this->aics[param_1].populationPerFarm = 5; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0x16; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x1e; - this->aics[param_1].doubleRationsFoodThreshold = 0x32; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x28; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 100; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 6; - this->aics[param_1].populationPerIronmine = 0xc; - this->aics[param_1].populationPerPitchrig = 6; - this->aics[param_1].maxQuarries = 3; - this->aics[param_1].maxIronmines = 1; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 4; - this->aics[param_1].maxFarms = 8; - this->aics[param_1].buildInterval = 3; - this->aics[param_1].resourceRebuildDelay = 0x32; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource02 = 3; - this->aics[param_1].sellResource03 = 6; - this->aics[param_1].sellResource06 = 0xe; - this->aics[param_1].sellResource08 = 0x11; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x46; - this->aics[param_1].recruitProbDefDefault = 0x1e; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x14; - this->aics[param_1].recruitProbAttackWeak = 0x1e; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].DefDiggingUnit = 0x47; - this->aics[param_1].RaidUnitsBase = 0x1e; - this->aics[param_1].HarassingSiegeEnginesMax = 4; - this->aics[param_1].HarassingSiegeEngine1 = 0x166; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].SortieUnitMeleeMin = 10; - this->aics[param_1].SortieUnitRangedMin = 6; - this->aics[param_1].SortieUnitMelee = 0x4b; - this->aics[param_1].SortieUnitRanged = 0x4a; - this->aics[param_1].RaidUnitsRandom = 10; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbAttackDefault = 0x32; - this->aics[param_1].recruitProbAttackStrong = 0x3c; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].DefWalls = 0x28; - this->aics[param_1].DefTotal = 0x28; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x46; - this->aics[param_1].DefUnit2 = 0x4c; - this->aics[param_1].AttForceBase = 0x28; - this->aics[param_1].AttForceRandom = 5; - this->aics[param_1].RaidUnit1 = 0x4a; - this->aics[param_1].AttForceSupportAllyThreshold = 0x1e; - this->aics[param_1].AttForceRallyPercentage = 0x50; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 4; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x5a; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x28; - this->aics[param_1].SiegeEngine2 = 0x4d; - this->aics[param_1].SiegeEngine3 = 0x4d; - this->aics[param_1].SiegeEngine4 = 0x4d; - this->aics[param_1].AttMaxEngineers = 9; - this->aics[param_1].AttDiggingUnit = 0x47; - this->aics[param_1].AttDiggingUnitMax = 0xf; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x4a; - this->aics[param_1].AttUnitBackupMax = 0x50; - this->aics[param_1].AttUnitBackupGroupsCount = 1; - this->aics[param_1].AttUnitEngageMax = 10; - this->aics[param_1].AttUnitEngage = 0x4c; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x4b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + this->aics[aicIndex].taxesMin = 2; + this->aics[aicIndex].minimumApples = -1; + this->aics[aicIndex].minimumCheese = -1; + this->aics[aicIndex].minimumBread = -1; + this->aics[aicIndex].minimumWheat = 2; + this->aics[aicIndex].minimumHop = -1; + this->aics[aicIndex].flagType = 10; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 1; + this->aics[aicIndex].unknown005 = 1; + this->aics[aicIndex].criticalPopularity = 0x1194; + this->aics[aicIndex].lowestPopularity = 5000; + this->aics[aicIndex].highestPopularity = 8000; + this->aics[aicIndex].taxesMax = 0xc; + this->aics[aicIndex].farm1 = 0x1e; + this->aics[aicIndex].populationPerFarm = 5; + this->aics[aicIndex].unknown011 = 10; + this->aics[aicIndex].maxFood = 100; + this->aics[aicIndex].tradeAmountFood = 0x14; + this->aics[aicIndex].tradeAmountEquipment = 0; + this->aics[aicIndex].aiRequestDelay = 0x16; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 0x1e; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x32; + this->aics[aicIndex].maxWood = 0x3c; + this->aics[aicIndex].maxStone = 0x28; + this->aics[aicIndex].maxResourceOther = 10; + this->aics[aicIndex].maxEquipment = 4; + this->aics[aicIndex].maxBeer = 10; + this->aics[aicIndex].maxResourceVariance = 4; + this->aics[aicIndex].recruitGoldThreshold = 100; + this->aics[aicIndex].populationPerWoodcutter = 7; + this->aics[aicIndex].populationPerQuarry = 6; + this->aics[aicIndex].populationPerIronmine = 0xc; + this->aics[aicIndex].populationPerPitchrig = 6; + this->aics[aicIndex].maxQuarries = 3; + this->aics[aicIndex].maxIronmines = 1; + this->aics[aicIndex].maxWoodcutters = 10; + this->aics[aicIndex].maxPitchrigs = 4; + this->aics[aicIndex].maxFarms = 8; + this->aics[aicIndex].buildInterval = 3; + this->aics[aicIndex].resourceRebuildDelay = 0x32; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x11; + this->aics[aicIndex].poleturnerSetting = 0x13; + this->aics[aicIndex].sellResource02 = 3; + this->aics[aicIndex].sellResource03 = 6; + this->aics[aicIndex].sellResource06 = 0xe; + this->aics[aicIndex].sellResource08 = 0x11; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource13 = 0x16; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].sellResource15 = 0x18; + this->aics[aicIndex].defWallPatrolRallyTime = 2; + this->aics[aicIndex].defWallPatrolGroups = 3; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 100; + this->aics[aicIndex].defSiegeEngineBuildDelay = 4; + this->aics[aicIndex].unknown072 = 200; + this->aics[aicIndex].unknown073 = 0x14; + this->aics[aicIndex].recruitProbDefWeak = 0x46; + this->aics[aicIndex].recruitProbDefDefault = 0x1e; + this->aics[aicIndex].recruitProbDefStrong = 0x14; + this->aics[aicIndex].recruitProbRaidDefault = 0x14; + this->aics[aicIndex].recruitProbRaidStrong = 0x14; + this->aics[aicIndex].recruitProbAttackWeak = 0x1e; + this->aics[aicIndex].DefDiggingUnitMax = 4; + this->aics[aicIndex].DefDiggingUnit = 0x47; + this->aics[aicIndex].RaidUnitsBase = 0x1e; + this->aics[aicIndex].HarassingSiegeEnginesMax = 4; + this->aics[aicIndex].HarassingSiegeEngine1 = 0x166; + this->aics[aicIndex].RaidRetargetDelay = 4; + this->aics[aicIndex].SortieUnitMeleeMin = 10; + this->aics[aicIndex].SortieUnitRangedMin = 6; + this->aics[aicIndex].SortieUnitMelee = 0x4b; + this->aics[aicIndex].SortieUnitRanged = 0x4a; + this->aics[aicIndex].RaidUnitsRandom = 10; + this->aics[aicIndex].recruitProbRaidWeak = 0; + this->aics[aicIndex].recruitProbAttackDefault = 0x32; + this->aics[aicIndex].recruitProbAttackStrong = 0x3c; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].RecruitInterval = 1; + this->aics[aicIndex].RecruitIntervalStrong = 1; + this->aics[aicIndex].DefWalls = 0x28; + this->aics[aicIndex].DefTotal = 0x28; + this->aics[aicIndex].OuterPatrolGroupsCount = 1; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 2; + this->aics[aicIndex].DefUnit1 = 0x46; + this->aics[aicIndex].DefUnit2 = 0x4c; + this->aics[aicIndex].AttForceBase = 0x28; + this->aics[aicIndex].AttForceRandom = 5; + this->aics[aicIndex].RaidUnit1 = 0x4a; + this->aics[aicIndex].AttForceSupportAllyThreshold = 0x1e; + this->aics[aicIndex].AttForceRallyPercentage = 0x50; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 4; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 5; + this->aics[aicIndex].AttCoordinationPreference = 0x5a; + this->aics[aicIndex].CowThrowInterval = 10000; + this->aics[aicIndex].SiegeEngine1 = 0x28; + this->aics[aicIndex].SiegeEngine2 = 0x4d; + this->aics[aicIndex].SiegeEngine3 = 0x4d; + this->aics[aicIndex].SiegeEngine4 = 0x4d; + this->aics[aicIndex].AttMaxEngineers = 9; + this->aics[aicIndex].AttDiggingUnit = 0x47; + this->aics[aicIndex].AttDiggingUnitMax = 0xf; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttUnit2 = 0; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x4a; + this->aics[aicIndex].AttUnitBackupMax = 0x50; + this->aics[aicIndex].AttUnitBackupGroupsCount = 1; + this->aics[aicIndex].AttUnitEngageMax = 10; + this->aics[aicIndex].AttUnitEngage = 0x4c; + this->aics[aicIndex].AttUnitSiegeDef = 0; + this->aics[aicIndex].AttUnitSiegeDefMax = 0; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicIndex].AttUnitMain1 = 0x4b; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 2; + this->aics[aicIndex].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 6f14a6c71..a6f01db1e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34177,7 +34177,7 @@ SHC_3BB0A8C1_0x004C8D20 | 90.4% | Constant store order differs SHC_3BB0A8C1_0x004C9120 | 80.0% | Constant store order differs -SHC_3BB0A8C1_0x004C94F0 | 0.0% | Pending +SHC_3BB0A8C1_0x004C94F0 | 89.5% | Constant store order differs SHC_3BB0A8C1_0x004C9900 | 0.0% | Pending From 6c01e8b59ceea9ba65c61d032b9b09e7828433dc Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:29 +0200 Subject: [PATCH 225/242] reimplement: SHC_3BB0A8C1_0x004C9900 84.21% Constant store order differs --- .../AI/AICState/setAICParameters_12.cpp | 267 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 133 insertions(+), 136 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp index f0de63e84..b76e2fd60 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp @@ -1,5 +1,4 @@ #include "../AICState.func.hpp" - #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { @@ -7,142 +6,140 @@ namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004C9900 - void AICState ::setAICParameters_12(int param_1) + void AICState::setAICParameters_12(int aicIndex) { - this->aics[param_1].farm1 = 0x1e; - this->aics[param_1].farm3 = 0x1e; - this->aics[param_1].minimumCheese = -1; - this->aics[param_1].minimumBread = -1; - this->aics[param_1].flagType = 10; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm2 = 0x20; - this->aics[param_1].farm4 = 0x1f; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 0x50; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumWheat = 2; - this->aics[param_1].minimumHop = 2; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x3c; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 6; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 4; - this->aics[param_1].maxIronmines = 3; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 0x10; - this->aics[param_1].buildInterval = 2; - this->aics[param_1].resourceRebuildDelay = 0x28; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x50; - this->aics[param_1].recruitProbDefDefault = 0x28; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 10; - this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].SortieUnitMeleeMin = 0x14; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].RaidUnitsRandom = 10; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackDefault = 0x28; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitInterval = 0; - this->aics[param_1].RecruitIntervalStrong = 0; - this->aics[param_1].SortieUnitRanged = 0x46; - this->aics[param_1].SortieUnitMelee = 0x4b; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].DefWalls = 0x32; - this->aics[param_1].DefTotal = 0x32; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].DefUnit2 = 0x46; - this->aics[param_1].RaidUnitsBase = 0x1e; - this->aics[param_1].RaidUnit1 = 0x4b; - this->aics[param_1].HarassingSiegeEnginesMax = 3; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].HarassingSiegeEngine2 = 0xbe; - this->aics[param_1].HarassingSiegeEngine3 = 0x166; - this->aics[param_1].AttForceBase = 0x1e; - this->aics[param_1].AttForceRandom = 10; - this->aics[param_1].AttForceSupportAllyThreshold = 0x14; - this->aics[param_1].AttForceRallyPercentage = 0x50; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x50; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].SiegeEngine2 = 0x27; - this->aics[param_1].SiegeEngine3 = 0x3d; - this->aics[param_1].AttMaxEngineers = 6; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 0xf; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x4a; - this->aics[param_1].AttUnitBackupMax = 0x50; - this->aics[param_1].AttUnitBackupGroupsCount = 1; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x4b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; - return; + this->aics[aicIndex].flagType = 10; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 1; + this->aics[aicIndex].unknown005 = 1; + this->aics[aicIndex].criticalPopularity = 0x1194; + this->aics[aicIndex].lowestPopularity = 5000; + this->aics[aicIndex].highestPopularity = 9000; + this->aics[aicIndex].taxesMin = 2; + this->aics[aicIndex].taxesMax = 0xc; + this->aics[aicIndex].unknown011 = 10; + this->aics[aicIndex].farm1 = 0x1e; + this->aics[aicIndex].farm2 = 0x20; + this->aics[aicIndex].farm3 = 0x1e; + this->aics[aicIndex].farm4 = 0x1f; + this->aics[aicIndex].populationPerFarm = 4; + this->aics[aicIndex].populationPerWoodcutter = 7; + this->aics[aicIndex].populationPerQuarry = 6; + this->aics[aicIndex].populationPerIronmine = 10; + this->aics[aicIndex].populationPerPitchrig = 0; + this->aics[aicIndex].maxQuarries = 4; + this->aics[aicIndex].maxIronmines = 3; + this->aics[aicIndex].maxWoodcutters = 10; + this->aics[aicIndex].maxPitchrigs = 1; + this->aics[aicIndex].maxFarms = 0x10; + this->aics[aicIndex].buildInterval = 2; + this->aics[aicIndex].resourceRebuildDelay = 0x28; + this->aics[aicIndex].maxFood = 0x50; + this->aics[aicIndex].minimumApples = 10; + this->aics[aicIndex].minimumCheese = -1; + this->aics[aicIndex].minimumBread = -1; + this->aics[aicIndex].minimumWheat = 2; + this->aics[aicIndex].minimumHop = 2; + this->aics[aicIndex].tradeAmountFood = 0x14; + this->aics[aicIndex].tradeAmountEquipment = 0; + this->aics[aicIndex].aiRequestDelay = 0xc; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 10; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x28; + this->aics[aicIndex].maxWood = 0x3c; + this->aics[aicIndex].maxStone = 0x3c; + this->aics[aicIndex].maxResourceOther = 10; + this->aics[aicIndex].maxEquipment = 4; + this->aics[aicIndex].maxBeer = 10; + this->aics[aicIndex].maxResourceVariance = 4; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x11; + this->aics[aicIndex].poleturnerSetting = 0x13; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource13 = 0x16; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].sellResource15 = 0x18; + this->aics[aicIndex].defWallPatrolRallyTime = 2; + this->aics[aicIndex].defWallPatrolGroups = 3; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 100; + this->aics[aicIndex].defSiegeEngineBuildDelay = 4; + this->aics[aicIndex].unknown072 = 200; + this->aics[aicIndex].unknown073 = 0x14; + this->aics[aicIndex].recruitProbDefDefault = 0x28; + this->aics[aicIndex].recruitProbDefWeak = 0x50; + this->aics[aicIndex].recruitProbDefStrong = 0x14; + this->aics[aicIndex].recruitProbRaidDefault = 0x14; + this->aics[aicIndex].recruitProbRaidWeak = 10; + this->aics[aicIndex].recruitProbRaidStrong = 0x1e; + this->aics[aicIndex].recruitProbAttackDefault = 0x28; + this->aics[aicIndex].recruitProbAttackWeak = 10; + this->aics[aicIndex].recruitProbAttackStrong = 0x32; + this->aics[aicIndex].SortieUnitRangedMin = 4; + this->aics[aicIndex].SortieUnitRanged = 0x46; + this->aics[aicIndex].SortieUnitMeleeMin = 0x14; + this->aics[aicIndex].SortieUnitMelee = 0x4b; + this->aics[aicIndex].DefDiggingUnitMax = 4; + this->aics[aicIndex].DefDiggingUnit = 0x16; + this->aics[aicIndex].RecruitInterval = 0; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].RecruitIntervalStrong = 0; + this->aics[aicIndex].DefTotal = 0x32; + this->aics[aicIndex].OuterPatrolGroupsCount = 1; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 2; + this->aics[aicIndex].DefWalls = 0x32; + this->aics[aicIndex].DefUnit1 = 0x16; + this->aics[aicIndex].DefUnit2 = 0x46; + this->aics[aicIndex].RaidUnitsBase = 0x1e; + this->aics[aicIndex].RaidUnitsRandom = 10; + this->aics[aicIndex].RaidUnit1 = 0x4b; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].HarassingSiegeEngine2 = 0xbe; + this->aics[aicIndex].HarassingSiegeEngine3 = 0x166; + this->aics[aicIndex].HarassingSiegeEnginesMax = 3; + this->aics[aicIndex].RaidRetargetDelay = 4; + this->aics[aicIndex].AttForceBase = 0x1e; + this->aics[aicIndex].AttForceRandom = 10; + this->aics[aicIndex].AttForceSupportAllyThreshold = 0x14; + this->aics[aicIndex].AttForceRallyPercentage = 0x50; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 0; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 5; + this->aics[aicIndex].AttCoordinationPreference = 0x50; + this->aics[aicIndex].SiegeEngine1 = 0x27; + this->aics[aicIndex].SiegeEngine2 = 0x27; + this->aics[aicIndex].SiegeEngine3 = 0x3d; + this->aics[aicIndex].CowThrowInterval = 10000; + this->aics[aicIndex].AttMaxEngineers = 6; + this->aics[aicIndex].AttDiggingUnit = 0x16; + this->aics[aicIndex].AttDiggingUnitMax = 0xf; + this->aics[aicIndex].AttUnit2 = 0; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x4a; + this->aics[aicIndex].AttUnitBackupMax = 0x50; + this->aics[aicIndex].AttUnitBackupGroupsCount = 1; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0; + this->aics[aicIndex].AttUnitSiegeDefMax = 0; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicIndex].AttUnitMain1 = 0x4b; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 2; + this->aics[aicIndex].TargetChoice = OpenSHC::AI::AIC::AITC_GOLD; } + } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a6f01db1e..7033ba778 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34179,7 +34179,7 @@ SHC_3BB0A8C1_0x004C9120 | 80.0% | Constant store order differs SHC_3BB0A8C1_0x004C94F0 | 89.5% | Constant store order differs -SHC_3BB0A8C1_0x004C9900 | 0.0% | Pending +SHC_3BB0A8C1_0x004C9900 | 84.2% | Constant store order differs SHC_3BB0A8C1_0x004C9CF0 | 0.0% | Pending From 983d6d102b4115b95a5a6684ca4187d519435430 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:29 +0200 Subject: [PATCH 226/242] reimplement: SHC_3BB0A8C1_0x004C9CF0 83.33% Constant store order differs --- .../AI/AICState/setAICParameters_13.cpp | 259 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 129 insertions(+), 132 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_13.cpp b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp index 1be44ae3b..c4318fa1f 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_13.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_13.cpp @@ -6,139 +6,136 @@ namespace OpenSHC { namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004C9CF0 - void AICState ::setAICParameters_13(int param_1) + void AICState::setAICParameters_13(int aicIndex) { - this->aics[param_1].minimumCheese = -1; - this->aics[param_1].minimumBread = -1; - this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumWheat = 5; - this->aics[param_1].minimumHop = 5; - this->aics[param_1].recruitGoldThreshold = 100; - this->aics[param_1].flagType = 10; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm1 = 0x1e; - this->aics[param_1].farm2 = 0x1e; - this->aics[param_1].farm3 = 0x1e; - this->aics[param_1].farm4 = 0x1f; - this->aics[param_1].populationPerFarm = 3; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].tradeAmountFood = 10; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x1e; - this->aics[param_1].doubleRationsFoodThreshold = 0x1e; - this->aics[param_1].maxWood = 0x32; - this->aics[param_1].maxStone = 0x28; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 10; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 0x14; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0xf; - this->aics[param_1].maxQuarries = 1; - this->aics[param_1].maxIronmines = 2; - this->aics[param_1].maxWoodcutters = 0xc; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 0x10; - this->aics[param_1].buildInterval = 1; - this->aics[param_1].resourceRebuildDelay = 0x14; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource03 = 6; - this->aics[param_1].sellResource08 = 0x11; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x50; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackDefault = 0x1e; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].RecruitInterval = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].recruitProbDefDefault = 0x32; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 0; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbAttackWeak = 0x14; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitIntervalWeak = 8; - this->aics[param_1].SortieUnitRanged = 0x46; - this->aics[param_1].SortieUnitRangedMin = 5; - this->aics[param_1].SortieUnitMeleeMin = 0xf; - this->aics[param_1].SortieUnitMelee = 0x46; - this->aics[param_1].DefDiggingUnitMax = 0x3c; - this->aics[param_1].DefDiggingUnit = 0x47; - this->aics[param_1].DefWalls = 0x50; - this->aics[param_1].DefTotal = 0x50; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x46; - this->aics[param_1].HarassingSiegeEnginesMax = 0; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].AttForceBase = 0x28; - this->aics[param_1].AttForceRandom = 0; - this->aics[param_1].AttForceSupportAllyThreshold = 10; - this->aics[param_1].AttForceRallyPercentage = 0x32; - this->aics[param_1].RaidUnitsBase = 5; - this->aics[param_1].RaidUnitsRandom = 5; - this->aics[param_1].RaidUnit1 = 0x49; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x32; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].AttMaxEngineers = 0; - this->aics[param_1].AttDiggingUnit = 0x47; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 0x28; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x4a; - this->aics[param_1].AttUnitBackupMax = 0; - this->aics[param_1].AttUnitBackupGroupsCount = 0; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x49; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 4; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; + this->aics[aicIndex].minimumCheese = -1; + this->aics[aicIndex].minimumBread = -1; + this->aics[aicIndex].maxFood = 100; + this->aics[aicIndex].minimumWheat = 5; + this->aics[aicIndex].minimumHop = 5; + this->aics[aicIndex].recruitGoldThreshold = 100; + this->aics[aicIndex].flagType = 10; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 1; + this->aics[aicIndex].unknown005 = 1; + this->aics[aicIndex].criticalPopularity = 0x1194; + this->aics[aicIndex].lowestPopularity = 5000; + this->aics[aicIndex].highestPopularity = 9000; + this->aics[aicIndex].taxesMin = 2; + this->aics[aicIndex].taxesMax = 0xc; + this->aics[aicIndex].farm1 = 0x1e; + this->aics[aicIndex].farm2 = 0x1e; + this->aics[aicIndex].farm3 = 0x1e; + this->aics[aicIndex].farm4 = 0x1f; + this->aics[aicIndex].populationPerFarm = 3; + this->aics[aicIndex].unknown011 = 10; + this->aics[aicIndex].minimumApples = 10; + this->aics[aicIndex].tradeAmountFood = 10; + this->aics[aicIndex].tradeAmountEquipment = 0; + this->aics[aicIndex].aiRequestDelay = 0xc; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 0x1e; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x1e; + this->aics[aicIndex].maxWood = 0x32; + this->aics[aicIndex].maxStone = 0x28; + this->aics[aicIndex].maxResourceOther = 10; + this->aics[aicIndex].maxEquipment = 4; + this->aics[aicIndex].maxBeer = 10; + this->aics[aicIndex].maxResourceVariance = 4; + this->aics[aicIndex].populationPerWoodcutter = 7; + this->aics[aicIndex].populationPerQuarry = 0x14; + this->aics[aicIndex].populationPerIronmine = 10; + this->aics[aicIndex].populationPerPitchrig = 0xf; + this->aics[aicIndex].maxQuarries = 1; + this->aics[aicIndex].maxIronmines = 2; + this->aics[aicIndex].maxWoodcutters = 0xc; + this->aics[aicIndex].maxPitchrigs = 1; + this->aics[aicIndex].maxFarms = 0x10; + this->aics[aicIndex].buildInterval = 1; + this->aics[aicIndex].resourceRebuildDelay = 0x14; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x11; + this->aics[aicIndex].poleturnerSetting = 0x13; + this->aics[aicIndex].sellResource03 = 6; + this->aics[aicIndex].sellResource08 = 0x11; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource13 = 0x16; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].sellResource15 = 0x18; + this->aics[aicIndex].defWallPatrolRallyTime = 2; + this->aics[aicIndex].defWallPatrolGroups = 3; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 100; + this->aics[aicIndex].defSiegeEngineBuildDelay = 4; + this->aics[aicIndex].unknown072 = 200; + this->aics[aicIndex].unknown073 = 0x14; + this->aics[aicIndex].recruitProbDefWeak = 0x50; + this->aics[aicIndex].recruitProbRaidStrong = 0x1e; + this->aics[aicIndex].recruitProbAttackDefault = 0x1e; + this->aics[aicIndex].RecruitIntervalStrong = 1; + this->aics[aicIndex].OuterPatrolGroupsCount = 1; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].RecruitInterval = 4; + this->aics[aicIndex].RaidRetargetDelay = 4; + this->aics[aicIndex].recruitProbDefDefault = 0x32; + this->aics[aicIndex].recruitProbDefStrong = 0x14; + this->aics[aicIndex].recruitProbRaidWeak = 0; + this->aics[aicIndex].recruitProbRaidDefault = 0x14; + this->aics[aicIndex].recruitProbAttackWeak = 0x14; + this->aics[aicIndex].recruitProbAttackStrong = 0x32; + this->aics[aicIndex].RecruitIntervalWeak = 8; + this->aics[aicIndex].SortieUnitRanged = 0x46; + this->aics[aicIndex].SortieUnitRangedMin = 5; + this->aics[aicIndex].SortieUnitMeleeMin = 0xf; + this->aics[aicIndex].SortieUnitMelee = 0x46; + this->aics[aicIndex].DefDiggingUnitMax = 0x3c; + this->aics[aicIndex].DefDiggingUnit = 0x47; + this->aics[aicIndex].DefWalls = 0x50; + this->aics[aicIndex].DefTotal = 0x50; + this->aics[aicIndex].OuterPatrolRallyDelay = 2; + this->aics[aicIndex].DefUnit1 = 0x46; + this->aics[aicIndex].HarassingSiegeEnginesMax = 0; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].AttForceBase = 0x28; + this->aics[aicIndex].AttForceRandom = 0; + this->aics[aicIndex].AttForceSupportAllyThreshold = 10; + this->aics[aicIndex].AttForceRallyPercentage = 0x32; + this->aics[aicIndex].RaidUnitsBase = 5; + this->aics[aicIndex].RaidUnitsRandom = 5; + this->aics[aicIndex].RaidUnit1 = 0x49; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 0; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 5; + this->aics[aicIndex].AttCoordinationPreference = 0x32; + this->aics[aicIndex].CowThrowInterval = 10000; + this->aics[aicIndex].SiegeEngine1 = 0x27; + this->aics[aicIndex].AttMaxEngineers = 0; + this->aics[aicIndex].AttDiggingUnit = 0x47; + this->aics[aicIndex].AttDiggingUnitMax = 0x14; + this->aics[aicIndex].AttMaxAssassins = 0x28; + this->aics[aicIndex].AttUnit2 = 0; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x4a; + this->aics[aicIndex].AttUnitBackupMax = 0; + this->aics[aicIndex].AttUnitBackupGroupsCount = 0; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0; + this->aics[aicIndex].AttUnitSiegeDefMax = 0; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicIndex].AttUnitMain1 = 0x49; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 4; + this->aics[aicIndex].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 7033ba778..b9a5b8a6f 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34181,7 +34181,7 @@ SHC_3BB0A8C1_0x004C94F0 | 89.5% | Constant store order differs SHC_3BB0A8C1_0x004C9900 | 84.2% | Constant store order differs -SHC_3BB0A8C1_0x004C9CF0 | 0.0% | Pending +SHC_3BB0A8C1_0x004C9CF0 | 83.3% | Constant store order differs SHC_3BB0A8C1_0x004CA0C0 | 0.0% | Pending From 023068aa83e3b1d845077200b3927ff0d669c2a8 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:30 +0200 Subject: [PATCH 227/242] reimplement: SHC_3BB0A8C1_0x004CA0C0 82.35% Constant store order differs --- .../AI/AICState/setAICParameters_14.cpp | 411 ++++++------------ status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 136 insertions(+), 277 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp index 297eb3611..f2cc56d61 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp @@ -1,5 +1,4 @@ #include "../AICState.func.hpp" - #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { @@ -7,283 +6,143 @@ namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ - // FUNCTION: STRONGHOLDCRUSADER 0x004CA0C0 - void AICState ::setAICParameters_14(int param_1) - + void AICState::setAICParameters_14(int aicIndex) { - - this->aics[param_1].minimumBread = 0xffffffff; - - this->aics[param_1].minimumWheat = 0xffffffff; - - this->aics[param_1].minimumHop = 2; - - this->aics[param_1].tradeAmountEquipment = 2; - - this->aics[param_1].defWallPatrolGroups = 2; - - this->aics[param_1].unknown004 = 1; - - this->aics[param_1].unknown005 = 1; - - this->aics[param_1].aiRequestDelay = 0x28; - - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0x28; - - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - - this->aics[param_1].defSiegeEngineGoldThreshold = 200; - - this->aics[param_1].unknown072 = 200; - - this->aics[param_1].flagType = 0xd; - - this->aics[param_1].unknown002 = 0; - - this->aics[param_1].unknown001 = 0; - - this->aics[param_1].unknown003 = 0; - - this->aics[param_1].criticalPopularity = 4000; - - this->aics[param_1].lowestPopularity = 6000; - - this->aics[param_1].highestPopularity = 9000; - - this->aics[param_1].taxesMin = 3; - - this->aics[param_1].taxesMax = 0xb; - - this->aics[param_1].farm1 = 0x20; - - this->aics[param_1].farm2 = 0x1f; - - this->aics[param_1].farm3 = 0x21; - - this->aics[param_1].populationPerFarm = 4; - - this->aics[param_1].unknown011 = 10; - - this->aics[param_1].maxFood = 300; - - this->aics[param_1].minimumApples = 0x14; - - this->aics[param_1].minimumCheese = 0x14; - - this->aics[param_1].tradeAmountFood = 10; - - this->aics[param_1].maxWood = 0x32; - - this->aics[param_1].maxStone = 0x32; - - this->aics[param_1].maxResourceOther = 10; - - this->aics[param_1].maxEquipment = 10; - - this->aics[param_1].maxBeer = 10; - - this->aics[param_1].maxResourceVariance = 5; - - this->aics[param_1].recruitGoldThreshold = 200; - - this->aics[param_1].populationPerWoodcutter = 7; - - this->aics[param_1].populationPerQuarry = 10; - - this->aics[param_1].populationPerIronmine = 0xc; - - this->aics[param_1].populationPerPitchrig = 0xf; - - this->aics[param_1].maxQuarries = 3; - - this->aics[param_1].maxIronmines = 6; - - this->aics[param_1].maxWoodcutters = 10; - - this->aics[param_1].maxPitchrigs = 4; - - this->aics[param_1].maxFarms = 10; - - this->aics[param_1].buildInterval = 3; - - this->aics[param_1].resourceRebuildDelay = 8; - - this->aics[param_1].blacksmithSetting = 0x15; - - this->aics[param_1].fletcherSetting = 0x12; - - this->aics[param_1].poleturnerSetting = 0x14; - - this->aics[param_1].sellResource05 = 9; - - this->aics[param_1].sellResource07 = 0x10; - - this->aics[param_1].sellResource08 = 0x11; - - this->aics[param_1].sellResource10 = 0x13; - - this->aics[param_1].sellResource11 = 0x14; - - this->aics[param_1].sellResource13 = 0x16; - - this->aics[param_1].sellResource15 = 0x18; - - this->aics[param_1].defWallPatrolRallyTime = 8; - - this->aics[param_1].defSiegeEngineBuildDelay = 4; - - this->aics[param_1].unknown073 = 0x1e; - - this->aics[param_1].recruitProbDefWeak = 100; - - this->aics[param_1].recruitProbDefDefault = 0x32; - - this->aics[param_1].recruitProbDefStrong = 0x1e; - - this->aics[param_1].recruitProbRaidDefault = 0x1e; - - this->aics[param_1].RecruitInterval = 4; - - this->aics[param_1].RecruitIntervalStrong = 4; - - this->aics[param_1].DefDiggingUnitMax = 4; - - this->aics[param_1].DefDiggingUnit = 0x1a; - - this->aics[param_1].RaidUnitsRandom = 4; - - this->aics[param_1].RaidRetargetDelay = 4; - - this->aics[param_1].recruitProbAttackDefault = 0x14; - - this->aics[param_1].recruitProbAttackStrong = 0x14; - - this->aics[param_1].recruitProbRaidStrong = 0x32; - - this->aics[param_1].SortieUnitRangedMin = 10; - - this->aics[param_1].SortieUnitMeleeMin = 10; - - this->aics[param_1].SortieUnitRanged = 0x17; - - this->aics[param_1].SortieUnitMelee = 0x1a; - - this->aics[param_1].DefTotal = 0x32; - - this->aics[param_1].RaidUnitsBase = 10; - - this->aics[param_1].recruitProbRaidWeak = 0; - - this->aics[param_1].recruitProbAttackWeak = 0; - - this->aics[param_1].RecruitIntervalWeak = 1; - - this->aics[param_1].DefWalls = 0x28; - - this->aics[param_1].OuterPatrolGroupsCount = 1; - - this->aics[param_1].OuterPatrolGroupsMove = 1; - - this->aics[param_1].OuterPatrolRallyDelay = 5; - - this->aics[param_1].DefUnit1 = 0x17; - - this->aics[param_1].DefUnit2 = 0x17; - - this->aics[param_1].DefUnit3 = 0x17; - - this->aics[param_1].DefUnit4 = 0x4c; - - this->aics[param_1].DefUnit5 = 0x49; - - this->aics[param_1].HarassingSiegeEnginesMax = 5; - - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - - this->aics[param_1].HarassingSiegeEngine2 = 0x166; - - this->aics[param_1].RaidUnit1 = 0x1a; - - this->aics[param_1].AttForceBase = 0x32; - - this->aics[param_1].AttForceRandom = 0x14; - - this->aics[param_1].AttForceSupportAllyThreshold = 0x32; - - this->aics[param_1].AttForceRallyPercentage = 0x50; - - this->aics[param_1].AttMovingTribesThreshold = 100; - - this->aics[param_1].AttAssaultDelay = 5; - - this->aics[param_1].AttUnitPatrolRecommandDelay = 8; - - this->aics[param_1].AttCoordinationPreference = 0x32; - - this->aics[param_1].CowThrowInterval = 6; - - this->aics[param_1].SiegeEngine1 = 0x27; - - this->aics[param_1].SiegeEngine2 = 0x27; - - this->aics[param_1].SiegeEngine3 = 0x4d; - - this->aics[param_1].SiegeEngine4 = 0x4d; - - this->aics[param_1].SiegeEngine5 = 0x4d; - - this->aics[param_1].AttMaxEngineers = 10; - - this->aics[param_1].AttDiggingUnit = 0x47; - - this->aics[param_1].AttDiggingUnitMax = 0x50; - - this->aics[param_1].AttMaxAssassins = 10; - - this->aics[param_1].AttUnit2 = 0x1a; - - this->aics[param_1].AttUnit2Max = 10; - - this->aics[param_1].AttMaxLaddermen = 0; - - this->aics[param_1].AttMaxTunnelers = 0; - - this->aics[param_1].AttUnitPatrol = 0x4c; - - this->aics[param_1].AttUnitPatrolMax = 0; - - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - - this->aics[param_1].AttUnitBackup = 0x17; - - this->aics[param_1].AttUnitBackupMax = 0x32; - - this->aics[param_1].AttUnitBackupGroupsCount = 1; - - this->aics[param_1].AttUnitEngageMax = 0; - - this->aics[param_1].AttUnitEngage = 0; - - this->aics[param_1].AttUnitSiegeDef = 0x1a; - - this->aics[param_1].AttUnitSiegeDefMax = 6; - - this->aics[param_1].AttUnitSiegeDefGroupsCount = 1; - - this->aics[param_1].AttUnitMain1 = 0x1a; - - this->aics[param_1].AttUnitMain2 = 0x1a; - - this->aics[param_1].AttMaxDefault = 200; - - this->aics[param_1].AttMainGroupsCount = 3; - - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; - - return; + this->aics[aicIndex].flagType = 0xd; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 1; + this->aics[aicIndex].unknown005 = 1; + this->aics[aicIndex].criticalPopularity = 4000; + this->aics[aicIndex].lowestPopularity = 6000; + this->aics[aicIndex].highestPopularity = 9000; + this->aics[aicIndex].taxesMin = 3; + this->aics[aicIndex].taxesMax = 0xb; + this->aics[aicIndex].unknown011 = 10; + this->aics[aicIndex].farm1 = 0x20; + this->aics[aicIndex].farm2 = 0x1f; + this->aics[aicIndex].farm3 = 0x21; + this->aics[aicIndex].populationPerFarm = 4; + this->aics[aicIndex].populationPerWoodcutter = 7; + this->aics[aicIndex].populationPerQuarry = 10; + this->aics[aicIndex].populationPerIronmine = 0xc; + this->aics[aicIndex].populationPerPitchrig = 0xf; + this->aics[aicIndex].maxQuarries = 3; + this->aics[aicIndex].maxIronmines = 6; + this->aics[aicIndex].maxWoodcutters = 10; + this->aics[aicIndex].maxPitchrigs = 4; + this->aics[aicIndex].maxFarms = 10; + this->aics[aicIndex].buildInterval = 3; + this->aics[aicIndex].resourceRebuildDelay = 8; + this->aics[aicIndex].maxFood = 300; + this->aics[aicIndex].minimumApples = 0x14; + this->aics[aicIndex].minimumCheese = 0x14; + this->aics[aicIndex].minimumBread = 0xffffffff; + this->aics[aicIndex].minimumWheat = 0xffffffff; + this->aics[aicIndex].minimumHop = 2; + this->aics[aicIndex].tradeAmountFood = 10; + this->aics[aicIndex].tradeAmountEquipment = 2; + this->aics[aicIndex].aiRequestDelay = 0x28; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 0x28; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x28; + this->aics[aicIndex].maxWood = 0x32; + this->aics[aicIndex].maxStone = 0x32; + this->aics[aicIndex].maxResourceOther = 10; + this->aics[aicIndex].maxEquipment = 10; + this->aics[aicIndex].maxBeer = 10; + this->aics[aicIndex].maxResourceVariance = 5; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].blacksmithSetting = 0x15; + this->aics[aicIndex].fletcherSetting = 0x12; + this->aics[aicIndex].poleturnerSetting = 0x14; + this->aics[aicIndex].sellResource05 = 9; + this->aics[aicIndex].sellResource07 = 0x10; + this->aics[aicIndex].sellResource08 = 0x11; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource13 = 0x16; + this->aics[aicIndex].sellResource15 = 0x18; + this->aics[aicIndex].defWallPatrolRallyTime = 8; + this->aics[aicIndex].defWallPatrolGroups = 2; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 200; + this->aics[aicIndex].defSiegeEngineBuildDelay = 4; + this->aics[aicIndex].unknown072 = 200; + this->aics[aicIndex].unknown073 = 0x1e; + this->aics[aicIndex].recruitProbDefDefault = 0x32; + this->aics[aicIndex].recruitProbDefWeak = 100; + this->aics[aicIndex].recruitProbDefStrong = 0x1e; + this->aics[aicIndex].recruitProbRaidDefault = 0x1e; + this->aics[aicIndex].recruitProbRaidWeak = 0; + this->aics[aicIndex].recruitProbRaidStrong = 0x32; + this->aics[aicIndex].recruitProbAttackDefault = 0x14; + this->aics[aicIndex].recruitProbAttackWeak = 0; + this->aics[aicIndex].recruitProbAttackStrong = 0x14; + this->aics[aicIndex].SortieUnitRangedMin = 10; + this->aics[aicIndex].SortieUnitRanged = 0x17; + this->aics[aicIndex].SortieUnitMeleeMin = 10; + this->aics[aicIndex].SortieUnitMelee = 0x1a; + this->aics[aicIndex].DefDiggingUnitMax = 4; + this->aics[aicIndex].DefDiggingUnit = 0x1a; + this->aics[aicIndex].RecruitInterval = 4; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].RecruitIntervalStrong = 4; + this->aics[aicIndex].DefTotal = 0x32; + this->aics[aicIndex].OuterPatrolGroupsCount = 1; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 5; + this->aics[aicIndex].DefWalls = 0x28; + this->aics[aicIndex].DefUnit1 = 0x17; + this->aics[aicIndex].DefUnit2 = 0x17; + this->aics[aicIndex].DefUnit3 = 0x17; + this->aics[aicIndex].DefUnit4 = 0x4c; + this->aics[aicIndex].DefUnit5 = 0x49; + this->aics[aicIndex].RaidUnitsBase = 10; + this->aics[aicIndex].RaidUnitsRandom = 4; + this->aics[aicIndex].RaidUnit1 = 0x1a; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].HarassingSiegeEngine2 = 0x166; + this->aics[aicIndex].HarassingSiegeEnginesMax = 5; + this->aics[aicIndex].RaidRetargetDelay = 4; + this->aics[aicIndex].AttForceBase = 0x32; + this->aics[aicIndex].AttForceRandom = 0x14; + this->aics[aicIndex].AttForceSupportAllyThreshold = 0x32; + this->aics[aicIndex].AttForceRallyPercentage = 0x50; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 5; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 8; + this->aics[aicIndex].AttCoordinationPreference = 0x32; + this->aics[aicIndex].SiegeEngine1 = 0x27; + this->aics[aicIndex].SiegeEngine2 = 0x27; + this->aics[aicIndex].SiegeEngine3 = 0x4d; + this->aics[aicIndex].SiegeEngine4 = 0x4d; + this->aics[aicIndex].SiegeEngine5 = 0x4d; + this->aics[aicIndex].CowThrowInterval = 6; + this->aics[aicIndex].AttMaxEngineers = 10; + this->aics[aicIndex].AttDiggingUnit = 0x47; + this->aics[aicIndex].AttDiggingUnitMax = 0x50; + this->aics[aicIndex].AttUnit2 = 0x1a; + this->aics[aicIndex].AttUnit2Max = 10; + this->aics[aicIndex].AttMaxAssassins = 10; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0x4c; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x17; + this->aics[aicIndex].AttUnitBackupMax = 0x32; + this->aics[aicIndex].AttUnitBackupGroupsCount = 1; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0x1a; + this->aics[aicIndex].AttUnitSiegeDefMax = 6; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 1; + this->aics[aicIndex].AttUnitMain1 = 0x1a; + this->aics[aicIndex].AttUnitMain2 = 0x1a; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 3; + this->aics[aicIndex].TargetChoice = OpenSHC::AI::AIC::AITC_CLOSEST; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index b9a5b8a6f..fd72e5b8d 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34183,7 +34183,7 @@ SHC_3BB0A8C1_0x004C9900 | 84.2% | Constant store order differs SHC_3BB0A8C1_0x004C9CF0 | 83.3% | Constant store order differs -SHC_3BB0A8C1_0x004CA0C0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CA0C0 | 82.3% | Constant store order differs SHC_3BB0A8C1_0x004CA4D0 | 0.0% | Pending From ebfb11205364892c4ad9aeb5ba7664fe1cd6053a Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:30 +0200 Subject: [PATCH 228/242] reimplement: SHC_3BB0A8C1_0x004CA4D0 74.92% Constant store order differs --- .../AI/AICState/setAICParameters_15.cpp | 259 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 129 insertions(+), 132 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_15.cpp b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp index 9574a6c87..2d2c9deca 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_15.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_15.cpp @@ -6,139 +6,136 @@ namespace OpenSHC { namespace AI { using OpenSHC::AI::AIC::AITargetChoice; - - /* - decompilerscript: committed: 2025-01-30 21:57:43.216000 */ // FUNCTION: STRONGHOLDCRUSADER 0x004CA4D0 - void AICState ::setAICParameters_15(int param_1) + void AICState::setAICParameters_15(int aicIndex) { - this->aics[param_1].farm1 = 0x21; - this->aics[param_1].farm3 = 0x21; - this->aics[param_1].farm4 = 0x21; - this->aics[param_1].populationPerFarm = 5; - this->aics[param_1].minimumHop = 5; - this->aics[param_1].minimumBread = -1; - this->aics[param_1].minimumWheat = -1; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 7; - this->aics[param_1].populationPerIronmine = 7; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].maxResourceOther = 0xc; - this->aics[param_1].maxIronmines = 3; - this->aics[param_1].buildInterval = 3; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 4000; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 8000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].taxesMax = 10; - this->aics[param_1].farm2 = 0x1f; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumCheese = 10; - this->aics[param_1].tradeAmountFood = 0x14; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 0; - this->aics[param_1].doubleRationsFoodThreshold = 0x50; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x32; - this->aics[param_1].maxEquipment = 10; - this->aics[param_1].maxBeer = 6; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 200; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 1; - this->aics[param_1].maxWoodcutters = 8; - this->aics[param_1].maxPitchrigs = 1; - this->aics[param_1].maxFarms = 9; - this->aics[param_1].resourceRebuildDelay = 0x28; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource04 = 7; - this->aics[param_1].sellResource05 = 9; - this->aics[param_1].sellResource07 = 0x10; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].RecruitIntervalStrong = 4; - this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].SortieUnitMeleeMin = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].RaidUnitsRandom = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].recruitProbRaidWeak = 0x28; - this->aics[param_1].recruitProbRaidDefault = 0x28; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].DefTotal = 0x28; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].AttForceBase = 10; - this->aics[param_1].AttForceSupportAllyThreshold = 10; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x32; - this->aics[param_1].recruitProbDefDefault = 0x1e; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackDefault = 0x1e; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].SortieUnitMelee = 0x1c; - this->aics[param_1].DefWalls = 0x1e; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].RaidUnitsBase = 0x10; - this->aics[param_1].RaidUnit1 = 0x1c; - this->aics[param_1].HarassingSiegeEnginesMax = 1; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].AttForceRandom = 0x14; - this->aics[param_1].AttForceRallyPercentage = 0x32; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x46; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x28; - this->aics[param_1].SiegeEngine2 = 0x28; - this->aics[param_1].AttMaxEngineers = 6; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 0x14; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x1e; - this->aics[param_1].AttUnitBackupGroupsCount = 3; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x1b; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + this->aics[aicIndex].farm1 = 0x21; + this->aics[aicIndex].farm3 = 0x21; + this->aics[aicIndex].farm4 = 0x21; + this->aics[aicIndex].populationPerFarm = 5; + this->aics[aicIndex].minimumHop = 5; + this->aics[aicIndex].minimumBread = -1; + this->aics[aicIndex].minimumWheat = -1; + this->aics[aicIndex].populationPerWoodcutter = 7; + this->aics[aicIndex].populationPerQuarry = 7; + this->aics[aicIndex].populationPerIronmine = 7; + this->aics[aicIndex].aiRequestDelay = 0xc; + this->aics[aicIndex].maxResourceOther = 0xc; + this->aics[aicIndex].maxIronmines = 3; + this->aics[aicIndex].buildInterval = 3; + this->aics[aicIndex].flagType = 0xd; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 1; + this->aics[aicIndex].unknown005 = 1; + this->aics[aicIndex].criticalPopularity = 4000; + this->aics[aicIndex].lowestPopularity = 5000; + this->aics[aicIndex].highestPopularity = 8000; + this->aics[aicIndex].taxesMin = 2; + this->aics[aicIndex].taxesMax = 10; + this->aics[aicIndex].farm2 = 0x1f; + this->aics[aicIndex].unknown011 = 10; + this->aics[aicIndex].maxFood = 100; + this->aics[aicIndex].minimumApples = 10; + this->aics[aicIndex].minimumCheese = 10; + this->aics[aicIndex].tradeAmountFood = 0x14; + this->aics[aicIndex].tradeAmountEquipment = 0; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 0; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x50; + this->aics[aicIndex].maxWood = 0x3c; + this->aics[aicIndex].maxStone = 0x32; + this->aics[aicIndex].maxEquipment = 10; + this->aics[aicIndex].maxBeer = 6; + this->aics[aicIndex].maxResourceVariance = 4; + this->aics[aicIndex].recruitGoldThreshold = 200; + this->aics[aicIndex].populationPerPitchrig = 0; + this->aics[aicIndex].maxQuarries = 1; + this->aics[aicIndex].maxWoodcutters = 8; + this->aics[aicIndex].maxPitchrigs = 1; + this->aics[aicIndex].maxFarms = 9; + this->aics[aicIndex].resourceRebuildDelay = 0x28; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x11; + this->aics[aicIndex].poleturnerSetting = 0x13; + this->aics[aicIndex].sellResource04 = 7; + this->aics[aicIndex].sellResource05 = 9; + this->aics[aicIndex].sellResource07 = 0x10; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].defWallPatrolRallyTime = 2; + this->aics[aicIndex].defWallPatrolGroups = 3; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 100; + this->aics[aicIndex].defSiegeEngineBuildDelay = 4; + this->aics[aicIndex].unknown072 = 200; + this->aics[aicIndex].RecruitIntervalStrong = 4; + this->aics[aicIndex].SortieUnitRangedMin = 4; + this->aics[aicIndex].SortieUnitMeleeMin = 4; + this->aics[aicIndex].DefDiggingUnitMax = 4; + this->aics[aicIndex].RaidUnitsRandom = 4; + this->aics[aicIndex].RaidRetargetDelay = 4; + this->aics[aicIndex].recruitProbRaidWeak = 0x28; + this->aics[aicIndex].recruitProbRaidDefault = 0x28; + this->aics[aicIndex].recruitProbAttackWeak = 10; + this->aics[aicIndex].SortieUnitRanged = 0x16; + this->aics[aicIndex].DefDiggingUnit = 0x16; + this->aics[aicIndex].DefTotal = 0x28; + this->aics[aicIndex].DefUnit1 = 0x16; + this->aics[aicIndex].AttForceBase = 10; + this->aics[aicIndex].AttForceSupportAllyThreshold = 10; + this->aics[aicIndex].unknown073 = 0x14; + this->aics[aicIndex].recruitProbDefWeak = 0x32; + this->aics[aicIndex].recruitProbDefDefault = 0x1e; + this->aics[aicIndex].recruitProbDefStrong = 0x14; + this->aics[aicIndex].recruitProbRaidStrong = 0x1e; + this->aics[aicIndex].recruitProbAttackDefault = 0x1e; + this->aics[aicIndex].recruitProbAttackStrong = 0x32; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].RecruitInterval = 1; + this->aics[aicIndex].SortieUnitMelee = 0x1c; + this->aics[aicIndex].DefWalls = 0x1e; + this->aics[aicIndex].OuterPatrolGroupsCount = 1; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 2; + this->aics[aicIndex].RaidUnitsBase = 0x10; + this->aics[aicIndex].RaidUnit1 = 0x1c; + this->aics[aicIndex].HarassingSiegeEnginesMax = 1; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].AttForceRandom = 0x14; + this->aics[aicIndex].AttForceRallyPercentage = 0x32; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 0; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 5; + this->aics[aicIndex].AttCoordinationPreference = 0x46; + this->aics[aicIndex].CowThrowInterval = 10000; + this->aics[aicIndex].SiegeEngine1 = 0x28; + this->aics[aicIndex].SiegeEngine2 = 0x28; + this->aics[aicIndex].AttMaxEngineers = 6; + this->aics[aicIndex].AttDiggingUnit = 0x16; + this->aics[aicIndex].AttDiggingUnitMax = 0x14; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttUnit2 = 0; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x16; + this->aics[aicIndex].AttUnitBackupMax = 0x1e; + this->aics[aicIndex].AttUnitBackupGroupsCount = 3; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0; + this->aics[aicIndex].AttUnitSiegeDefMax = 0; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicIndex].AttUnitMain1 = 0x1b; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 2; + this->aics[aicIndex].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index fd72e5b8d..bb7ad6a02 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34185,7 +34185,7 @@ SHC_3BB0A8C1_0x004C9CF0 | 83.3% | Constant store order differs SHC_3BB0A8C1_0x004CA0C0 | 82.3% | Constant store order differs -SHC_3BB0A8C1_0x004CA4D0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CA4D0 | 74.9% | Constant store order differs SHC_3BB0A8C1_0x004CA8A0 | 0.0% | Pending From 7420f91ee83470d2d7ad4a150d754d3c54f268d9 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:16:30 +0200 Subject: [PATCH 229/242] reimplement: SHC_3BB0A8C1_0x004CA8A0 84.75% Constant store order differs --- .../AI/AICState/setAICParameters_16.cpp | 258 +++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 130 insertions(+), 130 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setAICParameters_16.cpp b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp index f54f13b99..1721cd187 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_16.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_16.cpp @@ -8,136 +8,136 @@ namespace AI { using OpenSHC::AI::AIC::AITargetChoice; // FUNCTION: STRONGHOLDCRUSADER 0x004CA8A0 - void AICState ::setAICParameters_16(int param_1) + void AICState::setAICParameters_16(int aicIndex) { - this->aics[param_1].taxesMax = 0xc; - this->aics[param_1].farm2 = 0x1e; - this->aics[param_1].farm3 = 0x1e; - this->aics[param_1].aiRequestDelay = 0xc; - this->aics[param_1].maxFarms = 0xc; - this->aics[param_1].flagType = 0xd; - this->aics[param_1].unknown002 = 0; - this->aics[param_1].unknown001 = 0; - this->aics[param_1].unknown003 = 0; - this->aics[param_1].unknown004 = 1; - this->aics[param_1].unknown005 = 1; - this->aics[param_1].criticalPopularity = 0x1194; - this->aics[param_1].lowestPopularity = 5000; - this->aics[param_1].highestPopularity = 9000; - this->aics[param_1].taxesMin = 2; - this->aics[param_1].farm1 = 0x1f; - this->aics[param_1].populationPerFarm = 4; - this->aics[param_1].unknown011 = 10; - this->aics[param_1].maxFood = 100; - this->aics[param_1].minimumApples = 10; - this->aics[param_1].minimumCheese = -1; - this->aics[param_1].minimumBread = -1; - this->aics[param_1].minimumWheat = 2; - this->aics[param_1].minimumHop = 2; - this->aics[param_1].tradeAmountFood = 5; - this->aics[param_1].tradeAmountEquipment = 0; - this->aics[param_1].minimumGoodsRequiredAfterTrade = 10; - this->aics[param_1].doubleRationsFoodThreshold = 0x28; - this->aics[param_1].maxWood = 0x3c; - this->aics[param_1].maxStone = 0x28; - this->aics[param_1].maxResourceOther = 10; - this->aics[param_1].maxEquipment = 4; - this->aics[param_1].maxBeer = 5; - this->aics[param_1].maxResourceVariance = 4; - this->aics[param_1].recruitGoldThreshold = 0x32; - this->aics[param_1].populationPerWoodcutter = 7; - this->aics[param_1].populationPerQuarry = 6; - this->aics[param_1].populationPerIronmine = 10; - this->aics[param_1].populationPerPitchrig = 0; - this->aics[param_1].maxQuarries = 4; - this->aics[param_1].maxIronmines = 2; - this->aics[param_1].maxWoodcutters = 10; - this->aics[param_1].maxPitchrigs = 0; - this->aics[param_1].buildInterval = 2; - this->aics[param_1].resourceRebuildDelay = 0x28; - this->aics[param_1].blacksmithSetting = 0x16; - this->aics[param_1].fletcherSetting = 0x11; - this->aics[param_1].poleturnerSetting = 0x13; - this->aics[param_1].sellResource03 = 6; - this->aics[param_1].sellResource09 = 0x12; - this->aics[param_1].sellResource10 = 0x13; - this->aics[param_1].sellResource11 = 0x14; - this->aics[param_1].sellResource12 = 0x15; - this->aics[param_1].sellResource13 = 0x16; - this->aics[param_1].sellResource14 = 0x17; - this->aics[param_1].sellResource15 = 0x18; - this->aics[param_1].defWallPatrolRallyTime = 2; - this->aics[param_1].defWallPatrolGroups = 3; - this->aics[param_1].defSiegeEngineGoldThreshold = 100; - this->aics[param_1].defSiegeEngineBuildDelay = 4; - this->aics[param_1].unknown072 = 200; - this->aics[param_1].unknown073 = 0x14; - this->aics[param_1].recruitProbDefWeak = 0x50; - this->aics[param_1].recruitProbDefDefault = 0x28; - this->aics[param_1].recruitProbDefStrong = 0x14; - this->aics[param_1].recruitProbRaidWeak = 10; - this->aics[param_1].SortieUnitRangedMin = 4; - this->aics[param_1].DefDiggingUnitMax = 4; - this->aics[param_1].RaidRetargetDelay = 4; - this->aics[param_1].RecruitIntervalWeak = 1; - this->aics[param_1].RecruitInterval = 1; - this->aics[param_1].RecruitIntervalStrong = 1; - this->aics[param_1].SortieUnitRanged = 0x16; - this->aics[param_1].DefDiggingUnit = 0x16; - this->aics[param_1].OuterPatrolGroupsCount = 1; - this->aics[param_1].OuterPatrolGroupsMove = 1; - this->aics[param_1].OuterPatrolRallyDelay = 2; - this->aics[param_1].DefUnit1 = 0x16; - this->aics[param_1].recruitProbRaidDefault = 0x14; - this->aics[param_1].recruitProbRaidStrong = 0x1e; - this->aics[param_1].recruitProbAttackWeak = 10; - this->aics[param_1].recruitProbAttackDefault = 0x28; - this->aics[param_1].recruitProbAttackStrong = 0x32; - this->aics[param_1].SortieUnitMeleeMin = 0x14; - this->aics[param_1].SortieUnitMelee = 0x25; - this->aics[param_1].DefWalls = 0x1e; - this->aics[param_1].DefTotal = 0x1e; - this->aics[param_1].RaidUnitsBase = 0x1e; - this->aics[param_1].RaidUnitsRandom = 10; - this->aics[param_1].RaidUnit1 = 0x25; - this->aics[param_1].HarassingSiegeEnginesMax = 5; - this->aics[param_1].HarassingSiegeEngine1 = 0xbe; - this->aics[param_1].AttForceBase = 0x32; - this->aics[param_1].AttForceRandom = 10; - this->aics[param_1].AttForceSupportAllyThreshold = 0x28; - this->aics[param_1].AttForceRallyPercentage = 0x50; - this->aics[param_1].AttMovingTribesThreshold = 100; - this->aics[param_1].AttAssaultDelay = 0; - this->aics[param_1].AttUnitPatrolRecommandDelay = 5; - this->aics[param_1].AttCoordinationPreference = 0x50; - this->aics[param_1].CowThrowInterval = 10000; - this->aics[param_1].SiegeEngine1 = 0x27; - this->aics[param_1].SiegeEngine2 = 0x27; - this->aics[param_1].SiegeEngine3 = 0x27; - this->aics[param_1].SiegeEngine4 = 0x27; - this->aics[param_1].AttMaxEngineers = 8; - this->aics[param_1].AttDiggingUnit = 0x16; - this->aics[param_1].AttDiggingUnitMax = 10; - this->aics[param_1].AttMaxAssassins = 0; - this->aics[param_1].AttUnit2 = 0; - this->aics[param_1].AttUnit2Max = 0; - this->aics[param_1].AttMaxLaddermen = 0; - this->aics[param_1].AttMaxTunnelers = 0; - this->aics[param_1].AttUnitPatrol = 0; - this->aics[param_1].AttUnitPatrolMax = 0; - this->aics[param_1].AttUnitPatrolGroupsCount = 0; - this->aics[param_1].AttUnitBackup = 0x16; - this->aics[param_1].AttUnitBackupMax = 0x28; - this->aics[param_1].AttUnitBackupGroupsCount = 1; - this->aics[param_1].AttUnitEngageMax = 0; - this->aics[param_1].AttUnitEngage = 0; - this->aics[param_1].AttUnitSiegeDef = 0; - this->aics[param_1].AttUnitSiegeDefMax = 0; - this->aics[param_1].AttUnitSiegeDefGroupsCount = 0; - this->aics[param_1].AttUnitMain1 = 0x25; - this->aics[param_1].AttMaxDefault = 200; - this->aics[param_1].AttMainGroupsCount = 2; - this->aics[param_1].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; + this->aics[aicIndex].taxesMax = 0xc; + this->aics[aicIndex].farm2 = 0x1e; + this->aics[aicIndex].farm3 = 0x1e; + this->aics[aicIndex].aiRequestDelay = 0xc; + this->aics[aicIndex].maxFarms = 0xc; + this->aics[aicIndex].flagType = 0xd; + this->aics[aicIndex].unknown002 = 0; + this->aics[aicIndex].unknown001 = 0; + this->aics[aicIndex].unknown003 = 0; + this->aics[aicIndex].unknown004 = 1; + this->aics[aicIndex].unknown005 = 1; + this->aics[aicIndex].criticalPopularity = 0x1194; + this->aics[aicIndex].lowestPopularity = 5000; + this->aics[aicIndex].highestPopularity = 9000; + this->aics[aicIndex].taxesMin = 2; + this->aics[aicIndex].farm1 = 0x1f; + this->aics[aicIndex].populationPerFarm = 4; + this->aics[aicIndex].unknown011 = 10; + this->aics[aicIndex].maxFood = 100; + this->aics[aicIndex].minimumApples = 10; + this->aics[aicIndex].minimumCheese = -1; + this->aics[aicIndex].minimumBread = -1; + this->aics[aicIndex].minimumWheat = 2; + this->aics[aicIndex].minimumHop = 2; + this->aics[aicIndex].tradeAmountFood = 5; + this->aics[aicIndex].tradeAmountEquipment = 0; + this->aics[aicIndex].minimumGoodsRequiredAfterTrade = 10; + this->aics[aicIndex].doubleRationsFoodThreshold = 0x28; + this->aics[aicIndex].maxWood = 0x3c; + this->aics[aicIndex].maxStone = 0x28; + this->aics[aicIndex].maxResourceOther = 10; + this->aics[aicIndex].maxEquipment = 4; + this->aics[aicIndex].maxBeer = 5; + this->aics[aicIndex].maxResourceVariance = 4; + this->aics[aicIndex].recruitGoldThreshold = 0x32; + this->aics[aicIndex].populationPerWoodcutter = 7; + this->aics[aicIndex].populationPerQuarry = 6; + this->aics[aicIndex].populationPerIronmine = 10; + this->aics[aicIndex].populationPerPitchrig = 0; + this->aics[aicIndex].maxQuarries = 4; + this->aics[aicIndex].maxIronmines = 2; + this->aics[aicIndex].maxWoodcutters = 10; + this->aics[aicIndex].maxPitchrigs = 0; + this->aics[aicIndex].buildInterval = 2; + this->aics[aicIndex].resourceRebuildDelay = 0x28; + this->aics[aicIndex].blacksmithSetting = 0x16; + this->aics[aicIndex].fletcherSetting = 0x11; + this->aics[aicIndex].poleturnerSetting = 0x13; + this->aics[aicIndex].sellResource03 = 6; + this->aics[aicIndex].sellResource09 = 0x12; + this->aics[aicIndex].sellResource10 = 0x13; + this->aics[aicIndex].sellResource11 = 0x14; + this->aics[aicIndex].sellResource12 = 0x15; + this->aics[aicIndex].sellResource13 = 0x16; + this->aics[aicIndex].sellResource14 = 0x17; + this->aics[aicIndex].sellResource15 = 0x18; + this->aics[aicIndex].defWallPatrolRallyTime = 2; + this->aics[aicIndex].defWallPatrolGroups = 3; + this->aics[aicIndex].defSiegeEngineGoldThreshold = 100; + this->aics[aicIndex].defSiegeEngineBuildDelay = 4; + this->aics[aicIndex].unknown072 = 200; + this->aics[aicIndex].unknown073 = 0x14; + this->aics[aicIndex].recruitProbDefWeak = 0x50; + this->aics[aicIndex].recruitProbDefDefault = 0x28; + this->aics[aicIndex].recruitProbDefStrong = 0x14; + this->aics[aicIndex].recruitProbRaidWeak = 10; + this->aics[aicIndex].SortieUnitRangedMin = 4; + this->aics[aicIndex].DefDiggingUnitMax = 4; + this->aics[aicIndex].RaidRetargetDelay = 4; + this->aics[aicIndex].RecruitIntervalWeak = 1; + this->aics[aicIndex].RecruitInterval = 1; + this->aics[aicIndex].RecruitIntervalStrong = 1; + this->aics[aicIndex].SortieUnitRanged = 0x16; + this->aics[aicIndex].DefDiggingUnit = 0x16; + this->aics[aicIndex].OuterPatrolGroupsCount = 1; + this->aics[aicIndex].OuterPatrolGroupsMove = 1; + this->aics[aicIndex].OuterPatrolRallyDelay = 2; + this->aics[aicIndex].DefUnit1 = 0x16; + this->aics[aicIndex].recruitProbRaidDefault = 0x14; + this->aics[aicIndex].recruitProbRaidStrong = 0x1e; + this->aics[aicIndex].recruitProbAttackWeak = 10; + this->aics[aicIndex].recruitProbAttackDefault = 0x28; + this->aics[aicIndex].recruitProbAttackStrong = 0x32; + this->aics[aicIndex].SortieUnitMeleeMin = 0x14; + this->aics[aicIndex].SortieUnitMelee = 0x25; + this->aics[aicIndex].DefWalls = 0x1e; + this->aics[aicIndex].DefTotal = 0x1e; + this->aics[aicIndex].RaidUnitsBase = 0x1e; + this->aics[aicIndex].RaidUnitsRandom = 10; + this->aics[aicIndex].RaidUnit1 = 0x25; + this->aics[aicIndex].HarassingSiegeEnginesMax = 5; + this->aics[aicIndex].HarassingSiegeEngine1 = 0xbe; + this->aics[aicIndex].AttForceBase = 0x32; + this->aics[aicIndex].AttForceRandom = 10; + this->aics[aicIndex].AttForceSupportAllyThreshold = 0x28; + this->aics[aicIndex].AttForceRallyPercentage = 0x50; + this->aics[aicIndex].AttMovingTribesThreshold = 100; + this->aics[aicIndex].AttAssaultDelay = 0; + this->aics[aicIndex].AttUnitPatrolRecommandDelay = 5; + this->aics[aicIndex].AttCoordinationPreference = 0x50; + this->aics[aicIndex].CowThrowInterval = 10000; + this->aics[aicIndex].SiegeEngine1 = 0x27; + this->aics[aicIndex].SiegeEngine2 = 0x27; + this->aics[aicIndex].SiegeEngine3 = 0x27; + this->aics[aicIndex].SiegeEngine4 = 0x27; + this->aics[aicIndex].AttMaxEngineers = 8; + this->aics[aicIndex].AttDiggingUnit = 0x16; + this->aics[aicIndex].AttDiggingUnitMax = 10; + this->aics[aicIndex].AttMaxAssassins = 0; + this->aics[aicIndex].AttUnit2 = 0; + this->aics[aicIndex].AttUnit2Max = 0; + this->aics[aicIndex].AttMaxLaddermen = 0; + this->aics[aicIndex].AttMaxTunnelers = 0; + this->aics[aicIndex].AttUnitPatrol = 0; + this->aics[aicIndex].AttUnitPatrolMax = 0; + this->aics[aicIndex].AttUnitPatrolGroupsCount = 0; + this->aics[aicIndex].AttUnitBackup = 0x16; + this->aics[aicIndex].AttUnitBackupMax = 0x28; + this->aics[aicIndex].AttUnitBackupGroupsCount = 1; + this->aics[aicIndex].AttUnitEngageMax = 0; + this->aics[aicIndex].AttUnitEngage = 0; + this->aics[aicIndex].AttUnitSiegeDef = 0; + this->aics[aicIndex].AttUnitSiegeDefMax = 0; + this->aics[aicIndex].AttUnitSiegeDefGroupsCount = 0; + this->aics[aicIndex].AttUnitMain1 = 0x25; + this->aics[aicIndex].AttMaxDefault = 200; + this->aics[aicIndex].AttMainGroupsCount = 2; + this->aics[aicIndex].TargetChoice = OpenSHC::AI::AIC::AITC_BALANCED; return; } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index bb7ad6a02..1007a931c 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34187,7 +34187,7 @@ SHC_3BB0A8C1_0x004CA0C0 | 82.3% | Constant store order differs SHC_3BB0A8C1_0x004CA4D0 | 74.9% | Constant store order differs -SHC_3BB0A8C1_0x004CA8A0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CA8A0 | 84.8% | Constant store order differs SHC_3BB0A8C1_0x004CAC70 | 95.2% | Reimplemented From cfafac72d6040c32e223b091dbb4c1b20909c22a Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:17:21 +0200 Subject: [PATCH 230/242] reimplement: SHC_3BB0A8C1_0x004CB1B0 100.00% Reimplemented --- .../AI/AICState/setNextFarmTypeToBuild.cpp | 18 ++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp index 471100a98..01b79f53f 100644 --- a/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp +++ b/src/OpenSHC/AI/AICState/setNextFarmTypeToBuild.cpp @@ -9,19 +9,17 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB1B0 int AICState::setNextFarmTypeToBuild(PlayerID playerID) { - int _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType == AITA_NULL) { + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == AITA_NULL) return 0; - } - _aiType += -1; - DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex += 1; - if (8 <= DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex) { + int aicIndex = aiType - 1; + + DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex++; + if (DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex >= 8) DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; - } - if ((&this->aics[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] == 0) { + if ((&this->aics[aicIndex].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex] == 0) DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex = 0; - } - return (&this->aics[_aiType].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; + return (&this->aics[aicIndex].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex]; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 1007a931c..366439f27 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34207,7 +34207,7 @@ SHC_3BB0A8C1_0x004CB150 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB180 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004CB1B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB1B0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB220 | 97.8% | Reimplemented From 6c31c49f5910ee442e72e414168869fba15ab0df Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:17:21 +0200 Subject: [PATCH 231/242] reimplement: SHC_3BB0A8C1_0x004CC7B0 95.24% Reimplemented --- .../AICState/syncBehaviourType7UnitTribes.cpp | 38 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp b/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp index 7cfb1dbdf..0a37073ba 100644 --- a/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp +++ b/src/OpenSHC/AI/AICState/syncBehaviourType7UnitTribes.cpp @@ -10,27 +10,25 @@ namespace OpenSHC { namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC7B0 - void AICState::syncBehaviourType7UnitTribes(int param_1) + void AICState::syncBehaviourType7UnitTribes(int playerID) { - int tribeID; - uint unitID = 1; - if (1 < (int)DAT_UnitsState::instance.maxUnitCount) { - Map::Units::Unit* pUVar1 = &DAT_UnitsState::instance.units[1]; - do { - if ((((pUVar1->owner == param_1) && (pUVar1->logicalState == Map::Units::ULS_NORMAL)) - && (pUVar1->dying == 0)) - && (pUVar1->aiUnitBehaviourType == 7)) { - tribeID = (int)DAT_GameState::instance.playerDataArray[param_1].aiTribeIDs[0xa7]; - if (pUVar1->tribeID != tribeID) { - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( - unitID, (int)pUVar1->tribeID); - MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( - unitID, tribeID); - } - } - unitID = unitID + 1; - pUVar1 = pUVar1 + 1; - } while ((int)unitID < (int)DAT_UnitsState::instance.maxUnitCount); + for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { + if (DAT_UnitsState::instance.units[unitID].owner != playerID) + continue; + if (DAT_UnitsState::instance.units[unitID].logicalState != Map::Units::ULS_NORMAL) + continue; + if (DAT_UnitsState::instance.units[unitID].dying != 0) + continue; + if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType != 7) + continue; + + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[167]; + if (DAT_UnitsState::instance.units[unitID].tribeID == tribeID) + continue; + + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::removeUnitFromTribe, DAT_TribesState::ptr)( + unitID, DAT_UnitsState::instance.units[unitID].tribeID); + MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 366439f27..0fe4f5cdf 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34879,7 +34879,7 @@ SHC_3BB0A8C1_0x004CC6B0 | 0.0% | Pending SHC_3BB0A8C1_0x004CC720 | 95.2% | Reimplemented -SHC_3BB0A8C1_0x004CC7B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CC7B0 | 95.2% | Reimplemented SHC_3BB0A8C1_0x004CC840 | 94.3% | Reimplemented From b292e092ef3b39a4fa03b241ee0ce304cad37daf Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:17:21 +0200 Subject: [PATCH 232/242] reimplement: SHC_3BB0A8C1_0x004CB700 100.00% Reimplemented --- status/addresses-SHC-3BB0A8C1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 0fe4f5cdf..daa6f71ee 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34501,7 +34501,7 @@ SHC_3BB0A8C1_0x004CB6FA | 0.0% | Pending SHC_3BB0A8C1_0x004CB6FB | 0.0% | Pending -SHC_3BB0A8C1_0x004CB700 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB700 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB754 | 0.0% | Pending From 77bb2d19145a25ce7fab723ea6cd1863b383eb50 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:17:22 +0200 Subject: [PATCH 233/242] reimplement: SHC_3BB0A8C1_0x004CB9F0 93.33% Reimplemented --- status/addresses-SHC-3BB0A8C1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index daa6f71ee..4b44af201 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34851,7 +34851,7 @@ SHC_3BB0A8C1_0x004CB890 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CB940 | 88.9% | Register allocation differs -SHC_3BB0A8C1_0x004CB9F0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB9F0 | 93.3% | Reimplemented SHC_3BB0A8C1_0x004CBA50 | 85.1% | Reimplemented functionally, stack and cached load differencesd From b06799f8a2c046e15aced9e54eb9b5d8ecf25b50 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:17:22 +0200 Subject: [PATCH 234/242] reimplement: SHC_3BB0A8C1_0x004CB5B0 91.30% Reimplemented --- status/addresses-SHC-3BB0A8C1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 4b44af201..5d2af7b20 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -34221,7 +34221,7 @@ SHC_3BB0A8C1_0x004CB4D0 | 97.5% | Reimplemented SHC_3BB0A8C1_0x004CB540 | 97.5% | Reimplemented -SHC_3BB0A8C1_0x004CB5B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CB5B0 | 91.3% | Reimplemented SHC_3BB0A8C1_0x004CB610 | 100.0% | Reimplemented From d82ee9535fcb8d485ea299dc6936dbd7d95721db Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:17:23 +0200 Subject: [PATCH 235/242] reimplement: SHC_3BB0A8C1_0x004D1090 90.00% Reimplemented --- status/addresses-SHC-3BB0A8C1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 5d2af7b20..a678f2aa5 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35455,7 +35455,7 @@ SHC_3BB0A8C1_0x004D1000 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D1050 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D1090 | 0.0% | Pending +SHC_3BB0A8C1_0x004D1090 | 90.0% | Reimplemented SHC_3BB0A8C1_0x004D10B0 | 100.0% | Reimplemented, one reordered push edi From 2eb1b8410d9a86e287d15cb82074a1a568172804 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 17:17:23 +0200 Subject: [PATCH 236/242] reimplement: SHC_3BB0A8C1_0x004CD7B0 76.14% Register allocation differs --- .../AI/AICState/instructTribe166ToMove.cpp | 81 +++++++++---------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 37 insertions(+), 46 deletions(-) diff --git a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp index af70756dd..972175686 100644 --- a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp +++ b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp @@ -3,7 +3,6 @@ #include "OpenSHC/Game/GameStateStructures.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/AI/AIType.hpp" -#include "OpenSHC/AI/AITypeInt.hpp" #include "OpenSHC/Map/Units/Behavior/UnitStanceEnum.hpp" #include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp" #include "OpenSHC/WindowsHelper/Enums/BOOLEnum.hpp" @@ -14,65 +13,57 @@ namespace OpenSHC { namespace AI { - using OpenSHC::AI::AIType; - using OpenSHC::AI::AITypeInt; - using OpenSHC::Map::Units::Behavior::UnitStanceEnum; - using OpenSHC::Map::Units::Instructions::UnitMatchSpeedEnum; - using OpenSHC::WindowsHelper::Enums::BOOLEnum; - // FUNCTION: STRONGHOLDCRUSADER 0x004CD7B0 - void AICState ::instructTribe166ToMove(int playerID) + void AICState::instructTribe166ToMove(int playerID) { - AITypeInt _aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (_aiType == OpenSHC::AI::AIT_NULL) + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; + if (aiType == OpenSHC::AI::AIT_NULL) return; + int aicIndex = aiType - 1; - int _counter = DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01; - if (0 < _counter) - DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 = _counter + -1; - if (50 < DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01) + if (DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 > 0) + DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01--; + if (DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 > 50) DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 = 50; - int _tribeID = (int)DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; - BOOLEnum _keepEnclosed = MACRO_CALL_MEMBER( - OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); - - if (_tribeID == 0) + int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; + BOOLEnum keepEnclosed + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + if (tribeID == 0) return; - if (DAT_TribesState::instance.tribes[_tribeID].uid - != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0xa6]) + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[166]) return; - if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 + -5) + if (DAT_TribesState::instance.tribes[tribeID].size + < DAT_GameState::instance.playerDataArray[playerID].totalTroopsType6 - 5) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitsToTribe166, this)(playerID); - if ((DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker < 1) - || (_keepEnclosed != FALSE)) { + if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0 && keepEnclosed == FALSE) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + return; + } - if ((int)DAT_TribesState::instance.tribes[_tribeID].size - < *(int*)((int)this + (_aiType + ~OpenSHC::AI::AIT_NULL) * 0x2a4 + 0x14c)) { - // tribe too small: just set stance - DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - return; - } + if (DAT_TribesState::instance.tribes[tribeID].size < this->aics[aicIndex].SortieUnitRangedMin) { + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + return; + } - if ((0 < DAT_GameState::instance.playerDataArray[playerID].someXPosition) - && (0 < DAT_GameState::instance.playerDataArray[playerID].someYPosition)) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, - DAT_TribesState::ptr)(_tribeID); - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(_tribeID, - (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someXPosition)), - (uint)((int)(DAT_GameState::instance.playerDataArray[playerID].someYPosition)), 0, 0, - OpenSHC::Map::Units::Instructions::UMSE_0); - DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; - return; - } + if (DAT_GameState::instance.playerDataArray[playerID].someXPosition <= 0 + || DAT_GameState::instance.playerDataArray[playerID].someYPosition <= 0) { + MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + return; } - MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(_tribeID, playerID); - DAT_TribesState::instance.tribes[_tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)( + tribeID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, DAT_GameState::instance.playerDataArray[playerID].someXPosition, + DAT_GameState::instance.playerDataArray[playerID].someYPosition, 0, 0, + OpenSHC::Map::Units::Instructions::UMSE_0); + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a678f2aa5..17b4311f3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35279,7 +35279,7 @@ SHC_3BB0A8C1_0x004CD560 | 95.2% | Reimplemented SHC_3BB0A8C1_0x004CD690 | 94.9% | Reimplemented -SHC_3BB0A8C1_0x004CD7B0 | 0.0% | Pending +SHC_3BB0A8C1_0x004CD7B0 | 76.1% | Register allocation differs SHC_3BB0A8C1_0x004CD8F0 | 74.2% | Register allocation differs From 8569de1baf278591190d3ac090ace0a78dc5a4de Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 19:26:29 +0200 Subject: [PATCH 237/242] reimplement: SHC_3BB0A8C1_0x004CDF10 98.15% Reimplemented --- .../AICState/setCurrentAttackRaidParameter.cpp | 17 ++++++++--------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp index c53378ce5..0260e5f2c 100644 --- a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp +++ b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp @@ -12,25 +12,24 @@ namespace AI { void AICState::setCurrentAttackRaidParameter(int playerID) { int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (aiType == AITA_NULL) { + if (aiType == AITA_NULL) return; - } + int aicIndex = aiType - 1; int randomPercent = SEC_RNG::instance.currentNumber2 % 100; MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); - int raidUnits = this->aics[aiType - 1].RaidUnitsRandom; - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] < 1000) { + int attackedPlayerID = DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk; + int raidUnits = this->aics[aicIndex].RaidUnitsRandom; + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] < 1000) { raidUnits = 0; - } else if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] >= 5000) { + } else if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] >= 5000) { raidUnits *= 2; } - if (DAT_GameState::instance - .playerDataArray[DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk] - .currentResources[0xf] + if (DAT_GameState::instance.playerDataArray[attackedPlayerID].currentResources[Game::Resources::RT_GOLD] < 500) { - raidUnits = -(this->aics[aiType - 1].RaidUnitsBase / 2); + raidUnits = -(this->aics[aicIndex].RaidUnitsBase / 2); } DAT_GameState::instance.playerDataArray[playerID].currentAttackRaidParameter diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 17b4311f3..52316d974 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35297,7 +35297,7 @@ SHC_3BB0A8C1_0x004CDCF0 | 41.8% | Register allocation differs SHC_3BB0A8C1_0x004CDE60 | 76.09% | Reimplemented functionally different register usage -SHC_3BB0A8C1_0x004CDF10 | 72.0% | Reimplemented functionally, same different register usage as above +SHC_3BB0A8C1_0x004CDF10 | 98.2% | Reimplemented SHC_3BB0A8C1_0x004CDFD0 | 100.0% | Reimplemented From ac81515a7587e7a43c4a31c5cd439dda03b8507a Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 19:26:29 +0200 Subject: [PATCH 238/242] reimplement: SHC_3BB0A8C1_0x004CDE60 76.09% AIC index folding differs --- .../AI/AICState/setCurrentAttackStrength.cpp | 13 +++++-------- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp index 6f3b346e7..90217ac8e 100644 --- a/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp +++ b/src/OpenSHC/AI/AICState/setCurrentAttackStrength.cpp @@ -12,20 +12,17 @@ namespace AI { void AICState::setCurrentAttackStrength(int playerID) { int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; - if (aiType == AITA_NULL) { + if (aiType == AITA_NULL) return; - } - - aiType -= 1; - + int aicIndex = aiType - 1; int randomPercent = SEC_RNG::instance.currentNumber2 % 100; MACRO_CALL_MEMBER(Random::RNG_Func::nextRandomNumber2, SEC_RNG::ptr)(); DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength - = (this->aics[aiType].AttForceRandom * randomPercent) / 100; - DAT_GameState::instance.playerDataArray[playerID].currentAttackWave += 1; + = (this->aics[aicIndex].AttForceRandom * randomPercent) / 100; + DAT_GameState::instance.playerDataArray[playerID].currentAttackWave++; - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[0xf] > 10000) { + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] > 10000) { DAT_GameState::instance.playerDataArray[playerID].currentWaveRandomAttackingStrength += DAT_GameState::instance.playerDataArray[playerID].currentAttackWave * 7; } else { diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 52316d974..007c77be3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35295,7 +35295,7 @@ SHC_3BB0A8C1_0x004CDCA0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004CDCF0 | 41.8% | Register allocation differs -SHC_3BB0A8C1_0x004CDE60 | 76.09% | Reimplemented functionally different register usage +SHC_3BB0A8C1_0x004CDE60 | 76.1% | AIC index folding differs SHC_3BB0A8C1_0x004CDF10 | 98.2% | Reimplemented From 69122979ff7de181e9fe65cb18bfa60880d309e5 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 19:26:30 +0200 Subject: [PATCH 239/242] reimplement: SHC_3BB0A8C1_0x004D0B10 68.00% Load scheduling differs --- src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp | 4 ++-- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp index 3f9d7334b..403a03302 100644 --- a/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playNervous2BikFromPlayer.cpp @@ -20,7 +20,7 @@ namespace AI { return; } - int aicIndex = DAT_GameState::instance.playerDataArray[playerID].aiType - 1; + int aiType = DAT_GameState::instance.playerDataArray[playerID].aiType; int currentPlayerID = DAT_GameSynchronyState::instance.currentPlayerSlotID; DAT_GameState::instance.playerDataArray[playerID].nervousBikCountdown = 48; if (DAT_GameState::instance.mapAndTime.playerTeams[playerID] @@ -29,7 +29,7 @@ namespace AI { } MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( - playerID, aicIndex, 9); + playerID, aiType - 1, 9); } } } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 007c77be3..515965d6e 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35421,7 +35421,7 @@ SHC_3BB0A8C1_0x004D0A20 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004D0A80 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004D0B10 | 68.0% | Register scheduling issued +SHC_3BB0A8C1_0x004D0B10 | 68.0% | Load scheduling differs SHC_3BB0A8C1_0x004D0B70 | 100.0% | Reimplemented From ff586158f7f07bfb596f0cc3277a3936f458820a Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 19:31:48 +0200 Subject: [PATCH 240/242] progres --- .../AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp index c3816ae7b..a7af36538 100644 --- a/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp +++ b/src/OpenSHC/AI/AICState/percentageNonMovingTribesGTEAICSpecified.cpp @@ -52,7 +52,7 @@ namespace AI { return FALSE; } - return (BOOLEnum)(notReallyMoving * 100 / tribeTotal >= this->aics[aicIndex].AttMovingTribesThreshold); + return notReallyMoving * 100 / tribeTotal >= this->aics[aicIndex].AttMovingTribesThreshold; } } From 554ff498cf4213e5d5014c1e65eaaa6a938e9ce7 Mon Sep 17 00:00:00 2001 From: Gynt Date: Tue, 22 Sep 2026 19:58:22 +0200 Subject: [PATCH 241/242] reimplement: SHC_3BB0A8C1_0x004D1D60 57.99% Register allocation differs --- src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 10 +++++++--- status/addresses-SHC-3BB0A8C1.txt | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp index 535e504ae..9374bef8a 100644 --- a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -5,6 +5,7 @@ #include "OpenSHC/AI/Trading/AIResourceTradeCategory.hpp" #include "OpenSHC/AI/Trading/AIResourceTradeCategoryInt.hpp" #include "OpenSHC/AI/Trading/ResourceAICResourceMappingEntry.hpp" +#include "OpenSHC/Game/Player/PlayerData.hpp" #include "OpenSHC/Game/Resources/ResourceType.hpp" #include "OpenSHC/Globals/DAT_GameState.hpp" @@ -19,6 +20,7 @@ namespace AI { using OpenSHC::AI::Trading::AIResourceTradeCategory; using OpenSHC::AI::Trading::AIResourceTradeCategoryInt; using OpenSHC::AI::Trading::ResourceAICResourceMappingEntry; + using OpenSHC::Game::Player::PlayerData; using OpenSHC::Game::Resources::ResourceType; // FUNCTION: STRONGHOLDCRUSADER 0x004D1D60 @@ -30,12 +32,14 @@ namespace AI { } int aicIndex = aiType - 1; + int playerResourceBase = playerID * (sizeof(PlayerData) / sizeof(int)); int nervousActions = DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker; for (int i = 0; i < 20; i++) { ResourceType resourceType = (ResourceType)DAT_SkirmishDefinedData::instance.AIResourceTradeAICMapping[i].game; int category = DAT_SkirmishDefinedData::instance.AIResourceTradeAICMapping[i].aic; int variance = this->aics[aicIndex].maxResourceVariance; + int resourceOffset = (playerResourceBase + resourceType) * sizeof(int); int amount; if (category == OpenSHC::AI::Trading::AIRTC_WOOD) { @@ -75,7 +79,7 @@ namespace AI { } variance = 0; } else { - amount += DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType]; + amount += *(int*)((char*)DAT_GameState::instance.playerDataArray[0].resourcesToAcquireArray + resourceOffset); } // Resources the AIC always sells are kept at zero @@ -87,9 +91,9 @@ namespace AI { } } - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType] > amount) { + if (*(int*)((char*)DAT_GameState::instance.playerDataArray[0].currentResources + resourceOffset) > amount) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellGoods, this)(playerID, resourceType, - DAT_GameState::instance.playerDataArray[playerID].currentResources[resourceType] - amount + ((int*)DAT_GameState::instance.playerDataArray[0].currentResources)[playerResourceBase + resourceType] - amount + variance); return; } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index 515965d6e..a51ca345a 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -35475,7 +35475,7 @@ SHC_3BB0A8C1_0x004D1950 | 98.0% | Reimplemented SHC_3BB0A8C1_0x004D1A00 | 58.0% | Register allocation differs -SHC_3BB0A8C1_0x004D1D60 | 52.5% | Stuck +SHC_3BB0A8C1_0x004D1D60 | 58.0% | Register allocation differs SHC_3BB0A8C1_0x004D1F00 | 100.0% | Reimplemented From 023be2c5fc325f4782a3e7835e0d738b856a3f3b Mon Sep 17 00:00:00 2001 From: Gynt Date: Wed, 23 Sep 2026 11:04:40 +0200 Subject: [PATCH 242/242] repair formatting issues --- .../AI/AICState/addEngineersToSelection.cpp | 3 +- .../AI/AICState/addRallyPointForTribe.cpp | 3 +- src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp | 4 +- .../AICState/aiAddUnitToMoatDiggerTribe.cpp | 9 +- .../AI/AICState/aiAssignMoatDiggers.cpp | 17 +- .../AICState/aiCommandSiegeEngineTribes.cpp | 13 +- .../aiCommandTribe11StandGroundToGate.cpp | 9 +- .../aiCommandTribe12AggressiveApproach.cpp | 7 +- .../aiCommandTribe13DefensiveWave.cpp | 3 +- .../AI/AICState/aiCreateSiegeUnits.cpp | 160 ++++++++++++------ .../AI/AICState/aiGiveOuterPatrolCommand.cpp | 3 +- .../AI/AICState/aiGiveRaidInstructions.cpp | 44 ++--- .../AICState/aiRecruitEngineerForOilDuty.cpp | 12 +- .../AI/AICState/aiRecruitSortieMeleeUnits.cpp | 3 +- src/OpenSHC/AI/AICState/aiRecruitUnits.cpp | 35 ++-- .../AI/AICState/aiRequiresExtraOxtethers.cpp | 16 +- .../AI/AICState/aiShouldBuildIronMine.cpp | 4 +- .../AI/AICState/aiShouldBuildPitchrig.cpp | 4 +- .../AI/AICState/aiShouldBuildQuarry.cpp | 4 +- .../AI/AICState/aiShouldBuildWoodcutter.cpp | 4 +- .../AI/AICState/aiUpdateTaxesAndRations.cpp | 3 +- .../assignRequiredIdleEngineersToNewTribe.cpp | 3 +- src/OpenSHC/AI/AICState/buyRequiredGoods.cpp | 3 +- .../canNavigateUnitsFromTileToTargetTile.cpp | 8 +- .../clearRallyFlagOnAllAIAttackTribes.cpp | 4 +- .../AICState/computeEnemyKeepApproachTile.cpp | 8 +- .../AI/AICState/computeNervousness.cpp | 3 +- .../AICState/decideOnTribeAttackLocation.cpp | 45 ++--- .../AICState/destroyAnyBuildingInCategory.cpp | 70 ++++++-- ...determineAIPlayerAttackRequestResponse.cpp | 6 +- .../AI/AICState/determineAIPlayerHelp.cpp | 6 +- src/OpenSHC/AI/AICState/digNearestMoat.cpp | 14 +- ...ndAttackTribePositionAndPathToDefenses.cpp | 2 +- .../generateSiegeCreationInformation.cpp | 4 +- .../AI/AICState/getDefensiveTribeForUnit.cpp | 3 +- .../AI/AICState/getSmallestPatrolTribe.cpp | 5 +- .../getUnitTypeForUnitBehaviourType.cpp | 3 +- .../giveMoveCommandToAttackTribes.cpp | 10 +- .../AICState/giveMoveCommandToSortieUnits.cpp | 17 +- .../AI/AICState/giveSomeRaidCommand.cpp | 12 +- .../AICState/ifHasTribe0SendUnitsToKeep.cpp | 3 +- .../AI/AICState/instructTribe166ToMove.cpp | 4 +- ...eUnitsGoDefensiveAndBackToSomeLocation.cpp | 5 +- .../AICState/moveAttackTribesToLocations.cpp | 10 +- ...yerKilledBiksFromKilledAndKillerPlayer.cpp | 6 +- .../recomputeAIPathCostToAttackedKeep.cpp | 8 +- .../recruitHarrassingSiegeEngines.cpp | 10 +- ...oveOrganismsAndSetMoveDestinationPairs.cpp | 14 +- .../AI/AICState/selectAttackTarget.cpp | 4 +- src/OpenSHC/AI/AICState/sellExcessGoods.cpp | 8 +- ...oAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp | 17 +- ...sendOilMenForOilPickupOrToAIVLocations.cpp | 4 +- ...gedUnitTribesToAIVSlotsOrKeepIfNervous.cpp | 17 +- .../sendUnitsToAttackBreachedCastle.cpp | 14 +- .../sendUnitsToPlayerIDsKeepIfPossible.cpp | 3 +- ...sendWallPatrolUnitTribesToAIVLocations.cpp | 20 +-- .../AI/AICState/setAICParameters_10.cpp | 1 + .../AI/AICState/setAICParameters_12.cpp | 1 + .../AI/AICState/setAICParameters_14.cpp | 1 + .../AI/AICState/setAttackPrimeInfo.cpp | 7 +- .../setCurrentAttackRaidParameter.cpp | 3 +- .../AICState/setNextMoveLocationForUnits.cpp | 14 +- .../AICState/setupWorkshopProductionType.cpp | 12 +- .../AICState/shouldDestroyWoodCutterUnk.cpp | 2 +- .../AI/AICState/smallestTribeOfUnitType.cpp | 4 +- .../AI/AICState/someChatMessageSelection.cpp | 8 +- .../AI/AICState/teamIsWeakRelativeToEnemy.cpp | 6 +- 67 files changed, 471 insertions(+), 321 deletions(-) diff --git a/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp b/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp index 7466c7338..3aae5e97a 100644 --- a/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp +++ b/src/OpenSHC/AI/AICState/addEngineersToSelection.cpp @@ -14,7 +14,8 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC680 int AICState::addEngineersToSelection(int playerID, int unitCount) { - int tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + int tribeID + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { if (unitCount <= 0) return tribeID; diff --git a/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp b/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp index 241944136..5a8527736 100644 --- a/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp +++ b/src/OpenSHC/AI/AICState/addRallyPointForTribe.cpp @@ -33,7 +33,8 @@ namespace AI { continue; MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeNextRallyPointDestination, - DAT_PathFindingState::ptr)(-1, DAT_UnitsState::instance.units[unitID].x, DAT_UnitsState::instance.units[unitID].y); + DAT_PathFindingState::ptr)( + -1, DAT_UnitsState::instance.units[unitID].x, DAT_UnitsState::instance.units[unitID].y); DAT_TribesState::instance.tribes[tribeID] .rallyPointArray[DAT_TribesState::instance.tribes[tribeID].rallyPointCount][0] = DAT_PathFindingState::instance.ALG_ResultX; diff --git a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp index cf99d0e24..0cf637150 100644 --- a/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp +++ b/src/OpenSHC/AI/AICState/addUnitToItsTribe.cpp @@ -18,8 +18,8 @@ namespace AI { return; DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = aiUnitBehaviourType; - int tribeID - = MACRO_CALL_MEMBER(AICState_Func::addUnitToSmallestBehaviourTypeTribe, this)(owner, unitID, aiUnitBehaviourType); + int tribeID = MACRO_CALL_MEMBER(AICState_Func::addUnitToSmallestBehaviourTypeTribe, this)( + owner, unitID, aiUnitBehaviourType); if (tribeID != 0) MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); } diff --git a/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp index 3db77b3cc..4857156f9 100644 --- a/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp +++ b/src/OpenSHC/AI/AICState/aiAddUnitToMoatDiggerTribe.cpp @@ -16,10 +16,13 @@ namespace AI { DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 5; int tribeID = DAT_GameState::instance.playerDataArray[owner].aiTribeIDs[10]; if (tribeID == 0 - || DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[owner].aiTribeUIDs[10]) { - tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(owner); + || DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[owner].aiTribeUIDs[10]) { + tribeID + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(owner); DAT_GameState::instance.playerDataArray[owner].aiTribeIDs[10] = tribeID; - DAT_GameState::instance.playerDataArray[owner].aiTribeUIDs[10] = DAT_TribesState::instance.tribes[tribeID].uid; + DAT_GameState::instance.playerDataArray[owner].aiTribeUIDs[10] + = DAT_TribesState::instance.tribes[tribeID].uid; } MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_DEFENSIVE; diff --git a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp index ea2a93c40..6821d3933 100644 --- a/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp +++ b/src/OpenSHC/AI/AICState/aiAssignMoatDiggers.cpp @@ -34,13 +34,22 @@ namespace AI { if (DAT_UnitsState::instance.units[unitID].dying != 0) continue; - if (DAT_UnitsState::instance.units[unitID].unitType == UT_LORD || DAT_UnitsState::instance.units[unitID].unitType == UT_E_ENGINEER || DAT_UnitsState::instance.units[unitID].unitType == UT_TUNNELER || DAT_UnitsState::instance.units[unitID].unitType == UT_S_CATAPULT - || DAT_UnitsState::instance.units[unitID].unitType == UT_S_TREBUCHET || DAT_UnitsState::instance.units[unitID].unitType == UT_S_MANGONEL || DAT_UnitsState::instance.units[unitID].unitType == UT_S_TOWER - || DAT_UnitsState::instance.units[unitID].unitType == UT_S_BATTERINGRAM || DAT_UnitsState::instance.units[unitID].unitType == UT_S_SHIELD || DAT_UnitsState::instance.units[unitID].unitType == UT_S_BALLISTA + if (DAT_UnitsState::instance.units[unitID].unitType == UT_LORD + || DAT_UnitsState::instance.units[unitID].unitType == UT_E_ENGINEER + || DAT_UnitsState::instance.units[unitID].unitType == UT_TUNNELER + || DAT_UnitsState::instance.units[unitID].unitType == UT_S_CATAPULT + || DAT_UnitsState::instance.units[unitID].unitType == UT_S_TREBUCHET + || DAT_UnitsState::instance.units[unitID].unitType == UT_S_MANGONEL + || DAT_UnitsState::instance.units[unitID].unitType == UT_S_TOWER + || DAT_UnitsState::instance.units[unitID].unitType == UT_S_BATTERINGRAM + || DAT_UnitsState::instance.units[unitID].unitType == UT_S_SHIELD + || DAT_UnitsState::instance.units[unitID].unitType == UT_S_BALLISTA || DAT_UnitsState::instance.units[unitID].unitType == UT_S_FBALLISTA) continue; - if (this->aics[aicIndex].DefDiggingUnitMax == 0 || DAT_UnitsState::instance.units[unitID].unitType == UT_E_ARCHER || DAT_UnitsState::instance.units[unitID].unitType == UT_E_XBOW + if (this->aics[aicIndex].DefDiggingUnitMax == 0 + || DAT_UnitsState::instance.units[unitID].unitType == UT_E_ARCHER + || DAT_UnitsState::instance.units[unitID].unitType == UT_E_XBOW || DAT_UnitsState::instance.units[unitID].someUnitStat4 == 0) MACRO_CALL_MEMBER(AICState_Func::assignUnitToATribe, this)(unitID); else diff --git a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp index 42e6b8588..8032d413f 100644 --- a/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp @@ -56,11 +56,13 @@ namespace AI { continue; if (DAT_UnitsState::instance.units[unitID].unitType == UT_S_TOWER) { - if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc - 4) != 0) + if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc - 4) + != 0) MACRO_CALL_MEMBER(TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( tribeID, STBT_0x414); } else if (DAT_UnitsState::instance.units[unitID].unitType == UT_S_BATTERINGRAM) { - if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.gateValuesArray + playerID * 0x177bc - 4) != 0) + if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.gateValuesArray + playerID * 0x177bc - 4) + != 0) MACRO_CALL_MEMBER(TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)( tribeID, STBT_0x3f6); else if (*(int*)((int)DAT_TroopValueState::instance.attackInfo.wideValuesArray + playerID * 0x177bc - 4) @@ -87,9 +89,10 @@ namespace AI { tribeID, x, y, 0, 0, Instructions::UMSE_0); MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::calculatePreferredRelativeOrientation, - DAT_DirectionAlgorithmState::ptr)( - DAT_UnitsState::instance.units[targetUnitID].x, DAT_UnitsState::instance.units[targetUnitID].y, x, y); - DAT_TribesState::instance.tribes[tribeID].orientation = DAT_DirectionAlgorithmState::instance.orientation; + DAT_DirectionAlgorithmState::ptr)(DAT_UnitsState::instance.units[targetUnitID].x, + DAT_UnitsState::instance.units[targetUnitID].y, x, y); + DAT_TribesState::instance.tribes[tribeID].orientation + = DAT_DirectionAlgorithmState::instance.orientation; } } } diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp index 5d8597354..f4f46c614 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp @@ -18,15 +18,18 @@ namespace AI { int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[11]; if (tribeID == 0) return; - if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[11]) + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[11]) return; if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) return; DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_STAND_GROUND; - if (MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)(tribeID) + if (MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)( + tribeID) == 0) - MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)(tribeID); + MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)( + tribeID); } } } diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp index c217fd2e4..b82c43b75 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe12AggressiveApproach.cpp @@ -22,7 +22,8 @@ namespace AI { int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[12]; if (tribeID == 0) return; - if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[12]) + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[12]) return; int targetUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; if (targetUnitID == 0) @@ -48,8 +49,8 @@ namespace AI { == FALSE) return; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(tribeID, - DAT_PathFindingState::instance.ALG_ResultX, DAT_PathFindingState::instance.ALG_ResultY, 0, 0, + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( + tribeID, DAT_PathFindingState::instance.ALG_ResultX, DAT_PathFindingState::instance.ALG_ResultY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); } diff --git a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp index 37cd28012..b921b42ae 100644 --- a/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp +++ b/src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp @@ -18,7 +18,8 @@ namespace AI { int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[13]; if (tribeID == 0) return; - if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[13]) + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[13]) return; if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) return; diff --git a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp index ac16c8c01..7e51f30d5 100644 --- a/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiCreateSiegeUnits.cpp @@ -45,9 +45,11 @@ namespace AI { // The original also processes index 4, one past the end of SiegeEngineMetaInfoArray. for (int siegeIndex = 0; siegeIndex < 5; siegeIndex++) { - UnitType unitType = (UnitType)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].unitType; + UnitType unitType + = (UnitType)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].unitType; int slot = DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].slot; - int locationCount = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[slot]; + int locationCount + = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[slot]; if (locationCount >= 4) locationCount = 3; @@ -57,25 +59,39 @@ namespace AI { continue; int existingBuildingID = (short)DAT_TileMapState::instance.BuildingLayer[location]; - int unitID = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID; - int uid = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid; - int buildingID - = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID; + int unitID = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[siegeIndex][i] + .unitID; + int uid + = DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid; + int buildingID = DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[siegeIndex][i] + .buildingID; if (unitID != 0 && DAT_UnitsState::instance.units[unitID].uid != uid) { - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID + = 0; DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unknown = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay + = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unknown + = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[siegeIndex][i] + .buildingID = 0; continue; } if (buildingID != 0 && DAT_BuildingsState::instance.buildings[buildingID].uid != uid) { - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID + = 0; DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unknown = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay + = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unknown + = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[siegeIndex][i] + .buildingID = 0; continue; } @@ -84,19 +100,23 @@ namespace AI { int requiredEngineers = MACRO_CALL_MEMBER( OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, DAT_BuildingsState::ptr)(buildingID); - if (DAT_BuildingsState::instance.buildings[buildingID].currentEmployeeCount == requiredEngineers) + if (DAT_BuildingsState::instance.buildings[buildingID].currentEmployeeCount + == requiredEngineers) continue; - if (requiredEngineers > DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { + if (requiredEngineers + > DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; continue; } - int tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)( - playerID, requiredEngineers); + int tribeID + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, + this)(playerID, requiredEngineers); DAT_TribesState::instance.tribes[tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; DAT_TribesState::instance.tribes[tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( - tribeID, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, buildingID, + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, + DAT_TribesState::ptr)(tribeID, + OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, buildingID, DAT_BuildingsState::instance.buildings[buildingID].uid, 0); return; } @@ -105,53 +125,73 @@ namespace AI { if (siegeIndex < 2) continue; } else if (siegeIndex < 2) { - if (DAT_BuildingsState::instance.buildings[existingBuildingID].buildingType != OpenSHC::Map::Buildings::BT_TOWER4 + if (DAT_BuildingsState::instance.buildings[existingBuildingID].buildingType + != OpenSHC::Map::Buildings::BT_TOWER4 && DAT_BuildingsState::instance.buildings[existingBuildingID].buildingType != OpenSHC::Map::Buildings::BT_TOWER5) continue; } - int requiredGold = DAT_BuildingsState::instance - .buildingCosts[DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].buildingType] - .requiredGold; + int requiredGold + = DAT_BuildingsState::instance + .buildingCosts[DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex] + .buildingType] + .requiredGold; DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay++; if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] + this->aics[aiType - 1].defSiegeEngineGoldThreshold < requiredGold) continue; - if (DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay + if (DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[siegeIndex][i] + .delay < this->aics[aiType - 1].defSiegeEngineBuildDelay) continue; int y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[location]; int x = location - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile; if (siegeIndex < 2) { - int spawnedUnitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::spawnUnit, DAT_UnitsState::ptr)( - playerID, playerID, x * 8 + 4, y * 8 + 4, + int spawnedUnitID = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::spawnUnit, + DAT_UnitsState::ptr)(playerID, playerID, x * 8 + 4, y * 8 + 4, DAT_BuildingsState::instance.buildings[existingBuildingID].terrainHeightUnk, unitType); - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID - = spawnedUnitID; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[siegeIndex][i] + .unitID = spawnedUnitID; DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid = DAT_UnitsState::instance.units[spawnedUnitID].uid; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID = 0; - MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::processPlacementResourceLossForBuildingType, + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[siegeIndex][i] + .buildingID = 0; + MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::processPlacementResourceLossForBuildingType, DAT_BuildingsState::ptr)(playerID, - (BuildingType)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex].buildingType, 0); + (BuildingType)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex] + .buildingType, + 0); } else { - MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID, x, y, + MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)( + playerID, x, y, (MappersEnum)(ushort)DAT_SkirmishDefinedData::instance.SiegeEngineMetaInfoArray[siegeIndex] .commandBuildingType, 3, 15); if (DAT_TileMapState::instance.buildingPlacementFail == FALSE) { - DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] -= requiredGold; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].unitID = 0; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].uid - = DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.placedBuildingID].uid; - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID - = DAT_TileMapState::instance.placedBuildingID; + DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] + -= requiredGold; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[siegeIndex][i] + .unitID = 0; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[siegeIndex][i] + .uid + = DAT_BuildingsState::instance.buildings[DAT_TileMapState::instance.placedBuildingID] + .uid; + DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[siegeIndex][i] + .buildingID = DAT_TileMapState::instance.placedBuildingID; } } - DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay = 0; + DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].delay + = 0; return; } @@ -160,47 +200,55 @@ namespace AI { int requiredEngineers = MACRO_CALL_MEMBER( OpenSHC::Map::Buildings::BuildingsState_Func::getRequiredEngineerCountForSiegeBuilding, DAT_BuildingsState::ptr)(buildingID); - if (DAT_BuildingsState::instance.buildings[buildingID].currentEmployeeCount == requiredEngineers) + if (DAT_BuildingsState::instance.buildings[buildingID].currentEmployeeCount + == requiredEngineers) continue; - if (requiredEngineers > DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { + if (requiredEngineers + > DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated) { DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; continue; } - int tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)( - playerID, requiredEngineers); + int tribeID + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, + this)(playerID, requiredEngineers); DAT_TribesState::instance.tribes[tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; DAT_TribesState::instance.tribes[tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x410_SIEGE_EQUIPMENT_CONSTRUCTION; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)( - tribeID, OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, buildingID, + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeAnInstruction, + DAT_TribesState::ptr)(tribeID, + OpenSHC::Map::Units::UIT_CONSTRUCT_SIEGE_EQUIPMENTOIL_DUTYENGINEERRELATED, buildingID, DAT_BuildingsState::instance.buildings[buildingID].uid, 0); return; } - int remainingEngineers = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, - DAT_UnitsState::ptr)(unitID); + int remainingEngineers + = MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getRemainingRequiredEngineers, + DAT_UnitsState::ptr)(unitID); if (remainingEngineers <= 0) continue; if (DAT_GameState::instance.playerDataArray[playerID].engineerCountRelated < remainingEngineers) { DAT_GameState::instance.playerDataArray[playerID].isEngineerRequired = TRUE; continue; } - int tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, this)( - playerID, remainingEngineers); + int tribeID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignRequiredIdleEngineersToNewTribe, + this)(playerID, remainingEngineers); int targetUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; if (targetUnitID == 0) continue; - if (MACRO_CALL_MEMBER( - OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, + if (MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func:: + calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)(playerID, - (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[unitID].tile], - (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[targetUnitID].tile], + (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance.units[unitID].tile], + (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance.units[targetUnitID].tile], 0) == 0) continue; DAT_TribesState::instance.tribes[tribeID].tribeType = OpenSHC::AI::Tribes::AITT_ENGINEERS; DAT_TribesState::instance.tribes[tribeID].tribeBehaviorType = OpenSHC::Map::Units::STBT_0x41c; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(tribeID, - OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, unitID, DAT_UnitsState::instance.units[unitID].uid, 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + tribeID, OpenSHC::Map::Units::UIT_MAN_SIEGE_EQUIPMENT, unitID, + DAT_UnitsState::instance.units[unitID].uid, 0); return; } } diff --git a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp index 26d070116..1e8ad2f21 100644 --- a/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveOuterPatrolCommand.cpp @@ -70,7 +70,8 @@ namespace AI { MACRO_CALL_MEMBER(Map::Units::TribesState_Func::commandUnitsToLocation, DAT_TribesState::ptr)( tribeID, x, y, 0); else - MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(tribeID, playerID); } + MACRO_CALL_MEMBER(AICState_Func::sendUnitsToCampfire, this)(tribeID, playerID); + } } } } diff --git a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp index 22f418b16..2f1047fba 100644 --- a/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp +++ b/src/OpenSHC/AI/AICState/aiGiveRaidInstructions.cpp @@ -49,40 +49,43 @@ namespace AI { != 0) { if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter != 0) continue; - buildingID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, - this)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk, i); + buildingID + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, + this)(DAT_GameState::instance.playerDataArray[playerID].playerID_askerUnk, i); if (buildingID == 0) - buildingID - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); } else if (DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown == 0 - && DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk - < MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( - aicIndex, playerID)) { + && DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk < MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(aicIndex, playerID)) { if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter != 0) continue; if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)(tribeID, i, TRUE) != FALSE) continue; - buildingID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, - this)(playerID, i); + buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, this)(playerID, i); if (buildingID == 0) - buildingID - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); + buildingID = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::selectBuildingFromAListOfBuildingTypes, this)(playerID); } else if (DAT_SkirmishDefinedData::instance.TribeTypeID[i] == 182 || DAT_SkirmishDefinedData::instance.TribeTypeID[i] == 181) { if (DAT_GameState::instance.playerDataArray[playerID].raidRetargetDelayCounter != 0) continue; - if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)(tribeID, i, FALSE) + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)( + tribeID, i, FALSE) != FALSE) continue; - buildingID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, - this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk, i); + buildingID + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::selectRandomBuildingIDFromListOfBuildingTypes, + this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk, i); if (buildingID == 0) buildingID = MACRO_CALL_MEMBER( OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)( DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); } else { - if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)(tribeID, i, FALSE) + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)( + tribeID, i, FALSE) != FALSE) continue; @@ -91,7 +94,8 @@ namespace AI { && DAT_BuildingsState::instance.buildings[targetBuildingID].uid == DAT_TribesState::instance.tribes[tribeID].targetBuildingUID && DAT_BuildingsState::instance.buildings[targetBuildingID].fireDuration == 0 - && MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)(tribeID, i, TRUE) + && MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::checkTribeActivityPercentages, this)( + tribeID, i, TRUE) != FALSE) { if (DAT_GameState::instance.mapAndTime.yearChanged != 0) DAT_TribesState::instance.tribes[tribeID].targetBuildingID = 0; @@ -100,15 +104,15 @@ namespace AI { } targetBuildingID - = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)( - DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, + this)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID_2Unk); if (targetBuildingID == 0) { DAT_TribesState::instance.tribes[tribeID].targetBuildingID = 0; DAT_GameState::instance.playerDataArray[playerID].someTotalDefenseTroopsRelatedCountdown = 0; continue; } - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(tribeID, - OpenSHC::Map::Units::UIT_ATTACK_BUILDING, targetBuildingID, + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + tribeID, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, targetBuildingID, DAT_BuildingsState::instance.buildings[targetBuildingID].uid, 0); DAT_TribesState::instance.tribes[tribeID].targetBuildingID = targetBuildingID; DAT_TribesState::instance.tribes[tribeID].targetBuildingUID diff --git a/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp index 8970c828b..8c7e889a5 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitEngineerForOilDuty.cpp @@ -1,6 +1,6 @@ +#include "OpenSHC/AI/AICState.func.hpp" #include "OpenSHC/Map/Units/TribesState.func.hpp" #include "OpenSHC/Map/Units/UnitsState.func.hpp" -#include "OpenSHC/AI/AICState.func.hpp" #include "OpenSHC/AI/AITypeA.hpp" #include "OpenSHC/AI/Tribes/AITribeType.hpp" #include "OpenSHC/Map/Buildings/BuildingType.hpp" @@ -45,14 +45,16 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[Game::Resources::RT_PITCH] = 4; return; } - if (MACRO_CALL_MEMBER(AICState_Func::checksAndGenerateAITribesForPlayerIfNotExisting, this)(playerID, amount, TRUE) + if (MACRO_CALL_MEMBER(AICState_Func::checksAndGenerateAITribesForPlayerIfNotExisting, this)( + playerID, amount, TRUE) == FALSE) return; - int tribeID - = MACRO_CALL_MEMBER(AICState_Func::checksAndGenerateAITribesForPlayerIfNotExisting, this)(playerID, amount, FALSE); + int tribeID = MACRO_CALL_MEMBER(AICState_Func::checksAndGenerateAITribesForPlayerIfNotExisting, this)( + playerID, amount, FALSE); int unitID = MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::nonEuroRecruit, DAT_UnitsState::ptr)( - Map::Units::UT_E_ENGINEER, DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, playerID, 0); + Map::Units::UT_E_ENGINEER, DAT_GameState::instance.playerDataArray[playerID].engineersGuild.id, playerID, + 0); MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID); if (unitID == 0) return; diff --git a/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp index 4326ee098..c3ae30af2 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitSortieMeleeUnits.cpp @@ -23,7 +23,8 @@ namespace AI { int aicIndex = aiType - 1; if (this->aics[aicIndex].SortieUnitMeleeMin < 0) return; - if (DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 >= this->aics[aicIndex].SortieUnitMeleeMin) + if (DAT_GameState::instance.playerDataArray[playerID].totalTroopsType7 + >= this->aics[aicIndex].SortieUnitMeleeMin) return; if (DAT_GameState::instance.playerDataArray[playerID].idlePeasantsCount <= 0) return; diff --git a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp index f7f6a4555..0bcda0b49 100644 --- a/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp +++ b/src/OpenSHC/AI/AICState/aiRecruitUnits.cpp @@ -36,8 +36,8 @@ namespace AI { && DAT_GameCore::instance.isSkirmishTrail == TRUE && DAT_GameCore::instance.currentTrailType == OpenSHC::Game::TT_EXTREME; - int recruitInterval - = (&this->aics[aicIndex].RecruitInterval)[DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling]; + int recruitInterval = (&this->aics[aicIndex] + .RecruitInterval)[DAT_GameState::instance.playerDataArray[playerID].aiStrengthFeeling]; int recruitCount = recruitInterval != 0 ? 1 : 2; if (isExtremeTrail) recruitCount++; @@ -56,7 +56,8 @@ namespace AI { if (DAT_GameState::instance.playerDataArray[playerID].canStartSpending == 0) return; - if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_DEFENSIVE) { + if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState + == OpenSHC::AI::AIRUC_DEFENSIVE) { int defTotal = this->aics[aicIndex].DefTotal; if (isExtremeTrail) defTotal = defTotal * 4 / 3; @@ -66,9 +67,8 @@ namespace AI { return; } else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_RAIDING) { - if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk - >= MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)( - aicIndex, playerID)) + if (DAT_GameState::instance.playerDataArray[playerID].totalRaidingTroopsUnk >= MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::getCurrentDesiredAttackRaidUnitCount, this)(aicIndex, playerID)) return; } else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_ATTACKING @@ -78,8 +78,8 @@ namespace AI { bool recruitDiggingUnit = false; if (this->aics[aicIndex].DefDiggingUnitMax != 0 - && MACRO_CALL_MEMBER(OpenSHC::Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)( - playerID) + && MACRO_CALL_MEMBER( + OpenSHC::Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)(playerID) != 0) { int diggerTribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10]; if (diggerTribeID == 0 @@ -104,7 +104,8 @@ namespace AI { == OpenSHC::AI::AIRUC_DEFENSIVE) { if (DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex > 7) DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex = 0; - if ((&this->aics[aicIndex].DefUnit1)[DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex] + if ((&this->aics[aicIndex] + .DefUnit1)[DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex] == 0) DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex = 0; int choice = DAT_GameState::instance.playerDataArray[playerID].aiDefUnitChoiceIndex; @@ -114,7 +115,8 @@ namespace AI { == OpenSHC::AI::AIRUC_RAIDING) { if (DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex > 7) DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex = 0; - if ((&this->aics[aicIndex].RaidUnit1)[DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex] + if ((&this->aics[aicIndex] + .RaidUnit1)[DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex] == 0) DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex = 0; int choice = DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex; @@ -122,8 +124,8 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID].aiRaidUnitChoiceIndex = choice + 1; } else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_ATTACKING) { - behaviourType = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::randomlySelectAttackUnitTypeToRecruit, this)( - playerID); + behaviourType = MACRO_CALL_MEMBER( + OpenSHC::AI::AICState_Func::randomlySelectAttackUnitTypeToRecruit, this)(playerID); unitType = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::getUnitTypeForUnitBehaviourType, this)( playerID, (AIUnitBehaviourType)behaviourType); } @@ -136,7 +138,8 @@ namespace AI { else if (unitType == OpenSHC::Map::Units::UT_TUNNELER) buildingID = DAT_GameState::instance.playerDataArray[playerID].tunnelersGuild.id; else if (unitType == OpenSHC::Map::Units::UT_E_MONK) - buildingID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + buildingID = MACRO_CALL_MEMBER( + OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_CATHEDRAL); else if (unitType < 70) buildingID = DAT_GameState::instance.playerDataArray[playerID].barracks.id; @@ -166,8 +169,7 @@ namespace AI { = this->aics[aicIndex].tradeAmountEquipment; else DAT_GameState::instance.playerDataArray[playerID] - .resourcesToAcquireArray[DAT_UnitsState::instance.euroUnitRequiredResource] - = 5; + .resourcesToAcquireArray[DAT_UnitsState::instance.euroUnitRequiredResource] = 5; return; } @@ -175,7 +177,8 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::aiAddUnitToMoatDiggerTribe, this)(unitID); else if (DAT_GameState::instance.playerDataArray[playerID].aiRecruitUnitChoiceState == OpenSHC::AI::AIRUC_DEFENSIVE) { - if (DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk < this->aics[aicIndex].DefWalls) + if (DAT_GameState::instance.playerDataArray[playerID].totalDefensiveTroopsUnk + < this->aics[aicIndex].DefWalls) MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::assignUnitToATribe, this)(unitID); else MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::addUnitToSmallestPatrolTribe, this)(unitID); diff --git a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp index 75f3d197d..7117f018c 100644 --- a/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp +++ b/src/OpenSHC/AI/AICState/aiRequiresExtraOxtethers.cpp @@ -12,12 +12,13 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CB3A0 undefined4 AICState::aiRequiresExtraOxtethers(int playerID) { - int quarryID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, - DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_QUARRY); + int quarryID + = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findFirstBuildingIDForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_QUARRY); int highestStonePerTether = 0; int highestQuarryID = 0; - if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)( - playerID, OpenSHC::Map::Buildings::BT_OXTETHER, 1) + if (MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_OXTETHER, 1) >= 10) return 0; @@ -26,8 +27,8 @@ namespace AI { return 0; for (; quarryID != 0; - quarryID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findNextBuildingForPlayerAndType, - DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_QUARRY, quarryID)) { + quarryID = MACRO_CALL_MEMBER(OpenSHC::Map::Buildings::BuildingsState_Func::findNextBuildingForPlayerAndType, + DAT_BuildingsState::ptr)(playerID, OpenSHC::Map::Buildings::BT_QUARRY, quarryID)) { int stone = DAT_BuildingsState::instance .buildings[(short)DAT_BuildingsState::instance.buildings[quarryID].quarryStockpileID] .resources[Game::Resources::RT_STONE]; @@ -36,7 +37,8 @@ namespace AI { int tetherID = DAT_BuildingsState::instance.buildings[quarryID].quarryLinkedOxTethers[i]; if (tetherID == 0) continue; - if (DAT_BuildingsState::instance.buildings[tetherID].buildingType == OpenSHC::Map::Buildings::BT_OXTETHER + if (DAT_BuildingsState::instance.buildings[tetherID].buildingType + == OpenSHC::Map::Buildings::BT_OXTETHER && DAT_BuildingsState::instance.buildings[tetherID].oxtetherLinkedQuarryID == quarryID) tetherCount++; else diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp index 155e3e57a..1f0c072e0 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildIronMine.cpp @@ -19,8 +19,8 @@ namespace AI { if (this->aics[aicIndex].populationPerIronmine <= 0) return 0; - int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)( - playerID, Map::Buildings::BT_IRONMINE, 1); + int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_IRONMINE, 1); if (count <= 0) count = 1; else if (count >= this->aics[aicIndex].maxIronmines) diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp index b09490a9d..5cf71d7e0 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildPitchrig.cpp @@ -19,8 +19,8 @@ namespace AI { if (this->aics[aicIndex].populationPerPitchrig <= 0) return 0; - int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)( - playerID, Map::Buildings::BT_PITCHRIG, 1); + int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_PITCHRIG, 1); if (count <= 0) count = 1; else if (count >= this->aics[aicIndex].maxPitchrigs) diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp index 86930a063..2fcefd9ab 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildQuarry.cpp @@ -19,8 +19,8 @@ namespace AI { if (this->aics[aicIndex].populationPerQuarry <= 0) return 0; - int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)( - playerID, Map::Buildings::BT_QUARRY, 1); + int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_QUARRY, 1); if (count <= 0) count = 1; else if (count >= this->aics[aicIndex].maxQuarries) diff --git a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp index 79564b50f..7d223c5a9 100644 --- a/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp +++ b/src/OpenSHC/AI/AICState/aiShouldBuildWoodcutter.cpp @@ -22,8 +22,8 @@ namespace AI { if (this->aics[aicIndex].populationPerWoodcutter <= 0) return FALSE; - int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, DAT_BuildingsState::ptr)( - playerID, Map::Buildings::BT_WOODCUTTERSHUT, 1); + int count = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::countBuildingsForPlayer, + DAT_BuildingsState::ptr)(playerID, Map::Buildings::BT_WOODCUTTERSHUT, 1); if (count <= 0) { count = 1; } else { diff --git a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp index b3e668cc0..cd1b58035 100644 --- a/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp +++ b/src/OpenSHC/AI/AICState/aiUpdateTaxesAndRations.cpp @@ -46,7 +46,8 @@ namespace AI { else DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 3; if (this->aics[aicIndex].doubleRationsFoodThreshold != 0 - && DAT_GameState::instance.playerDataArray[playerID].totalFood >= this->aics[aicIndex].doubleRationsFoodThreshold) + && DAT_GameState::instance.playerDataArray[playerID].totalFood + >= this->aics[aicIndex].doubleRationsFoodThreshold) DAT_GameState::instance.playerDataArray[playerID].rationsSetting = 4; } else if (DAT_GameState::instance.playerDataArray[playerID].aiPopularityDecisionValue == 0) { if (DAT_GameState::instance.playerDataArray[playerID].taxesSetting < this->aics[aicIndex].taxesMax) { diff --git a/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp index f05cf559c..d6f813898 100644 --- a/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp +++ b/src/OpenSHC/AI/AICState/assignRequiredIdleEngineersToNewTribe.cpp @@ -13,7 +13,8 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CC5A0 int AICState::assignRequiredIdleEngineersToNewTribe(int playerID, int count) { - int tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + int tribeID + = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) { if (count <= 0) return tribeID; diff --git a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp index 8605948c5..6fde84ca6 100644 --- a/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp +++ b/src/OpenSHC/AI/AICState/buyRequiredGoods.cpp @@ -45,7 +45,8 @@ namespace AI { continue; } - if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::buyGoods, this)(playerID, (ResourceType)resourceType, amount) + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::buyGoods, this)( + playerID, (ResourceType)resourceType, amount) != FALSE) { DAT_GameState::instance.playerDataArray[playerID].resourcesToAcquireArray[resourceType] = 0; return; diff --git a/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp index db81e30ae..2b8922be6 100644 --- a/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp +++ b/src/OpenSHC/AI/AICState/canNavigateUnitsFromTileToTargetTile.cpp @@ -13,10 +13,12 @@ namespace AI { BOOLEnum AICState::canNavigateUnitsFromTileToTargetTile(int tribeID, int tile) { int owner = DAT_TribesState::instance.tribes[tribeID].owner; - int fromArea = (short)DAT_TileMapState::instance.PathConnectionLayer - [DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID].tile]; + int fromArea = (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID] + .tile]; return MACRO_CALL_MEMBER(Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, - DAT_PathFindingState::ptr)(owner, fromArea, (short)DAT_TileMapState::instance.PathConnectionLayer[tile], 0) + DAT_PathFindingState::ptr)( + owner, fromArea, (short)DAT_TileMapState::instance.PathConnectionLayer[tile], 0) != 0; } } diff --git a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp index c06815f87..09533eb02 100644 --- a/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/clearRallyFlagOnAllAIAttackTribes.cpp @@ -27,8 +27,8 @@ namespace AI { != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[j + tribeType]) continue; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)( - tribeID); + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)(tribeID); } } } diff --git a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp index 1b1585398..d158bc23f 100644 --- a/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp +++ b/src/OpenSHC/AI/AICState/computeEnemyKeepApproachTile.cpp @@ -33,11 +33,11 @@ namespace AI { DAT_DirectionAlgorithmState::ptr)(keepX, keepY, tile - DAT_ViewportRenderState::instance - .translationMatrix[DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]] - .addXgetTile, + .translationMatrix[DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]] + .addXgetTile, DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]); - this->aiBorderTiles[i].distance - = DAT_TileMapState::instance.unitDeathHeatMap[tile] + DAT_DirectionAlgorithmState::instance.distanceHigh; + this->aiBorderTiles[i].distance = DAT_TileMapState::instance.unitDeathHeatMap[tile] + + DAT_DirectionAlgorithmState::instance.distanceHigh; } int shortestDistanceTile = 0; diff --git a/src/OpenSHC/AI/AICState/computeNervousness.cpp b/src/OpenSHC/AI/AICState/computeNervousness.cpp index 61274298d..2d92d4bca 100644 --- a/src/OpenSHC/AI/AICState/computeNervousness.cpp +++ b/src/OpenSHC/AI/AICState/computeNervousness.cpp @@ -10,7 +10,8 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004D3780 void AICState::computeNervousness(int playerID) { - int troopValueNearKeep = DAT_TroopValueState::instance.attackInfo.playerTotalTroopValueOfTroopsNearKeep[playerID]; + int troopValueNearKeep + = DAT_TroopValueState::instance.attackInfo.playerTotalTroopValueOfTroopsNearKeep[playerID]; int enemyTroopValue = DAT_GameState::instance.playerDataArray[playerID].totalEnemyTroopValue; int margin; diff --git a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp index 21713a7e5..48f809905 100644 --- a/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp +++ b/src/OpenSHC/AI/AICState/decideOnTribeAttackLocation.cpp @@ -42,18 +42,18 @@ namespace AI { byte moatWasHit = 0; int x = 0; int y = 0; - int unitID - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::getUnitIDForIndexInTribe, DAT_TribesState::ptr)( - tribeID, 0); + int unitID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::getUnitIDForIndexInTribe, DAT_TribesState::ptr)(tribeID, 0); if (unitID != 0 - && MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, + && MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::PathFindingState_Func::pathFindingToAttackCastleIncludingMoat, DAT_PathFindingState::ptr)(DAT_TribesState::instance.tribes[tribeID].owner, targetPlayer, DAT_UnitsState::instance.units[unitID].x, DAT_UnitsState::instance.units[unitID].y, &moatWasHit, &x, &y)) { if (moatWasHit != 0) { MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( - tribeID, (UnitInstructionType)35, DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x, - 0, 0); + tribeID, (UnitInstructionType)35, + DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile + x, 0, 0); return; } MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( @@ -72,18 +72,20 @@ namespace AI { && DAT_BuildingsState::instance.buildings[targetBuildingID].uid == DAT_TribesState::instance.tribes[tribeID].targetBuildingUID && DAT_BuildingsState::instance.buildings[targetBuildingID].fireDuration == 0 - && MACRO_CALL_MEMBER(AICState_Func::checkTribeActivityPercentages, this)(tribeID, FALSE, TRUE) != FALSE) { + && MACRO_CALL_MEMBER(AICState_Func::checkTribeActivityPercentages, this)(tribeID, FALSE, TRUE) + != FALSE) { if (DAT_GameState::instance.mapAndTime.yearChanged != 0) DAT_TribesState::instance.tribes[tribeID].targetBuildingID = 0; return; } - int buildingID = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, - DAT_GameState::ptr)(targetPlayer); + int buildingID + = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::selectARandomBuildingOwnedByPlayer, + DAT_GameState::ptr)(targetPlayer); if (buildingID != 0) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)(tribeID, - OpenSHC::Map::Units::UIT_ATTACK_BUILDING, buildingID, DAT_BuildingsState::instance.buildings[buildingID].uid, - 0); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::relayTribeInstruction, DAT_UnitsState::ptr)( + tribeID, OpenSHC::Map::Units::UIT_ATTACK_BUILDING, buildingID, + DAT_BuildingsState::instance.buildings[buildingID].uid, 0); DAT_TribesState::instance.tribes[tribeID].targetBuildingID = buildingID; DAT_TribesState::instance.tribes[tribeID].targetBuildingUID = DAT_BuildingsState::instance.buildings[buildingID].uid; @@ -93,8 +95,8 @@ namespace AI { int destinationX = DAT_GameState::instance.playerDataArray[targetPlayer].campground.xEntry; DAT_TribesState::instance.tribes[tribeID].targetBuildingID = 0; int destinationY = DAT_GameState::instance.playerDataArray[targetPlayer].campground.yEntry; - if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( - tribeID, DAT_ViewportRenderState::instance.translationMatrix[destinationY].addXgetTile + destinationX) + if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)(tribeID, + DAT_ViewportRenderState::instance.translationMatrix[destinationY].addXgetTile + destinationX) == FALSE) return; @@ -107,9 +109,10 @@ namespace AI { DAT_GameState::ptr)(targetPlayer); int destinationTile; if (buildingID == 0) { - destinationTile = DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[targetPlayer].campground.yEntry] - .addXgetTile + destinationTile + = DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[targetPlayer].campground.yEntry] + .addXgetTile + DAT_GameState::instance.playerDataArray[targetPlayer].campground.xEntry; } else if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0) { destinationTile = DAT_BuildingsState::instance.buildings[buildingID].buildingEntryX @@ -119,8 +122,9 @@ namespace AI { } else { MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::pathfindingForAttacksUnk, DAT_PathFindingState::ptr)(tribeID, buildingID, 1, - (short)DAT_TileMapState::instance.PathConnectionLayer - [DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID].tile], + (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance + .units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID] + .tile], targetPlayer); destinationTile = DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile1; if (DAT_PathFindingState::instance.searchQueue.destinationsArray[0].tile2OrAHelper == 0) @@ -135,7 +139,8 @@ namespace AI { return; int destinationY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[destinationTile]; - int destinationX = destinationTile - DAT_ViewportRenderState::instance.translationMatrix[destinationY].addXgetTile; + int destinationX + = destinationTile - DAT_ViewportRenderState::instance.translationMatrix[destinationY].addXgetTile; if (MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::canNavigateUnitsFromTileToTargetTile, this)( tribeID, destinationTile) == FALSE) { diff --git a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp index 3d9cd00bc..a8c02b8b2 100644 --- a/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp +++ b/src/OpenSHC/AI/AICState/destroyAnyBuildingInCategory.cpp @@ -23,29 +23,67 @@ namespace AI { bool matches = false; if (buildingCategory == AINDBC_FEAR_FACTOR_BUILDINGS) - matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CESSPIT || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BURNINGSTAKE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GIBBET || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DUNGEON - || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STRETCHINGRACK || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_RACKFLOGGING || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CHOPPINGBLOCK - || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DUNKINGSTOOL || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DOGCAGE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STATUE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_SHRINE - || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DANCINGBEAR || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_POND || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GALLOWS || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STOCKS - || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WITCHHOIST || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_MAYPOLE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GARDEN; + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CESSPIT + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BURNINGSTAKE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GIBBET + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DUNGEON + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STRETCHINGRACK + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_RACKFLOGGING + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CHOPPINGBLOCK + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DUNKINGSTOOL + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DOGCAGE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STATUE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_SHRINE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DANCINGBEAR + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_POND + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GALLOWS + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STOCKS + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WITCHHOIST + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_MAYPOLE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GARDEN; else if (buildingCategory == AINDBC_WORKSHOPS_AND_RELIGIOUS_BUILDINGS) - matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_FLETCHER || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BLACKSMITH || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_POLETURNER || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_ARMOURER - || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TANNER || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_INN || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_APOTHECARY || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CHAPEL - || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CHURCH || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CATHEDRAL; + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_FLETCHER + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BLACKSMITH + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_POLETURNER + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_ARMOURER + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TANNER + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_INN + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_APOTHECARY + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CHAPEL + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CHURCH + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_CATHEDRAL; else if (buildingCategory == AINDBC_GATEHOUSES_TOWERS_GUILDS) - matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GATEHOUSELARGE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GATEHOUSESMALL || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DRAWBRIDGE - || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER1 || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER2 || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER3 || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER4 - || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER5 || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_ENGINEERSGUILD || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TUNNELERSGUILD + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GATEHOUSELARGE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_GATEHOUSESMALL + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DRAWBRIDGE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER1 + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER2 + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER3 + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER4 + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TOWER5 + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_ENGINEERSGUILD + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_TUNNELERSGUILD || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_OILSMELTER; else if (buildingCategory == AINDBC_BARRACKS_MERCPOST_STABLES) - matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_MERCENARYPOST || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BARRACKS || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STABLES; + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_MERCENARYPOST + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BARRACKS + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_STABLES; else if (buildingCategory == AINDBC_WATER_BUILDINGS) - matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WELL || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WATERPOT; + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WELL + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WATERPOT; else if (buildingCategory == AINDBC_RESOURCE_BUILDINGS) - matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_OXTETHER || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_IRONMINE || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_PITCHRIG || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BAKERY - || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BREWERY || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_QUARRY || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_MILL; + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_OXTETHER + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_IRONMINE + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_PITCHRIG + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BAKERY + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_BREWERY + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_QUARRY + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_MILL; else if (buildingCategory == AINDBC_FARMS) - matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WHEATFARM || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_HOPFARM || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_APPLEFARM || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DAIRYFARM; + matches = DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_WHEATFARM + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_HOPFARM + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_APPLEFARM + || DAT_BuildingsState::instance.buildings[buildingID].buildingType == BT_DAIRYFARM; if (!matches) continue; diff --git a/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp b/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp index 7628ed4fe..6f54dca38 100644 --- a/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp +++ b/src/OpenSHC/AI/AICState/determineAIPlayerAttackRequestResponse.cpp @@ -16,14 +16,16 @@ namespace AI { int aicIndex = aiType - 1; if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue != 0) { - MACRO_CALL_MEMBER(AICState_Func::playWillNotAttack1BikFromPlayerToPlayer, this)(playerID, requestedByPlayerID); + MACRO_CALL_MEMBER(AICState_Func::playWillNotAttack1BikFromPlayerToPlayer, this)( + playerID, requestedByPlayerID); return FALSE; } if (DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops - DAT_GameState::instance.playerDataArray[playerID].totalAttackingEngineerTroops < this->aics[aicIndex].AttForceSupportAllyThreshold) { - MACRO_CALL_MEMBER(AICState_Func::playWillNotAttack2BikFromPlayerToPlayer, this)(playerID, requestedByPlayerID); + MACRO_CALL_MEMBER(AICState_Func::playWillNotAttack2BikFromPlayerToPlayer, this)( + playerID, requestedByPlayerID); return FALSE; } diff --git a/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp b/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp index 214c9d2e7..df8442f09 100644 --- a/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp +++ b/src/OpenSHC/AI/AICState/determineAIPlayerHelp.cpp @@ -16,13 +16,15 @@ namespace AI { int aicIndex = aiType - 1; if (DAT_GameState::instance.playerDataArray[playerID].isNotNervousByEnemyTroopValue != 0) { - MACRO_CALL_MEMBER(AICState_Func::playWillNotHelp1BikFromPlayerToPlayer, this)(playerID, requestedByPlayerID); + MACRO_CALL_MEMBER(AICState_Func::playWillNotHelp1BikFromPlayerToPlayer, this)( + playerID, requestedByPlayerID); return FALSE; } if (DAT_GameState::instance.playerDataArray[playerID].totalAttackTroops < this->aics[aicIndex].AttForceSupportAllyThreshold) { - MACRO_CALL_MEMBER(AICState_Func::playWillNotHelp2BikFromPlayerToPlayer, this)(playerID, requestedByPlayerID); + MACRO_CALL_MEMBER(AICState_Func::playWillNotHelp2BikFromPlayerToPlayer, this)( + playerID, requestedByPlayerID); return FALSE; } diff --git a/src/OpenSHC/AI/AICState/digNearestMoat.cpp b/src/OpenSHC/AI/AICState/digNearestMoat.cpp index da6dac8af..a8f101b79 100644 --- a/src/OpenSHC/AI/AICState/digNearestMoat.cpp +++ b/src/OpenSHC/AI/AICState/digNearestMoat.cpp @@ -19,22 +19,24 @@ namespace AI { int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[10]; if (tribeID == 0) return; - if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10]) + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[10]) return; if (DAT_TribesState::instance.tribes[tribeID].size <= 0) return; if (DAT_TribesState::instance.tribes[tribeID].percentageSomething > 80) return; - if (MACRO_CALL_MEMBER(Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)(playerID) + if (MACRO_CALL_MEMBER(Map::TileMapState_Func::countUnfinishedMoatTilesForPlayer, DAT_TileMapState::ptr)( + playerID) <= 0) { MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); return; } int targetUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; - int tile = MACRO_CALL_MEMBER(Map::TileMapState_Func::findNearestFriendlyMoatTileForDigging, DAT_TileMapState::ptr)( - playerID, targetUnitID, 1); + int tile = MACRO_CALL_MEMBER(Map::TileMapState_Func::findNearestFriendlyMoatTileForDigging, + DAT_TileMapState::ptr)(playerID, targetUnitID, 1); if (tile <= -1) return; @@ -44,8 +46,8 @@ namespace AI { return; MACRO_CALL_MEMBER(Map::Units::TribesState_Func::giveTribeAnInstruction, DAT_TribesState::ptr)(tribeID, - Map::Units::UIT_DIG_MOAT, DAT_TileMapState::instance.ALG_MoatXResult, DAT_TileMapState::instance.ALG_MoatYResult, - 0); + Map::Units::UIT_DIG_MOAT, DAT_TileMapState::instance.ALG_MoatXResult, + DAT_TileMapState::instance.ALG_MoatYResult, 0); DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_STAND_GROUND; } } diff --git a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp index fa83afc50..b854d8312 100644 --- a/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp +++ b/src/OpenSHC/AI/AICState/findAttackTribePositionAndPathToDefenses.cpp @@ -26,7 +26,7 @@ namespace AI { continue; if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[j + DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType]) + .aiTribeUIDs[j + DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType]) continue; targetUnitID = DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID; diff --git a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp index e06149d2a..95a84c59f 100644 --- a/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp +++ b/src/OpenSHC/AI/AICState/generateSiegeCreationInformation.cpp @@ -33,7 +33,9 @@ namespace AI { int i; for (i = 0; i < locationCount; i++) { if (DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[slot][i] > 0 - && DAT_GameState::instance.playerDataArray[playerID].aiSiegeCreationInformation[siegeIndex][i].buildingID + && DAT_GameState::instance.playerDataArray[playerID] + .aiSiegeCreationInformation[siegeIndex][i] + .buildingID == buildingID) break; } diff --git a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp index eb72c6142..fd1ac266c 100644 --- a/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp +++ b/src/OpenSHC/AI/AICState/getDefensiveTribeForUnit.cpp @@ -45,7 +45,8 @@ namespace AI { tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeIndex] = tribeID; - DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[tribeIndex] = DAT_TribesState::instance.tribes[tribeID].uid; + DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[tribeIndex] + = DAT_TribesState::instance.tribes[tribeID].uid; return tribeID; } } diff --git a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp index 6edf8182f..cea616412 100644 --- a/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp +++ b/src/OpenSHC/AI/AICState/getSmallestPatrolTribe.cpp @@ -20,9 +20,8 @@ namespace AI { if (tribeID == 0 || DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[i + 170]) { - selectedTribeID - = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)( - playerID); + selectedTribeID = MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); selectedIndex = i; break; } diff --git a/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp b/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp index 143bed0a2..3a4accdb0 100644 --- a/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp +++ b/src/OpenSHC/AI/AICState/getUnitTypeForUnitBehaviourType.cpp @@ -40,7 +40,8 @@ namespace AI { if (unitBehaviourType != OpenSHC::AI::AIUBT_ATTUNITMAIN) return (UnitType)this->aics[aicIndex].AttUnitMain1; - if ((&this->aics[aicIndex].AttUnitMain1)[DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex] + if ((&this->aics[aicIndex] + .AttUnitMain1)[DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex] == 0) DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex = 0; if (DAT_GameState::instance.playerDataArray[playerID].aiAttUnitMainChoiceIndex >= 4) diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp index 72b1efc80..00d41635a 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToAttackTribes.cpp @@ -34,10 +34,12 @@ namespace AI { continue; DAT_TribesState::instance.tribes[tribeID].unitStance = (char)(SEC_RNG::instance.currentNumber2 & 1); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - tribeID, - DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex].xOffset, - DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex].yOffset, + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(tribeID, + DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex] + .xOffset, + DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex] + .yOffset, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); destIndex++; } diff --git a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp index 0c4613340..30db96be3 100644 --- a/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp +++ b/src/OpenSHC/AI/AICState/giveMoveCommandToSortieUnits.cpp @@ -48,16 +48,17 @@ namespace AI { && MACRO_CALL_MEMBER( OpenSHC::Map::Navigation::PathFindingState_Func::calculateCanPlayerUnitsNavigateToAreaFromArea, DAT_PathFindingState::ptr)(playerID, - (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[targetUnitID] - .tile], - (short)DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[unitID].tile], + (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_UnitsState::instance.units[targetUnitID].tile], + (short) + DAT_TileMapState::instance.PathConnectionLayer[DAT_UnitsState::instance.units[unitID].tile], 0) != 0) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, - DAT_TribesState::ptr)(tribeID); - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - tribeID, DAT_UnitsState::instance.units[unitID].x, DAT_UnitsState::instance.units[unitID].y, 0, 0, - OpenSHC::Map::Units::Instructions::UMSE_0); + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)(tribeID); + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(tribeID, DAT_UnitsState::instance.units[unitID].x, + DAT_UnitsState::instance.units[unitID].y, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; return; } diff --git a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp index 71c020461..c094f57f1 100644 --- a/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp +++ b/src/OpenSHC/AI/AICState/giveSomeRaidCommand.cpp @@ -26,14 +26,16 @@ namespace AI { return 1; DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = 0; - int buildingID = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, - this)(DAT_GameState::instance.playerDataArray[owner].attackedPlayerID); + int buildingID + = MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::chooseRandomBuildingIDFromPlayersArrayOfBuildings, this)( + DAT_GameState::instance.playerDataArray[owner].attackedPlayerID); if (buildingID == 0) return 0; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::queueDisbandAndAttackCommand4Params, DAT_UnitsState::ptr)( - tribeIndex, 9, buildingID, DAT_BuildingsState::instance.buildings[buildingID].uid); - DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID = DAT_BuildingsState::instance.buildings[buildingID].uid; + MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::queueDisbandAndAttackCommand4Params, + DAT_UnitsState::ptr)(tribeIndex, 9, buildingID, DAT_BuildingsState::instance.buildings[buildingID].uid); + DAT_TribesState::instance.tribes[tribeIndex].targetBuildingUID + = DAT_BuildingsState::instance.buildings[buildingID].uid; DAT_TribesState::instance.tribes[tribeIndex].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; DAT_TribesState::instance.tribes[tribeIndex].targetBuildingID = buildingID; return 1; diff --git a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp index 8c8d55360..95b2d1aeb 100644 --- a/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp +++ b/src/OpenSHC/AI/AICState/ifHasTribe0SendUnitsToKeep.cpp @@ -12,7 +12,8 @@ namespace AI { int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[0]; if (tribeID <= 0) return; - if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0]) + if (DAT_TribesState::instance.tribes[tribeID].uid + != DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[0]) return; MACRO_CALL_MEMBER(AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); diff --git a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp index 972175686..22d967f1f 100644 --- a/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp +++ b/src/OpenSHC/AI/AICState/instructTribe166ToMove.cpp @@ -27,8 +27,8 @@ namespace AI { DAT_GameState::instance.playerDataArray[playerID].unknownCounter_01 = 50; int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[166]; - BOOLEnum keepEnclosed - = MACRO_CALL_MEMBER(OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); + BOOLEnum keepEnclosed = MACRO_CALL_MEMBER( + OpenSHC::Game::GameStateStructures_Func::checkKeepEnclosed, DAT_GameState::ptr)(playerID); if (tribeID == 0) return; if (DAT_TribesState::instance.tribes[tribeID].uid diff --git a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp index a6e4bac6f..b9d4faf2f 100644 --- a/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp +++ b/src/OpenSHC/AI/AICState/makeUnitsGoDefensiveAndBackToSomeLocation.cpp @@ -32,9 +32,8 @@ namespace AI { continue; DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - uint result = MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(tribeID, - DAT_GameState::instance.playerDataArray[playerID].someX, + uint result = MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(tribeID, DAT_GameState::instance.playerDataArray[playerID].someX, DAT_GameState::instance.playerDataArray[playerID].someY, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); if (result == 0) diff --git a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp index 6801cfdf0..ee8e3ad57 100644 --- a/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp +++ b/src/OpenSHC/AI/AICState/moveAttackTribesToLocations.cpp @@ -31,10 +31,12 @@ namespace AI { continue; DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - tribeID, - DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex].xOffset, - DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex].yOffset, + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(tribeID, + DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex] + .xOffset, + DAT_GameState::instance.mapAndTime.aiTribeMoveDestinationXYPairArray1[playerID * 5][destIndex] + .yOffset, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); destIndex++; } diff --git a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp index 93e437633..a652216ca 100644 --- a/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp +++ b/src/OpenSHC/AI/AICState/playPlayerKilledBiksFromKilledAndKillerPlayer.cpp @@ -34,10 +34,12 @@ namespace AI { continue; } if (DAT_GameState::instance.mapAndTime.playerTeams[i] - != DAT_GameState::instance.mapAndTime.playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { + != DAT_GameState::instance.mapAndTime + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID]) { continue; } - if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i) == 0) { + if (MACRO_CALL_MEMBER(Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i) + == 0) { continue; } MACRO_CALL_MEMBER(Rendering::Bink::AIMessageQueue_Func::playBikVideoFromPlayer, DAT_VideoBikQueue::ptr)( diff --git a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp index 45197c9e8..5fae78c3f 100644 --- a/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp +++ b/src/OpenSHC/AI/AICState/recomputeAIPathCostToAttackedKeep.cpp @@ -26,11 +26,10 @@ namespace AI { int borderDistance; if (DAT_GameState::instance.playerDataArray[attackedPlayerID].unknownPathBorderDistanceRelated > 120) { borderDistance = 98; - } - else { + } else { borderDistance = DAT_GameState::instance.playerDataArray[attackedPlayerID].unknownPathBorderDistanceRelated > 90 ? 70 - : 50; + : 50; } if (useBorderDistance == 0) { borderDistance = 0; @@ -47,8 +46,7 @@ namespace AI { != FALSE) { MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 1, 1); - } - else { + } else { MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::computeAIZoneLayer, DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID, 0, 1); } diff --git a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp index f58644824..d72a3a55f 100644 --- a/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp +++ b/src/OpenSHC/AI/AICState/recruitHarrassingSiegeEngines.cpp @@ -45,7 +45,8 @@ namespace AI { if (aiType == 0) { return; } - if (DAT_GameState::instance.playerDataArray[playerID].currentResources[OpenSHC::Game::Resources::RT_GOLD] < 500) { + if (DAT_GameState::instance.playerDataArray[playerID].currentResources[OpenSHC::Game::Resources::RT_GOLD] + < 500) { return; } @@ -102,14 +103,13 @@ namespace AI { MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)( unitID, tribeID); DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = OpenSHC::AI::AIUBT_HARASS_SIEGE; - } - else { + } else { // Enough engineers: pick the next siege engine from the AIC list and place its tent if (DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex >= 8) { DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = 0; } - if ((&this->aics[aicIndex].HarassingSiegeEngine1) - [DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex] + if ((&this->aics[aicIndex].HarassingSiegeEngine1)[DAT_GameState::instance.playerDataArray[playerID] + .harrassingSiegeEnginesIndex] == 0) { DAT_GameState::instance.playerDataArray[playerID].harrassingSiegeEnginesIndex = 0; } diff --git a/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp b/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp index 4736730bd..b81a2726e 100644 --- a/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp +++ b/src/OpenSHC/AI/AICState/removeOrganismsAndSetMoveDestinationPairs.cpp @@ -24,17 +24,19 @@ namespace AI { void AICState::removeOrganismsAndSetMoveDestinationPairs(int playerID) { // Clear a tree standing on the target tile - int organismID = (short)DAT_TileMapState::instance.OrganismLayer - [DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] - .addXgetTile - + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]; + int organismID + = (short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]; if (organismID != 0) { MACRO_CALL_MEMBER(OpenSHC::Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)(organismID); } // Hardcoded exception: the Sultan keeps a smaller distance than all other AIs - int extraDistance = DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_SULTAN ? 8 : 20; + int extraDistance + = DAT_GameState::instance.playerDataArray[playerID].aiType == OpenSHC::AI::AIT_SULTAN ? 8 : 20; MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::PathFindingState_Func::findLinkageBasedPathOrWalkRadius, DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, -1, -1, 10000, FALSE); diff --git a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp index 4dd36397c..cacb4823f 100644 --- a/src/OpenSHC/AI/AICState/selectAttackTarget.cpp +++ b/src/OpenSHC/AI/AICState/selectAttackTarget.cpp @@ -116,8 +116,8 @@ namespace AI { == DAT_GameState::instance.mapAndTime.playerTeams[playerID]) { continue; } - if (MACRO_CALL_MEMBER( - OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)(i) + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::UnitsState_Func::getAliveLordForPlayer, DAT_UnitsState::ptr)( + i) == 0) { continue; } diff --git a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp index 9374bef8a..222bd7854 100644 --- a/src/OpenSHC/AI/AICState/sellExcessGoods.cpp +++ b/src/OpenSHC/AI/AICState/sellExcessGoods.cpp @@ -79,7 +79,8 @@ namespace AI { } variance = 0; } else { - amount += *(int*)((char*)DAT_GameState::instance.playerDataArray[0].resourcesToAcquireArray + resourceOffset); + amount += *( + int*)((char*)DAT_GameState::instance.playerDataArray[0].resourcesToAcquireArray + resourceOffset); } // Resources the AIC always sells are kept at zero @@ -93,8 +94,9 @@ namespace AI { if (*(int*)((char*)DAT_GameState::instance.playerDataArray[0].currentResources + resourceOffset) > amount) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sellGoods, this)(playerID, resourceType, - ((int*)DAT_GameState::instance.playerDataArray[0].currentResources)[playerResourceBase + resourceType] - amount - + variance); + ((int*)DAT_GameState::instance.playerDataArray[0] + .currentResources)[playerResourceBase + resourceType] + - amount + variance); return; } } diff --git a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp index cc8bb42ab..abe6c64a1 100644 --- a/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp +++ b/src/OpenSHC/AI/AICState/sendCertainUnitTribesToAIVSlotsOrKeepIfNervousAndNotEnclosed.cpp @@ -30,16 +30,14 @@ namespace AI { int count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount [DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[i].aivUnitType]; for (int j = 0; j < count; j++) { - int tribeID = DAT_GameState::instance.playerDataArray[playerID] - .aiTribeIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[i] - .tribeArrayOffset - + j]; + int tribeID + = DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[i].tribeArrayOffset + + j]; if (tribeID != 0 && DAT_TribesState::instance.tribes[tribeID].uid - == DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[i] - .tribeArrayOffset - + j]) { + == DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs + [DAT_SkirmishDefinedData::instance.MaxAIVLocationForGroundUnits[i].tribeArrayOffset + j]) { if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker <= 0 || enclosed != FALSE) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)(tribeID, @@ -56,8 +54,7 @@ namespace AI { DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; } else { - DAT_TribesState::instance.tribes[tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; } } } diff --git a/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp index f5d86fd16..5fc7b54b3 100644 --- a/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp +++ b/src/OpenSHC/AI/AICState/sendOilMenForOilPickupOrToAIVLocations.cpp @@ -42,8 +42,8 @@ namespace AI { if (DAT_UnitsState::instance.units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID] .resourceToDeposit != 0) { - MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, - DAT_TribesState::ptr)(tribeID); + MACRO_CALL_MEMBER( + OpenSHC::Map::Units::TribesState_Func::unsetRallyRelatedFlagOnUnits, DAT_TribesState::ptr)(tribeID); MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendTribeToAIVLocationSlot, this)( tribeID, OpenSHC::AI::AIVUT_ENGINEER, i - 1); continue; diff --git a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp index 704a12842..0110e7fed 100644 --- a/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp +++ b/src/OpenSHC/AI/AICState/sendRangedUnitTribesToAIVSlotsOrKeepIfNervous.cpp @@ -24,25 +24,24 @@ namespace AI { int count = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount [DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[i].aivUnitType]; for (int j = 0; j < count; j++) { - int tribeID = DAT_GameState::instance.playerDataArray[playerID] - .aiTribeIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[i] - .tribeArrayOffset - + j]; + int tribeID + = DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[i].tribeArrayOffset + + j]; if (tribeID == 0) { continue; } if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[i] - .tribeArrayOffset - + j]) { + .aiTribeUIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForRangedUnits[i].tribeArrayOffset + + j]) { continue; } if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0) { if ((DAT_TileMapState::instance.LogicLayer[DAT_UnitsState::instance - .units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID] - .tile] + .units[DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID] + .tile] & 0x10000100U) == 0) { MACRO_CALL_MEMBER(OpenSHC::AI::AICState_Func::sendUnitsToKeep, this)(tribeID, playerID); diff --git a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp index ccfd04650..6346c66e0 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToAttackBreachedCastle.cpp @@ -71,7 +71,8 @@ namespace AI { int attackedPlayerID = DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID; - MACRO_CALL_MEMBER(OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, + MACRO_CALL_MEMBER( + OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::setAxisBasedDistanceResult, DAT_DirectionAlgorithmState::ptr)(DAT_UnitsState::instance.units[targetUnitID].x, DAT_UnitsState::instance.units[targetUnitID].y, DAT_GameState::instance.mapAndTime.attackVectors[attackedPlayerID][vector].x, @@ -80,18 +81,17 @@ namespace AI { if (DAT_DirectionAlgorithmState::instance.distanceHigh > 4) { attackedPlayerID = DAT_GameState::instance.playerDataArray[attackingPlayerIndex].attackedPlayerID; - MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - tribeID, DAT_GameState::instance.mapAndTime.attackVectors[attackedPlayerID][vector].x, + MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(tribeID, + DAT_GameState::instance.mapAndTime.attackVectors[attackedPlayerID][vector].x, DAT_GameState::instance.mapAndTime.attackVectors[attackedPlayerID][vector].y, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0); } vector += 1; } else { // Send units to attack lord - if (MACRO_CALL_MEMBER( - OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)( - tribeID, DAT_UnitsState::instance.units[defendingLordID].x, + if (MACRO_CALL_MEMBER(OpenSHC::Map::Units::TribesState_Func::giveTribeMoveInstruction, + DAT_TribesState::ptr)(tribeID, DAT_UnitsState::instance.units[defendingLordID].x, DAT_UnitsState::instance.units[defendingLordID].y, 0, 0, OpenSHC::Map::Units::Instructions::UMSE_0) == 0) { diff --git a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp index 9f0595474..be3532ffb 100644 --- a/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp +++ b/src/OpenSHC/AI/AICState/sendUnitsToPlayerIDsKeepIfPossible.cpp @@ -32,7 +32,8 @@ namespace AI { DAT_PathFindingState::ptr)(playerID2, campfireX, campfireY); if (gatehouseTile != 0) { gatehouseY = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[gatehouseTile]; - gatehouseX = gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[gatehouseY].addXgetTile; + gatehouseX + = gatehouseTile - DAT_ViewportRenderState::instance.translationMatrix[gatehouseY].addXgetTile; } else { DAT_GameState::instance.playerDataArray[playerID1].requestStateUnk = 0; return; diff --git a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp index f3285132e..0296967f4 100644 --- a/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp +++ b/src/OpenSHC/AI/AICState/sendWallPatrolUnitTribesToAIVLocations.cpp @@ -53,23 +53,22 @@ namespace AI { } for (int j = 0, patrolGroupIndex = 0; j < groups; j++, patrolGroupIndex += stepSize) { - int tribeID = DAT_GameState::instance.playerDataArray[playerID] - .aiTribeIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[i] - .tribeArrayOffset - + j]; + int tribeID + = DAT_GameState::instance.playerDataArray[playerID] + .aiTribeIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[i].tribeArrayOffset + + j]; if (tribeID == 0) { continue; } if (DAT_TribesState::instance.tribes[tribeID].uid != DAT_GameState::instance.playerDataArray[playerID] - .aiTribeUIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[i] - .tribeArrayOffset - + j]) { + .aiTribeUIDs[DAT_SkirmishDefinedData::instance.MaxAIVLocationForPatrolUnits[i].tribeArrayOffset + + j]) { continue; } - int slot = (DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits - + patrolGroupIndex) + int slot + = (DAT_GameState::instance.playerDataArray[playerID].defWallPatrolRallyTimeHits + patrolGroupIndex) % count; if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0 && enclosed == FALSE) { @@ -82,8 +81,7 @@ namespace AI { if (DAT_GameState::instance.playerDataArray[playerID].aiNervousActionsTracker > 0 && enclosed == FALSE) { - DAT_TribesState::instance.tribes[tribeID].unitStance - = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; + DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_DEFENSIVE; } else { DAT_TribesState::instance.tribes[tribeID].unitStance = OpenSHC::Map::Units::Behavior::USE_AGGRESSIVE; diff --git a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp index c730d59b1..58aebe7c6 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_10.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_10.cpp @@ -1,4 +1,5 @@ #include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp index b76e2fd60..c08fc909d 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_12.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_12.cpp @@ -1,4 +1,5 @@ #include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp index f2cc56d61..bee77c542 100644 --- a/src/OpenSHC/AI/AICState/setAICParameters_14.cpp +++ b/src/OpenSHC/AI/AICState/setAICParameters_14.cpp @@ -1,4 +1,5 @@ #include "../AICState.func.hpp" + #include "OpenSHC/AI/AIC/AITargetChoice.hpp" namespace OpenSHC { diff --git a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp index 25e1873db..db0febac5 100644 --- a/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp +++ b/src/OpenSHC/AI/AICState/setAttackPrimeInfo.cpp @@ -17,10 +17,9 @@ namespace AI { DAT_TroopValueState::instance.attackInfo.zoneSize = DAT_PathFindingState::instance.zoneSizesArray[DAT_TroopValueState::instance.attackInfo.startCon]; DAT_TroopValueState::instance.attackInfo.unknownOne_0x20f90 = 1; - DAT_TroopValueState::instance.attackInfo.keepCon = (short)DAT_TileMapState::instance - .PathConnectionLayer[DAT_GameState::instance - .playerDataArray[attackedPlayerID] - .campground.tileEntry]; + DAT_TroopValueState::instance.attackInfo.keepCon + = (short)DAT_TileMapState::instance + .PathConnectionLayer[DAT_GameState::instance.playerDataArray[attackedPlayerID].campground.tileEntry]; } } } diff --git a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp index 0260e5f2c..ef07f7cf0 100644 --- a/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp +++ b/src/OpenSHC/AI/AICState/setCurrentAttackRaidParameter.cpp @@ -23,7 +23,8 @@ namespace AI { int raidUnits = this->aics[aicIndex].RaidUnitsRandom; if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] < 1000) { raidUnits = 0; - } else if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] >= 5000) { + } else if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] + >= 5000) { raidUnits *= 2; } diff --git a/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp b/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp index 0afc6660e..56eda5317 100644 --- a/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp +++ b/src/OpenSHC/AI/AICState/setNextMoveLocationForUnits.cpp @@ -16,11 +16,12 @@ namespace AI { // FUNCTION: STRONGHOLDCRUSADER 0x004CE3B0 void AICState::setNextMoveLocationForUnits(int playerID) { - int organismID = (short)DAT_TileMapState::instance.OrganismLayer - [DAT_ViewportRenderState::instance - .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] - .addXgetTile - + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]; + int organismID + = (short)DAT_TileMapState::instance.OrganismLayer + [DAT_ViewportRenderState::instance + .translationMatrix[DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY] + .addXgetTile + + DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX]; if (organismID != 0) { MACRO_CALL_MEMBER(Map::LandscapeState_Func::removeTree, DAT_LandscapeState::ptr)(organismID); } @@ -29,7 +30,8 @@ namespace AI { DAT_PathFindingState::ptr)(DAT_GameState::instance.playerDataArray[playerID].shortestDistanceX, DAT_GameState::instance.playerDataArray[playerID].shortestDistanceY, -1, -1, 4000, FALSE); MACRO_CALL_MEMBER(Map::Navigation::PathFindingState_Func::setDestinationPairsBasedOnPreviousSearch, - DAT_PathFindingState::ptr)(playerID - 1, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); + DAT_PathFindingState::ptr)( + playerID - 1, DAT_GameState::instance.playerDataArray[playerID].attackedPlayerID); } } diff --git a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp index 37f46f67a..94036fdec 100644 --- a/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp +++ b/src/OpenSHC/AI/AICState/setupWorkshopProductionType.cpp @@ -25,8 +25,8 @@ namespace AI { if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == Map::Buildings::BT_BLACKSMITH) { int setting = this->aics[aicIndex].blacksmithSetting; if (setting == -999) { - int itemType = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::chooseProductionItemType, - DAT_BuildingsState::ptr)( + int itemType = MACRO_CALL_MEMBER( + Map::Buildings::BuildingsState_Func::chooseProductionItemType, DAT_BuildingsState::ptr)( DAT_BuildingsState::instance.buildings[buildingID].owner, Map::Buildings::BT_BLACKSMITH); DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)itemType; DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)itemType; @@ -45,8 +45,8 @@ namespace AI { if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == Map::Buildings::BT_POLETURNER) { int setting = this->aics[aicIndex].poleturnerSetting; if (setting == -999) { - int itemType = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::chooseProductionItemType, - DAT_BuildingsState::ptr)( + int itemType = MACRO_CALL_MEMBER( + Map::Buildings::BuildingsState_Func::chooseProductionItemType, DAT_BuildingsState::ptr)( DAT_BuildingsState::instance.buildings[buildingID].owner, Map::Buildings::BT_POLETURNER); DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)itemType; DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)itemType; @@ -65,8 +65,8 @@ namespace AI { if (DAT_BuildingsState::instance.buildings[buildingID].buildingType == Map::Buildings::BT_FLETCHER) { int setting = this->aics[aicIndex].fletcherSetting; if (setting == -999) { - int itemType = MACRO_CALL_MEMBER(Map::Buildings::BuildingsState_Func::chooseProductionItemType, - DAT_BuildingsState::ptr)( + int itemType = MACRO_CALL_MEMBER( + Map::Buildings::BuildingsState_Func::chooseProductionItemType, DAT_BuildingsState::ptr)( DAT_BuildingsState::instance.buildings[buildingID].owner, Map::Buildings::BT_FLETCHER); DAT_BuildingsState::instance.buildings[buildingID].producedItemType = (ResourceTypeShort)itemType; DAT_BuildingsState::instance.buildings[buildingID].producedItemTypeNext = (ResourceTypeShort)itemType; diff --git a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp index ef62ccba5..ea63343e2 100644 --- a/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp +++ b/src/OpenSHC/AI/AICState/shouldDestroyWoodCutterUnk.cpp @@ -2,8 +2,8 @@ #include "OpenSHC/Map/Buildings/BuildingsState.func.hpp" #include "OpenSHC/AI/AICState.hpp" #include "OpenSHC/AI/AITypeA.hpp" -#include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Game/Resources/ResourceType.hpp" +#include "OpenSHC/Map/Buildings/BuildingType.hpp" #include "OpenSHC/Globals/DAT_AIVState.hpp" #include "OpenSHC/Globals/DAT_BuildingsState.hpp" diff --git a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp index 6c3238d9e..f5c367225 100644 --- a/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp +++ b/src/OpenSHC/AI/AICState/smallestTribeOfUnitType.cpp @@ -35,8 +35,8 @@ namespace AI { // end of the function, skipping the "smallestTribeID == 0" check. A goto reproduces this and // matches the assembly much better (~55% vs ~41%), but we avoid goto, so the assignment is // duplicated here. - tribeID = MACRO_CALL_MEMBER( - Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID); + tribeID = MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)( + playerID); DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[offset + i] = (short)tribeID; DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[offset + i] = DAT_TribesState::instance.tribes[tribeID].uid; diff --git a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp index c9c1f2020..f6194c79a 100644 --- a/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp +++ b/src/OpenSHC/AI/AICState/someChatMessageSelection.cpp @@ -48,28 +48,28 @@ namespace AI { if ((DAT_GameSynchronyState::instance.currentAIArray[playerID] != 0) && (DAT_GameState::instance.mapAndTime.playerTeams[playerID] != DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { candidates[candidateCount] = playerID; candidateCount++; } if ((DAT_GameSynchronyState::instance.currentAIArray[playerID + 1] != 0) && (DAT_GameState::instance.mapAndTime.playerTeams[playerID + 1] != DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { candidates[candidateCount] = playerID + 1; candidateCount++; } if ((DAT_GameSynchronyState::instance.currentAIArray[playerID + 2] != 0) && (DAT_GameState::instance.mapAndTime.playerTeams[playerID + 2] != DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { candidates[candidateCount] = playerID + 2; candidateCount++; } if ((DAT_GameSynchronyState::instance.currentAIArray[playerID + 3] != 0) && (DAT_GameState::instance.mapAndTime.playerTeams[playerID + 3] != DAT_GameState::instance.mapAndTime - .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { + .playerTeams[DAT_GameSynchronyState::instance.currentPlayerSlotID])) { candidates[candidateCount] = playerID + 3; candidateCount++; } diff --git a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp index 178a39760..480816f06 100644 --- a/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp +++ b/src/OpenSHC/AI/AICState/teamIsWeakRelativeToEnemy.cpp @@ -29,8 +29,7 @@ namespace AI { } else if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy >= 300) return FALSE; - } else if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy - >= 100) { + } else if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy >= 100) { return FALSE; } } else { @@ -43,8 +42,7 @@ namespace AI { } else if ((int)DAT_GameCore::instance.mapTimeInTicks < 12000) { if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy >= 250) return FALSE; - } else if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy - >= 75) { + } else if (DAT_GameState::instance.playerDataArray[playerID].relativeStrengthOfTeamComparedToEnemy >= 75) { return FALSE; } }