From cd47125598c2672d2f0fbbc9a9e6830d9913abfa Mon Sep 17 00:00:00 2001 From: sourcehold Date: Sun, 19 Jul 2026 18:12:29 +0200 Subject: [PATCH 01/25] 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 00000000..bdd9f731 --- /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 00000000..8f92126f --- /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 00000000..db339291 --- /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 00000000..e9c39df1 --- /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 00000000..82412eba --- /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 00000000..cd1bede8 --- /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 00000000..a9a7fde6 --- /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 00000000..2ef6bf1f --- /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 00000000..c8f602ef --- /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 00000000..4e78da7d --- /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 00000000..e04f4d87 --- /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 00000000..9d849388 --- /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 00000000..d8dceeb3 --- /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 00000000..92afcf35 --- /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 00000000..53cc9576 --- /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 00000000..5e81a2a9 --- /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 00000000..cff5e290 --- /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 00000000..93ea91df --- /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 00000000..43483ef0 --- /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 00000000..47697719 --- /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 00000000..676b02f3 --- /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 00000000..36ab16d6 --- /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 00000000..851e0154 --- /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 02/25] 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 cd1bede8..25aca2c0 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 4e78da7d..ce4ba794 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 00000000..d27a0501 --- /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 00000000..8be83b08 --- /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 00000000..0f772a91 --- /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 00000000..4895c8e2 --- /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 00000000..172e3b81 --- /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 5e81a2a9..5e876dac 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 00000000..01f0675d --- /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 00000000..3d849bf2 --- /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 00000000..42c6a14d --- /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 03/25] 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 82412eba..ca1d6515 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 25aca2c0..29132eb9 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 a9a7fde6..7ddf0e04 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 2ef6bf1f..0227c21c 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 c8f602ef..ac4afab7 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 ce4ba794..221047ca 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 d3ed4a5e..8c35a40a 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 8be83b08..b3697220 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 9d849388..d20a9e2f 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 4895c8e2..2a27d660 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 92afcf35..21e9aeba 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 53cc9576..a762c3c9 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 c1221fa8..981ad02d 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 5e876dac..8f0706f8 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 01f0675d..00000000 --- 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 3d849bf2..1b9dcf37 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 42c6a14d..16c993e2 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 04/25] 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 00000000..6057d908 --- /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 00000000..5f9524b0 --- /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 00000000..55c81532 --- /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 00000000..b4f0895a --- /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 00000000..fb68e284 --- /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 00000000..8168e916 --- /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 00000000..e39cd8bc --- /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 00000000..d54d90ec --- /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 00000000..70816a82 --- /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 00000000..3438b870 --- /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 00000000..79a4d2d2 --- /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 00000000..16bce6ec --- /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 00000000..c92c7b45 --- /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 00000000..45520c9d --- /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 00000000..259138f4 --- /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 00000000..68feb468 --- /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 00000000..3a98835e --- /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 05/25] 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 00000000..104d8e01 --- /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 00000000..2dcf5a1a --- /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 00000000..9c0cb83f --- /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 00000000..ef1b52ec --- /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 00000000..7eedbe48 --- /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 00000000..857e5593 --- /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 00000000..037a2f2f --- /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 00000000..22cda9ad --- /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 00000000..75dc1e34 --- /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 00000000..640f619e --- /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 00000000..7379a3ed --- /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 00000000..7af062fb --- /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 00000000..aeb6e898 --- /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 00000000..383a4e51 --- /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 00000000..8b18080b --- /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 00000000..11260ee9 --- /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 00000000..88bab103 --- /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 00000000..97c182d7 --- /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 00000000..c734a3ff --- /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 00000000..7aaa535d --- /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 00000000..6dd67d99 --- /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 00000000..4f4662e1 --- /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 00000000..b235964f --- /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 00000000..2d99ef4d --- /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 00000000..d3d56f13 --- /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 00000000..8aec4a1c --- /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 00000000..fbab88ed --- /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 00000000..b976cc78 --- /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 00000000..28e61efb --- /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 00000000..4d3b6da3 --- /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 00000000..d8ca7367 --- /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 00000000..b9bf203f --- /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 00000000..1dc39d4b --- /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 00000000..89cacc94 --- /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 00000000..e27c7b59 --- /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 00000000..e216c8c1 --- /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 00000000..5fb4e29c --- /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 00000000..ad2cf43b --- /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 00000000..b1b870c2 --- /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 00000000..45d773b2 --- /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 00000000..fb055692 --- /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 00000000..414009e9 --- /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 06/25] 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 00000000..3cb13057 --- /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 00000000..c3e0c0b6 --- /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 00000000..2305891e --- /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 00000000..e81e060e --- /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 00000000..b3958aa0 --- /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 07/25] 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 2dcf5a1a..216be457 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 9c0cb83f..fb1ce997 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 ef1b52ec..9a2d04fe 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 7eedbe48..fa55cb88 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 857e5593..c9a91b8d 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 037a2f2f..0cc81166 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 22cda9ad..cd5bb7b9 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 6057d908..7001fe9c 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 5f9524b0..c28d2776 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 55c81532..fe11b9a9 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 75dc1e34..20b5496f 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 640f619e..3c745352 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 7379a3ed..c96ca96b 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 7af062fb..c42651ee 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 aeb6e898..d1f3f488 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 383a4e51..5cbcef48 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 d27a0501..40422864 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 8b18080b..b68d9605 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 11260ee9..f161e8f1 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 88bab103..55622a56 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 97c182d7..85d25c03 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 c734a3ff..9187b70c 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 7aaa535d..0007cf99 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 b4f0895a..32fca083 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 0f772a91..8a56546e 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 fb68e284..b118a2cc 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 6dd67d99..9b205892 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 4f4662e1..d544ada7 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 b235964f..dbef793f 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 2d99ef4d..ea8497a8 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 d3d56f13..62fd7fb6 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 8aec4a1c..484a7fbb 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 fbab88ed..b9afb883 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 b976cc78..e6528e25 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 28e61efb..93c274c9 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 4d3b6da3..a2b044f2 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 d8ca7367..2a4c1101 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 b9bf203f..a0679b77 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 1dc39d4b..fc2a1bac 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 89cacc94..e9565887 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 e27c7b59..02745d87 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 e216c8c1..110bb938 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 5fb4e29c..97437bc3 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 ad2cf43b..a733ce5f 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 e39cd8bc..791472b6 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 d54d90ec..f595abbd 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 70816a82..86bc9971 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 3438b870..b81436f3 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 79a4d2d2..8b0339ef 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 172e3b81..0689b241 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 16bce6ec..77248973 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 c92c7b45..b44d4a6c 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 45520c9d..2290c59f 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 259138f4..87e451e4 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 68feb468..d374436e 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 3a98835e..52613f2e 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 b1b870c2..a7b0d34e 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 45d773b2..7cfb1dbd 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 fb055692..9633dd0c 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 414009e9..20ee5094 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 08/25] 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 e9c39df1..2d3d8b87 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 00000000..1ae3180d --- /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 9a2d04fe..2939e158 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 00000000..0181f825 --- /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 00000000..46b561d3 --- /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 00000000..f4a02fbc --- /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 00000000..e4b5a135 --- /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 fe11b9a9..3f1f25be 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 00000000..ec0e19d7 --- /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 00000000..3f67ced0 --- /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 00000000..0de10b08 --- /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 3c745352..4b40f07e 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 00000000..3b011e85 --- /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 00000000..b9e473e2 --- /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 00000000..50877b90 --- /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 00000000..74dfe4fd --- /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 00000000..a1c8bb33 --- /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 00000000..d2308602 --- /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 00000000..173aa064 --- /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 00000000..8bf86d29 --- /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 5cbcef48..f3cfc892 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 00000000..27cb9b4c --- /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 00000000..595a02e1 --- /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 00000000..91ef8a70 --- /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 00000000..ca0fa349 --- /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 00000000..54810680 --- /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 00000000..d701a1a3 --- /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 00000000..e73d9dff --- /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 00000000..3143812d --- /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 00000000..2d0d9f26 --- /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 00000000..e58e3615 --- /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 00000000..59f8a77c --- /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 85d25c03..e34daac0 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 00000000..ecdd9457 --- /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 00000000..41f1ba2e --- /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 00000000..531b03ab --- /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 00000000..68b44974 --- /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 00000000..581d2e86 --- /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 00000000..3b82b7d3 --- /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 00000000..5cb3f087 --- /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 00000000..fcf4860b --- /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 00000000..b9bce306 --- /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 00000000..6c36b0a2 --- /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 00000000..0228ab5f --- /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 32fca083..d550e65f 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 00000000..414d34b9 --- /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 8168e916..17c068b4 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 00000000..4c1c47ab --- /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 00000000..46999d70 --- /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 00000000..18634bdf --- /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 00000000..8d942cd2 --- /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 00000000..c9b015a8 --- /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 a0679b77..b520df92 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 e9565887..cc48af4e 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 00000000..7eaedffb --- /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 00000000..c9ffdb38 --- /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 00000000..a25c3950 --- /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 00000000..6213b44c --- /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 00000000..8ab398ad --- /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 a733ce5f..78ed1689 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 00000000..21cd5785 --- /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 00000000..34db026d --- /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 00000000..6367b31c --- /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 00000000..20c9e32d --- /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 00000000..b9af53ac --- /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 00000000..1b1c2239 --- /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 00000000..072e4b84 --- /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 00000000..412497ce --- /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 00000000..83b89971 --- /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 00000000..afc77615 --- /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 00000000..429bb500 --- /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 00000000..3cd36393 --- /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 00000000..6870e836 --- /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 8b0339ef..dd0c25b0 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 00000000..db61864a --- /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 00000000..b5d4cdd8 --- /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 00000000..2a28425d --- /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 00000000..84fc2c94 --- /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 00000000..fbc4839a --- /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 00000000..28bd5aac --- /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 00000000..0d6b6afb --- /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 00000000..9f6a82e8 --- /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 00000000..a09be5a2 --- /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 00000000..be05cbf9 --- /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 00000000..c5590667 --- /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 00000000..db36e5ca --- /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 00000000..98b8a0d2 --- /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 2a27d660..339f09d8 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 77248973..79dbdfb5 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 00000000..e8bcb8cd --- /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 00000000..072dc667 --- /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 00000000..080fa0a9 --- /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 00000000..f7b90a16 --- /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 00000000..80ba930b --- /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 47697719..e16bf1b2 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 676b02f3..d2a7df33 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 a7b0d34e..e4b8ffcd 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 00000000..7a9a56b3 --- /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 9633dd0c..63e7743b 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 00000000..258a3215 --- /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 00000000..6946450d --- /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 00000000..b864cfc3 --- /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 00000000..22deecfe --- /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 00000000..65cc46e7 --- /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 00000000..8011403c --- /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 00000000..ff4f4d85 --- /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 20ee5094..2a2e2abc 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 851e0154..975bfa83 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 09/25] 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 20b5496f..55025b43 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 27cb9b4c..9a0ea9e4 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 581d2e86..bc11333d 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 d550e65f..5862623d 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 c9b015a8..dd0c5b81 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 d544ada7..fed855c2 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 fc2a1bac..3be00819 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 0689b241..7910e23a 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 10/25] 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 fb1ce997..402f0e20 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 ec0e19d7..704837ea 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 55025b43..a48ad6d5 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 3f67ced0..32b7b368 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 50877b90..22307f6a 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 a1c8bb33..8ccc1c4d 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 173aa064..1f3a4f19 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 29132eb9..8f077577 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 8bf86d29..7bd2e0f1 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 595a02e1..b180166d 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 ca0fa349..5d3637d4 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 2d0d9f26..ca79afa7 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 59f8a77c..5e71e48d 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 55622a56..42b5dde6 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 e34daac0..29895258 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 e04f4d87..108bf6d8 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 68b44974..2420b23f 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 0007cf99..24934a4d 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 3b82b7d3..daeffb4e 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 6c36b0a2..a4632438 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 0228ab5f..eb6658bc 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 5862623d..fe3050b2 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 8a56546e..28dffd26 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 414d34b9..620439b2 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 7eaedffb..a6a3f9d4 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 b9af53ac..be79bfac 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 412497ce..f4283f86 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 3cd36393..73e501ba 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 080fa0a9..3c35fb36 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 f7b90a16..2ce93575 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 d374436e..c0e9f4f2 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 43483ef0..4ba34629 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 52613f2e..544c8e38 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 e4b8ffcd..086bf948 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 258a3215..eda86856 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 6946450d..09488387 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 b864cfc3..88a716c3 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 22deecfe..8ff7b185 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 65cc46e7..d84f52f9 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 11/25] 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 d2308602..68d583f0 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 46999d70..69cfc411 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 db61864a..50779533 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 88a716c3..607b9a75 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 12/25] 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 68d583f0..ba171bf2 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 69cfc411..eaaa3fd9 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 50779533..4c459302 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 13/25] 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 402f0e20..c26db36f 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 46b561d3..165cf293 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 704837ea..c5e339c2 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 32b7b368..f1a374dc 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 ba171bf2..810c29fc 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 9a0ea9e4..900f0e7a 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 b180166d..73e758d0 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 91ef8a70..86ca327e 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 54810680..2cdeef7f 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 2420b23f..7059f8a9 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 bc11333d..1fddcaf4 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 5cb3f087..cd9b3b5e 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 b9bce306..4e463ac1 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 4c1c47ab..7d2f22dd 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 eaaa3fd9..4e4a6a0e 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 8d942cd2..e98776b5 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 a6a3f9d4..2ecd2604 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 c9ffdb38..24deba5f 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 1b1c2239..75b65a9e 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 f4283f86..f0ef6d94 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 83b89971..7b01dc9c 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 429bb500..5e202cb2 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 6870e836..66d46dc7 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 4c459302..3413b263 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 b5d4cdd8..6683a569 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 086bf948..02619dda 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 7a9a56b3..43f52c12 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 eda86856..ff18d5cb 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 8011403c..b5ec39df 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 14/25] 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 f4a02fbc..4d458992 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 c5e339c2..fb783db4 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 a48ad6d5..90ab12ec 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 f1a374dc..eaf78554 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 810c29fc..a80d0065 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 3143812d..e833529d 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 5e71e48d..5d078d37 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 7059f8a9..d8525fab 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 4e4a6a0e..6de76caf 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 73e501ba..2d8aad2b 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 3413b263..4ad45f3f 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 15/25] 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 4ad45f3f..00653f14 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 16/25] 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 165cf293..61e3f397 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 17/25] 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 61e3f397..1e64d7c9 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 18/25] 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 4d458992..cee33b45 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 19/25] 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 7001fe9c..ffd86e8b 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 e4b5a135..8dd97308 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 c28d2776..bf47a5df 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 20/25] 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 1e64d7c9..de707eeb 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 fb783db4..886073a2 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 86ca327e..913be600 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 2cdeef7f..e0180814 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 e73d9dff..bb31d983 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 e833529d..7f28e426 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 42b5dde6..8f1d56ea 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 29895258..3cff7bcb 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 d8525fab..e896ea9e 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 4e463ac1..a224fd2e 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 7d2f22dd..540b6cdd 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 00000000..09d8f657 --- /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 e98776b5..dba68ea4 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 2ecd2604..b53a16f1 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 24deba5f..0fc1d175 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 a25c3950..3964e391 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 6213b44c..199d93ec 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 8ab398ad..3396df9e 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 21cd5785..f497eabd 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 6367b31c..46687d25 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 66d46dc7..54406b44 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 c0e9f4f2..7b9edebb 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 cff5e290..51ca9393 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 93ea91df..5ef58f27 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 4ba34629..d14e60a1 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 e16bf1b2..6c80452e 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 544c8e38..c1ac9a6b 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 d2a7df33..83caadc1 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 36ab16d6..db2fd86b 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 43f52c12..a92dbbe8 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 607b9a75..c0bee72c 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 b5ec39df..2b4bb448 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 ff4f4d85..3f47b327 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 2a2e2abc..ed4a0203 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 975bfa83..00000000 --- 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 21/25] 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 f0ef6d94..643d5642 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 22/25] 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 2b4bb448..f3e1e0af 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 23/25] 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 3cb13057..d085d91a 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 24/25] 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 2305891e..7f8f963a 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 e81e060e..91312740 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 b3958aa0..ad9eb85f 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 2a28425d..b80d1635 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 84fc2c94..9e00fc0d 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 fbc4839a..038ccf90 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 28bd5aac..1000c850 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 0d6b6afb..8b1e50bc 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 9f6a82e8..2296787e 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 a09be5a2..d2c250af 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 be05cbf9..1bfe3d4e 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 c5590667..91bb5efe 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 db36e5ca..f05d8235 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 98b8a0d2..d7e7a439 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 25/25] 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 9e00fc0d..589ad5bd 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;