Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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);
}

}
}
2 changes: 1 addition & 1 deletion src/OpenSHC/AI/AIVState/aiPlaceAIVBuilding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ namespace AI {
orientation);
int const placedID = DAT_TileMapState::instance.placedBuildingID;
if (!DAT_TileMapState::instance.buildingPlacementFail) {
DAT_BuildingsState::instance.buildings[placedID].field240_0x2c8 = 1;
DAT_BuildingsState::instance.buildings[placedID].field202_0x2c8 = 1;
MACRO_CALL_MEMBER(AICState_Func::setupWorkshopProductionType, DAT_AICState::ptr)(playerID, placedID);
}
if (!DAT_TileMapState::instance.buildingPlacementFail) {
Expand Down
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