Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Customized] AI base construction modification #1470

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ This page lists all the individual contributions to the project by their author.
- Fix aircraft `MovementZone` and `SpeedType` inconsistencies
- Use 2D distance instead of 3D to check whether in air team members have arrived destination
- Enhanced Straight trajectory
- AI base construction modification
- **Ollerus**
- Build limit group enhancement
- Customizable rocker amplitude
Expand Down
17 changes: 17 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,23 @@ SpyEffect.VictimSuperWeapon= ; SuperWeaponType
SpyEffect.InfiltratorSuperWeapon= ; SuperWeaponType
```

### AI base construction modification

- AI can now have some new behaviors.
- `AIAutoDeployMCV` controls whether AI will still automatically deploy the mcv after owning a construction yard.
- `AISetBaseCenter` controls whether AI will still set the newly deployed construction yard as the base center after owning a construction yard.
- `AIBiasSpawnCell` controls whether AI will preferentially select the construction yard close to the birth point as the base center (useless in campaign).
- `AIForbidConYard` controls whether AI cannot place buildings with `ConstructionYard=true`. AI will try to build one after a construction yard is destroyed but will not put it down. After that, it will continue to build other buildings. Building a construction yard will still take some time. You can try to reduce the build time of it.

In `rulesmd.ini`:
```ini
[AI]
AIAutoDeployMCV=true ; boolean
AISetBaseCenter=true ; boolean
AIBiasSpawnCell=false ; boolean
AIForbidConYard=false ; boolean
```

## Infantry

### Customizable FLH When Infantry Is Prone Or Deployed
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ New:
- Allow infantry to use land sequences in water (by Starkku)
- `<Player @ X>` can now be used as owner for pre-placed objects on skirmish and multiplayer maps (by Starkku)
- Allow customizing charge turret delays per burst on a weapon (by Starkku)
- AI base construction modification (by CrimRecya)
- Unit `Speed` setting now accepts floating point values (by Starkku)
- Custom exit cell for infantry factory (by Starkku)

Expand Down
108 changes: 108 additions & 0 deletions src/Ext/House/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,114 @@ DEFINE_HOOK(0x7015C9, TechnoClass_Captured_UpdateTracking, 0x6)

#pragma endregion

#pragma region AIConstructionYard

DEFINE_HOOK(0x740A11, UnitClass_Mission_Guard_AIAutoDeployMCV, 0x6)
{
enum { SkipGameCode = 0x740A50 };

GET(UnitClass*, pMCV, ESI);

return (!RulesExt::Global()->AIAutoDeployMCV && pMCV->Owner->NumConYards > 0) ? SkipGameCode : 0;
}

DEFINE_HOOK(0x739889, UnitClass_TryToDeploy_AISetBaseCenter, 0x6)
{
enum { SkipGameCode = 0x73992B };

GET(UnitClass*, pMCV, EBP);

return (!RulesExt::Global()->AISetBaseCenter && pMCV->Owner->NumConYards > 1) ? SkipGameCode : 0;
}

DEFINE_HOOK(0x4FD538, HouseClass_AIHouseUpdate_CheckAIBaseCenter, 0x7)
{
if (RulesExt::Global()->AIBiasSpawnCell && !SessionClass::IsCampaign())
{
GET(HouseClass*, pAI, EBX);

if (const auto count = pAI->ConYards.Count)
{
const auto wayPoint = pAI->GetSpawnPosition();

if (wayPoint != -1)
{
const auto center = ScenarioClass::Instance->GetWaypointCoords(wayPoint);
auto newCenter = center;
double distanceSquared = 131072.0;

for (int i = 0; i < count; ++i)
{
if (const auto pBuilding = pAI->ConYards.GetItem(i))
{
if (pBuilding->IsAlive && pBuilding->Health && !pBuilding->InLimbo)
{
const auto newDistanceSquared = pBuilding->GetMapCoords().DistanceFromSquared(center);

if (newDistanceSquared < distanceSquared)
{
distanceSquared = newDistanceSquared;
newCenter = pBuilding->GetMapCoords();
}
}
}
}

if (newCenter != center)
{
pAI->BaseSpawnCell = newCenter;
pAI->Base.Center = newCenter;
}
}
}
}

return 0;
}

DEFINE_HOOK(0x4451F8, BuildingClass_KickOutUnit_CleanUpAIBuildingSpace, 0x6)
{
enum { BuildFailed = 0x445696 };

GET(BaseNodeClass* const, pBaseNode, EBX);
GET(BuildingClass* const, pBuilding, EDI);

const auto pBuildingType = pBuilding->Type;

if (RulesExt::Global()->AIForbidConYard && pBuildingType->ConstructionYard)
{
if (pBaseNode)
{
pBaseNode->Placed = true;
pBaseNode->Attempts = 0;
}

return BuildFailed;
}

return 0;
}

DEFINE_HOOK(0x42EB8E, BaseClass_GetBaseNodeIndex_CheckValidBaseNode, 0x6)
{
enum { Valid = 0x42EBC3, Invalid = 0x42EBAE };

GET(BaseClass* const, pBase, ESI);
GET(BaseNodeClass* const, pBaseNode, EAX);

if (pBaseNode->Placed)
{
const auto index = pBaseNode->BuildingTypeIndex;

if (index >= 0 && index < BuildingTypeClass::Array->Count && BuildingTypeClass::Array->Items[index]->ConstructionYard && RulesExt::Global()->AIForbidConYard)
return Invalid;
}

return reinterpret_cast<bool(__thiscall*)(HouseClass*, BaseNodeClass*)>(0x50CAD0)(pBase->Owner, pBaseNode) ? Valid : Invalid;
}

#pragma endregion

DEFINE_HOOK(0x65EB8D, HouseClass_SendSpyPlanes_PlaceAircraft, 0x6)
{
enum { SkipGameCode = 0x65EBE5, SkipGameCodeNoSuccess = 0x65EC12 };
Expand Down
9 changes: 9 additions & 0 deletions src/Ext/Rules/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI)

this->UseFixedVoxelLighting.Read(exINI, GameStrings::AudioVisual, "UseFixedVoxelLighting");

this->AIAutoDeployMCV.Read(exINI, GameStrings::AI, "AIAutoDeployMCV");
this->AISetBaseCenter.Read(exINI, GameStrings::AI, "AISetBaseCenter");
this->AIBiasSpawnCell.Read(exINI, GameStrings::AI, "AIBiasSpawnCell");
this->AIForbidConYard.Read(exINI, GameStrings::AI, "AIForbidConYard");

this->GatherWhenMCVDeploy.Read(exINI, GameStrings::General, "GatherWhenMCVDeploy");
this->AIFireSale.Read(exINI, GameStrings::General, "AIFireSale");
this->AIFireSaleDelay.Read(exINI, GameStrings::General, "AIFireSaleDelay");
Expand Down Expand Up @@ -384,6 +389,10 @@ void RulesExt::ExtData::Serialize(T& Stm)
.Process(this->VoxelLightSource)
// .Process(this->VoxelShadowLightSource)
.Process(this->UseFixedVoxelLighting)
.Process(this->AIAutoDeployMCV)
.Process(this->AISetBaseCenter)
.Process(this->AIBiasSpawnCell)
.Process(this->AIForbidConYard)
.Process(this->GatherWhenMCVDeploy)
.Process(this->AIFireSale)
.Process(this->AIFireSaleDelay)
Expand Down
9 changes: 9 additions & 0 deletions src/Ext/Rules/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ class RulesExt
// Nullable<Vector3D<float>> VoxelShadowLightSource;
Valueable<bool> UseFixedVoxelLighting;

Valueable<bool> AIAutoDeployMCV;
Valueable<bool> AISetBaseCenter;
Valueable<bool> AIBiasSpawnCell;
Valueable<bool> AIForbidConYard;

Valueable<bool> GatherWhenMCVDeploy;
Valueable<bool> AIFireSale;
Valueable<int> AIFireSaleDelay;
Expand Down Expand Up @@ -280,6 +285,10 @@ class RulesExt
, VoxelLightSource { }
// , VoxelShadowLightSource { }
, UseFixedVoxelLighting { false }
, AIAutoDeployMCV { true }
, AISetBaseCenter { true }
, AIBiasSpawnCell { false }
, AIForbidConYard { false }
, GatherWhenMCVDeploy { true }
, AIFireSale { true }
, AIFireSaleDelay { 0 }
Expand Down
Loading