Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions src/OpenSHC/AI/AIVState/aiDecideOnNewBuildings.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include "../AIVState.func.hpp"

#include "OpenSHC/AI/AICState.func.hpp"

#include "OpenSHC/Globals/DAT_AICState.hpp"
#include "OpenSHC/Globals/DAT_GameState.hpp"

namespace OpenSHC {
namespace AI {

// FUNCTION: STRONGHOLDCRUSADER 0x004F15C0
void AIVState::aiDecideOnNewBuildings(int playerID)
{
int const aivID = DAT_GameState::instance.playerDataArray[playerID].aivID;
int isPausing = 0;

if (aivID <= 0) {
return;
}

int stepIncrement = 1;

if (DAT_GameState::instance.playerDataArray[playerID].resourceRebuildDelay != 0) {
++DAT_GameState::instance.playerDataArray[playerID].resourceRebuildDelay;
if (DAT_GameState::instance.playerDataArray[playerID].resourceRebuildDelay
< MACRO_CALL_MEMBER(AICState_Func::getResourceRebuildDelay, DAT_AICState::ptr)(playerID)) {
return;
}
DAT_GameState::instance.playerDataArray[playerID].resourceRebuildDelay = 0;
}

if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD] > 16000) {
// rich
stepIncrement = 2;
} else if (DAT_GameState::instance.playerDataArray[playerID].currentResources[Game::Resources::RT_GOLD]
> 5000) {
stepIncrement = 1;
} else {
// poor
++this->aivs[aivID].aivPoorCounter;
if (this->aivs[aivID].aivPoorCounter < this->aivs[aivID].aivPoorLimit_OR_AIC_buildInterval) {
return;
}
}
this->aivs[aivID].aivPoorCounter = 0;

++DAT_GameState::instance.playerDataArray[playerID].aiResourceBuildingFocusIndicator;
if (DAT_GameState::instance.playerDataArray[playerID].aiResourceBuildingFocusIndicator >= 5) {
DAT_GameState::instance.playerDataArray[playerID].aiResourceBuildingFocusIndicator = 0;
}
if (DAT_GameState::instance.playerDataArray[playerID].aiResourceBuildingFocusIndicator == 0) {
if (!MACRO_CALL_MEMBER(AICState_Func::shouldDestroyWoodCutterUnk, DAT_AICState::ptr)(playerID)
&& MACRO_CALL_MEMBER(AICState_Func::aiShouldBuildWoodcutter, DAT_AICState::ptr)(playerID)) {
MACRO_CALL_MEMBER(AIVState_Func::aiPlaceWoodcuttershut, this)(playerID);
}
} else if (DAT_GameState::instance.playerDataArray[playerID].aiResourceBuildingFocusIndicator == 1) {
if (MACRO_CALL_MEMBER(AICState_Func::aiShouldBuildFarm, DAT_AICState::ptr)(playerID)
&& MACRO_CALL_MEMBER(AIVState_Func::aiPlaceFarm, this)(playerID,
(MappersEnum)MACRO_CALL_MEMBER(AICState_Func::aiFarmChoice, DAT_AICState::ptr)(playerID))) {
MACRO_CALL_MEMBER(AICState_Func::setNextFarmTypeToBuild, DAT_AICState::ptr)(playerID);
}
} else if (DAT_GameState::instance.playerDataArray[playerID].aiResourceBuildingFocusIndicator == 2) {
if (MACRO_CALL_MEMBER(AICState_Func::aiShouldBuildQuarry, DAT_AICState::ptr)(playerID)) {
MACRO_CALL_MEMBER(AIVState_Func::aiPlaceQuarryAndOxtether, this)(playerID);
}
if (MACRO_CALL_MEMBER(AICState_Func::aiRequiresExtraOxtethers, DAT_AICState::ptr)(playerID)) {
MACRO_CALL_MEMBER(AIVState_Func::aiPlaceAdditionalOxtether, this)(playerID);
}
} else if (DAT_GameState::instance.playerDataArray[playerID].aiResourceBuildingFocusIndicator == 3) {
if (MACRO_CALL_MEMBER(AICState_Func::aiShouldBuildIronMine, DAT_AICState::ptr)(playerID)) {
MACRO_CALL_MEMBER(AIVState_Func::aiPlaceIronMine, this)(playerID);
}
} else if (DAT_GameState::instance.playerDataArray[playerID].aiResourceBuildingFocusIndicator == 4) {
if (MACRO_CALL_MEMBER(AICState_Func::aiShouldBuildPitchrig, DAT_AICState::ptr)(playerID)) {
MACRO_CALL_MEMBER(AIVState_Func::aiPlacePitchrig, this)(playerID);
}
}

if (DAT_GameState::instance.playerDataArray[playerID].aivCurrentPause != 0) {
if (stepIncrement > 1) {
DAT_GameState::instance.playerDataArray[playerID].aivCurrentPause = 0;
} else {
--DAT_GameState::instance.playerDataArray[playerID].aivCurrentPause;
}
isPausing = 1;
} else {
int const pauseStep
= DAT_GameState::instance.playerDataArray[playerID]
.aivPauses[DAT_GameState::instance.playerDataArray[playerID].aivCurrentPauseIndex];
if (pauseStep > 0 && this->aivs[aivID].currentStepGoal >= pauseStep) {
DAT_GameState::instance.playerDataArray[playerID].aivCurrentPause
= DAT_GameState::instance.playerDataArray[playerID].aivPauseDelay;
++DAT_GameState::instance.playerDataArray[playerID].aivCurrentPauseIndex;
return;
}
// the step goal can advance by 2 when the player is rich
this->aivs[aivID].currentStepGoal += stepIncrement;
}

if (this->aivs[aivID].aivSubType == 0) {
MACRO_CALL_MEMBER(AIVState_Func::executeDefaultCastleAIV, this)(playerID, isPausing);
} else if (!MACRO_CALL_MEMBER(AICState_Func::destroyHouse, DAT_AICState::ptr)(playerID)) {
for (int step = 1; step <= this->aivs[aivID].totalSteps && step <= this->aivs[aivID].currentStepGoal;
++step) {
if (MACRO_CALL_MEMBER(AIVState_Func::aiPlaceAIVBuilding, this)(playerID, step, isPausing)) {
break;
}
}
}
MACRO_CALL_MEMBER(AIVState_Func::aiPlaceFlag, this)(playerID);
MACRO_CALL_MEMBER(AIVState_Func::aiPlaceBrazier, this)(playerID);
}

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

#include "OpenSHC/Map/Entities/EntityState.func.hpp"
#include "OpenSHC/Map/TileMapState.func.hpp"
#include "OpenSHC/AI/AIVUnitType.hpp"

#include "OpenSHC/Globals/DAT_AICState.hpp"
#include "OpenSHC/Globals/DAT_EntityState.hpp"
#include "OpenSHC/Globals/DAT_GameState.hpp"
#include "OpenSHC/Globals/DAT_TileMapState.hpp"
#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp"

namespace OpenSHC {
namespace AI {

// FUNCTION: STRONGHOLDCRUSADER 0x004ED240
void AIVState::aiPlaceFlag(int playerID)
{
Map::Entities::EntityType const flagType
= (Map::Entities::EntityType)DAT_AICState::instance
.aics[DAT_GameState::instance.playerDataArray[playerID].aiType - 1]
.flagType;
if (DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlotLocationCount[AIVUT_FLAG] <= 0) {
return;
}
for (int i = 0; i < 10; ++i) {
int const tile = DAT_GameState::instance.playerDataArray[playerID].aivUnitLocationSlots[AIVUT_FLAG][i];
if (tile <= 0) {
continue;
}
int const entityID = DAT_TileMapState::instance.EntityLayer[tile];
if (entityID != 0 && DAT_EntityState::instance.entityArray[entityID].entityType == flagType) {
continue;
}
int const height
= MACRO_CALL_MEMBER(Map::TileMapState_Func::getTotalHeightAt, DAT_TileMapState::ptr)(tile, playerID);
if (height <= 0) {
continue;
}
MACRO_CALL_MEMBER(Map::Entities::EntityState_Func::spawnProjectileEntity, DAT_EntityState::ptr)(0, playerID,
playerID,
(tile
- DAT_ViewportRenderState::instance
.translationMatrix[DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile]]
.addXgetTile)
* 8
+ 4,
DAT_ViewportRenderState::instance.tileTranslationMatrix_YComponent[tile] * 8 + 4, height, 0, 0, 0,
flagType, 0);
}
}

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

#include "OpenSHC/Game/GameStateStructures.func.hpp"
#include "OpenSHC/Map/TileMapState.func.hpp"

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

namespace OpenSHC {
namespace AI {

// FUNCTION: STRONGHOLDCRUSADER 0x004EFAB0
void AIVState::aiPlaceWoodcuttershut(int playerID)
{
if (!MACRO_CALL_MEMBER(Game::GameStateStructures_Func::checkRequiredResourcesForBuildingOrPlanToBuy,
DAT_GameState::ptr)(Commands::M_MAPPER_WOODSMAN, playerID, FALSE)
|| DAT_BuildingsState::instance.unknownCountdown01 < 20) {
return;
}
MACRO_CALL_MEMBER(AIVState_Func::findAppropriateWoodCutterGridLocation, this)(playerID);
if (this->buildingApproriateGridXPosition == -1) {
return;
}
this->heatMaps[(uint)this->buildingApproriateGridXPosition][(uint)this->buildingAppropriateGridYPosition]
.woodRelatedCountdownTo0 = 4;
// search around the result of the woodcutter search
MACRO_CALL_MEMBER(AIVState_Func::findSuitableGridLocationFittingCriteria, this)(
this->buildingApproriateGridXPosition, this->buildingAppropriateGridYPosition);
if (this->buildingApproriateGridXPosition == -1) {
return;
}
++this->heatMaps[(uint)this->buildingApproriateGridXPosition][(uint)this->buildingAppropriateGridYPosition]
.structureCount;
MACRO_CALL_MEMBER(Map::TileMapState_Func::placeBuilding, DAT_TileMapState::ptr)(playerID,
this->buildingApproriateGridXPosition * 5, this->buildingAppropriateGridYPosition * 5,
Commands::M_MAPPER_WOODSMAN,
MACRO_CALL_MEMBER(Map::TileMapState_Func::getBuildingSizeForCommandBuildingType, DAT_TileMapState::ptr)(
Commands::M_MAPPER_WOODSMAN),
15);
}

}
}
Loading