Skip to content
Merged
14 changes: 14 additions & 0 deletions src/OpenSHC/AI/AICState/Constructor_AICState.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "../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;
}
}
}
23 changes: 23 additions & 0 deletions src/OpenSHC/AI/AICState/abortAttackAndGoIdle.cpp
Original file line number Diff line number Diff line change
@@ -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;
}

}
}
30 changes: 30 additions & 0 deletions src/OpenSHC/AI/AICState/addBuildingToTargetableBuildings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "../AICState.func.hpp"

#include "OpenSHC/Game/GameMode.hpp"

#include "OpenSHC/Globals/DAT_BuildingsState.hpp"
#include "OpenSHC/Globals/DAT_GameState.hpp"
#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp"

namespace OpenSHC {
namespace AI {

// FUNCTION: STRONGHOLDCRUSADER 0x004CDA50
void AICState::addBuildingToTargetableBuildings(int buildingID)
{
int const owner = DAT_BuildingsState::instance.buildings[buildingID].owner;
if (DAT_GameSynchronyState::instance.currentGameMode == Game::GM_SOLITARY)
return;
if (DAT_GameState::instance.playerDataArray[owner].top100TargetableBuildingsTracker >= 100)
return;
if (DAT_BuildingsState::instance.buildings[buildingID].fireDuration != 0)
return;

DAT_GameState::instance.playerDataArray[owner]
.top100TargetableBuildings[DAT_GameState::instance.playerDataArray[owner].top100TargetableBuildingsTracker]
= buildingID;
DAT_GameState::instance.playerDataArray[owner].top100TargetableBuildingsTracker++;
}

}
}
44 changes: 44 additions & 0 deletions src/OpenSHC/AI/AICState/addEngineersToSelection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#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/Map/Units/UnitType.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 const tribeID
= MACRO_CALL_MEMBER(Map::Units::TribesState_Func::createTribeForPlayer, DAT_TribesState::ptr)(playerID);
for (int unitID = 1; unitID < (int)DAT_UnitsState::instance.maxUnitCount; unitID++) {
if (unitCount <= 0)
break;
if (DAT_UnitsState::instance.units[unitID].logicalState != Map::Units::ULS_NORMAL)
continue;
if (DAT_UnitsState::instance.units[unitID].owner != playerID)
continue;
if (DAT_UnitsState::instance.units[unitID].dying != 0)
continue;
if (DAT_UnitsState::instance.units[unitID].unitType != Map::Units::UT_E_ENGINEER)
continue;
if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType != 10)
continue;
if (DAT_UnitsState::instance.units[unitID].tribeID != 0)
continue;
if (DAT_UnitsState::instance.units[unitID].state.generic == Map::Units::States::US_STAND_UPUnk)
continue;

MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID);
unitCount--;
}
return tribeID;
}

}
}
27 changes: 27 additions & 0 deletions src/OpenSHC/AI/AICState/addUnitToSmallestPatrolTribe.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "../AICState.func.hpp"

#include "OpenSHC/Map/Units/TribesState.func.hpp"
#include "OpenSHC/AI/AITypeA.hpp"

#include "OpenSHC/Globals/DAT_GameState.hpp"
#include "OpenSHC/Globals/DAT_TribesState.hpp"
#include "OpenSHC/Globals/DAT_UnitsState.hpp"

namespace OpenSHC {
namespace AI {

// FUNCTION: STRONGHOLDCRUSADER 0x004D2730
void AICState::addUnitToSmallestPatrolTribe(int unitID)
{
int const owner = DAT_UnitsState::instance.units[unitID].owner;
if (DAT_GameState::instance.playerDataArray[owner].aiType == AITA_NULL)
return;
int const aicIndex = DAT_GameState::instance.playerDataArray[owner].aiType - 1;

DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType = 4;
int const tribeID = MACRO_CALL_MEMBER(AICState_Func::getSmallestPatrolTribe, this)(
owner, this->aics[aicIndex].OuterPatrolGroupsCount);
MACRO_CALL_MEMBER(Map::Units::TribesState_Func::addUnitToTribe, DAT_TribesState::ptr)(unitID, tribeID);
}
}
}
45 changes: 45 additions & 0 deletions src/OpenSHC/AI/AICState/aiChoiceAttForceRallyPercentage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "../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 {

// FUNCTION: STRONGHOLDCRUSADER 0x004CEC80
BOOLEnum AICState::aiChoiceAttForceRallyPercentage(int playerID)
{
int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType;
if (aiType == OpenSHC::AI::AIT_NULL)
return FALSE;
int const aicIndex = aiType - 1;

int activeTribes = 0;
int rallyingTribes = 0;
for (int i = 0; i < 11; i++) {
int const tribeType = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeType;
int const tribeCount = DAT_SkirmishDefinedData::instance.MaxAttackTribes1[i].tribeCount;
for (int j = 0; j < tribeCount; j++) {
int const tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeType + j];
if (tribeID == 0)
continue;
if (DAT_TribesState::instance.tribes[tribeID].uid
!= DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[j + tribeType])
continue;

activeTribes++;
if (DAT_TribesState::instance.tribes[tribeID].percentageMovingUnk < 20)
rallyingTribes++;
}
}

if (activeTribes <= 0)
return FALSE;
return rallyingTribes * 100 / activeTribes >= this->aics[aicIndex].AttForceRallyPercentage;
}

}
}
102 changes: 102 additions & 0 deletions src/OpenSHC/AI/AICState/aiCommandSiegeEngineTribes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include "../AICState.func.hpp"

#include "OpenSHC/Map/Navigation/DirectionAlgorithmState.func.hpp"
#include "OpenSHC/Map/Units/TribesState.func.hpp"
#include "OpenSHC/Map/Units/Instructions/UnitMatchSpeedEnum.hpp"
#include "OpenSHC/Map/Units/SomeTribeBehaviorType.hpp"
#include "OpenSHC/Map/Units/UnitLogicState.hpp"
#include "OpenSHC/Map/Units/UnitType.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 namespace OpenSHC::Map::Units;

// FUNCTION: STRONGHOLDCRUSADER 0x004CFCD0
void AICState::aiCommandSiegeEngineTribes(int playerID)
{
int shieldTargetTribeIDs[3];
shieldTargetTribeIDs[0] = 0;
shieldTargetTribeIDs[1] = 0;
shieldTargetTribeIDs[2] = 0;
int targetCount = 0;
for (int i = 186; i < 189; i++) {
int tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[i];
if (tribeID == 0)
continue;
if (DAT_TribesState::instance.tribes[tribeID].uid
!= DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[i])
continue;
shieldTargetTribeIDs[targetCount] = tribeID;
targetCount++;
}

int shieldCount = 0;
for (int unitID = 1; unitID < 2500; unitID++) {
if (DAT_UnitsState::instance.units[unitID].logicalState == ULS_INVISIBLE)
continue;
if (DAT_UnitsState::instance.units[unitID].unitType != UT_S_TOWER
&& DAT_UnitsState::instance.units[unitID].unitType != UT_S_BATTERINGRAM
&& DAT_UnitsState::instance.units[unitID].unitType != UT_S_SHIELD)
continue;
if (DAT_UnitsState::instance.units[unitID].unknownSiegeTentRelated02 != 3)
continue;
if (DAT_UnitsState::instance.units[unitID].aiUnitBehaviourType == 21)
continue;

if (DAT_UnitsState::instance.units[unitID].unitType == UT_S_TOWER) {
int tribeID = DAT_UnitsState::instance.units[unitID].tribeID;
if (tribeID == 0)
continue;
if (DAT_TroopValueState::instance.attackInfo.playerInfo[playerID - 1].wide3 != 0)
MACRO_CALL_MEMBER(TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(
tribeID, STBT_0x414);
} else if (DAT_UnitsState::instance.units[unitID].unitType == UT_S_BATTERINGRAM) {
int tribeID = DAT_UnitsState::instance.units[unitID].tribeID;
if (tribeID == 0)
continue;
if (DAT_TroopValueState::instance.attackInfo.playerInfo[playerID - 1].gate2 != 0)
MACRO_CALL_MEMBER(TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(
tribeID, STBT_0x3f6);
else if (DAT_TroopValueState::instance.attackInfo.playerInfo[playerID - 1].wide3 != 0)
MACRO_CALL_MEMBER(TribesState_Func::assignAttackTargetsForTribe, DAT_TribesState::ptr)(
tribeID, STBT_0x413);
} else if (DAT_UnitsState::instance.units[unitID].unitType == UT_S_SHIELD) {
int tribeID = DAT_UnitsState::instance.units[unitID].tribeID;
if (tribeID == 0)
continue;
if (shieldCount >= 3)
continue;

int const targetTribeID = shieldTargetTribeIDs[shieldCount];
DAT_TribesState::instance.tribes[tribeID].supportTribeID = targetTribeID;
DAT_TribesState::instance.tribes[tribeID].uid2 = DAT_TribesState::instance.tribes[targetTribeID].uid;
DAT_TribesState::instance.tribes[targetTribeID].tribeID = tribeID;
int const targetUnitID = DAT_TribesState::instance.tribes[targetTribeID].selectionTargetUnitID;
int const tile = DAT_UnitsState::instance.units[targetUnitID].tile;
shieldCount++;
if (tile <= 0)
continue;

int const y = DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile];
int const x = tile - DAT_ViewportRenderState::instance.translationMatrix[y].addXgetTile;
MACRO_CALL_MEMBER(TribesState_Func::giveTribeMoveInstruction, DAT_TribesState::ptr)(
tribeID, x, y, 0, 0, Instructions::UMSE_0);
MACRO_CALL_MEMBER(
OpenSHC::Map::Navigation::DirectionAlgorithmState_Func::calculatePreferredRelativeOrientation,
DAT_DirectionAlgorithmState::ptr)(DAT_UnitsState::instance.units[targetUnitID].x,
DAT_UnitsState::instance.units[targetUnitID].y, x, y);
DAT_TribesState::instance.tribes[tribeID].orientation
= DAT_DirectionAlgorithmState::instance.orientation;
}
}
}
}
}
37 changes: 37 additions & 0 deletions src/OpenSHC/AI/AICState/aiCommandTribe11StandGroundToGate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "../AICState.func.hpp"

#include "OpenSHC/Map/Units/TroopValueState.func.hpp"
#include "OpenSHC/AI/AITypeA.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 tribeIndex = 11;
if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL)
return;
int const tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeIndex];
if (tribeID == 0)
return;
if (DAT_TribesState::instance.tribes[tribeID].uid
!= DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[tribeIndex])
return;
if (DAT_TribesState::instance.tribes[tribeID].selectionTargetUnitID == 0)
return;

DAT_TribesState::instance.tribes[tribeID].unitStance = Map::Units::Behavior::USE_STAND_GROUND;
if (MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTribeToNearbyGatehouse, DAT_TroopValueState::ptr)(
tribeID)
== 0)
MACRO_CALL_MEMBER(Map::Units::TroopValueState_Func::moveTowardsParticularUnits, DAT_TroopValueState::ptr)(
tribeID);
}
}
}
34 changes: 34 additions & 0 deletions src/OpenSHC/AI/AICState/aiCommandTribe13DefensiveWave.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "../AICState.func.hpp"

#include "OpenSHC/Map/Units/TribesState.func.hpp"
#include "OpenSHC/AI/AITypeA.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"

namespace OpenSHC {
namespace AI {

// FUNCTION: STRONGHOLDCRUSADER 0x004CF270
void AICState::aiCommandTribe13DefensiveWave(int playerID)
{
int tribeIndex = 13;
Comment thread
gynt marked this conversation as resolved.
if (DAT_GameState::instance.playerDataArray[playerID].aiType == AITA_NULL)
return;
int const tribeID = DAT_GameState::instance.playerDataArray[playerID].aiTribeIDs[tribeIndex];
if (tribeID == 0)
return;
if (DAT_TribesState::instance.tribes[tribeID].uid
!= DAT_GameState::instance.playerDataArray[playerID].aiTribeUIDs[tribeIndex])
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);
}
}
}
19 changes: 19 additions & 0 deletions src/OpenSHC/AI/AICState/aiFarmChoice.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "../AICState.func.hpp"

#include "OpenSHC/AI/AITypeA.hpp"

#include "OpenSHC/Globals/DAT_GameState.hpp"

namespace OpenSHC {
namespace AI {

// FUNCTION: STRONGHOLDCRUSADER 0x004CB180
int AICState::aiFarmChoice(int playerID)
{
int const aiType = DAT_GameState::instance.playerDataArray[playerID].aiType;
if (aiType == AITA_NULL)
return 0;
return (&this->aics[aiType - 1].farm1)[DAT_GameState::instance.playerDataArray[playerID].aiFarmIndex];
Comment thread
gynt marked this conversation as resolved.
}
}
}
Loading
Loading