From 998505f65a1b6bffe6dacc8f21baeb3cedb9a282 Mon Sep 17 00:00:00 2001 From: Starkku Date: Sun, 25 Aug 2024 14:06:02 +0300 Subject: [PATCH] Allow customizing AI superweapon logic delay --- CREDITS.md | 1 + docs/New-or-Enhanced-Logics.md | 10 ++++++++++ docs/Whats-New.md | 1 + src/Ext/House/Body.cpp | 1 + src/Ext/House/Body.h | 3 +++ src/Ext/House/Hooks.cpp | 35 ++++++++++++++++++++++++++++++++++ src/Ext/Rules/Body.cpp | 2 ++ src/Ext/Rules/Body.h | 2 ++ 8 files changed, 55 insertions(+) diff --git a/CREDITS.md b/CREDITS.md index e1f8766b9b..667fff4b2b 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -235,6 +235,7 @@ This page lists all the individual contributions to the project by their author. - Option to enable parsing 8-bit RGB values from `[ColorAdd]` instead of RGB565 - Customizing height at which subterranean units travel - `MovementZone=Subterannean` harvester fix + - AI superweapon delay timer customization - **Morton (MortonPL)**: - `XDrawOffset` for animations - Shield passthrough & absorption diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 6e72d7dab8..d195be51c6 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -745,6 +745,16 @@ This currently has same limitations as `AirburstWeapon` in that it does not prop ## Super Weapons +### AI Superweapon delay timer + +- By default AI houses only process superweapon logic e.g checks if it can fire any superweapons firing them at randomized intervals of 106 to 112 game frames. This behaviour can now be customized by setting explicit delay, or disabling it entirely. Values of 0 and below disable the delay and cause AI houses to check superweapons on every game frame. + +In `rulesmd.ini`: +```ini +[General] +AISuperWeaponDelay= ; integer, game frames +``` + ### Convert TechnoType - Warheads can now change TechnoTypes of affected units to other Types in the same category (infantry to infantry, vehicles to vehicles, aircraft to aircraft). diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 07eb0ebda8..49e9405157 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -440,6 +440,7 @@ New: - Option for Warhead to remove all shield types at once (by Starkku) - Allow customizing voxel light source position (by Kerbiter, Morton, based on knowledge of thomassnedon) - Option to fix voxel light source being offset and incorrectly tilting on slopes (by Kerbiter) +- AI superweapon delay timer customization (by Starkku) Vanilla fixes: - Allow AI to repair structures built from base nodes/trigger action 125/SW delivery in single player missions (by Trsdy) diff --git a/src/Ext/House/Body.cpp b/src/Ext/House/Body.cpp index 749183d883..59b82738c7 100644 --- a/src/Ext/House/Body.cpp +++ b/src/Ext/House/Body.cpp @@ -529,6 +529,7 @@ void HouseExt::ExtData::Serialize(T& Stm) .Process(this->Factory_VehicleType) .Process(this->Factory_NavyType) .Process(this->Factory_AircraftType) + .Process(this->AISuperWeaponDelayTimer) .Process(this->RepairBaseNodes) .Process(this->LastBuiltNavalVehicleType) .Process(this->ProducingNavalUnitTypeIndex) diff --git a/src/Ext/House/Body.h b/src/Ext/House/Body.h index 9f703532ea..68ae82ee02 100644 --- a/src/Ext/House/Body.h +++ b/src/Ext/House/Body.h @@ -35,6 +35,8 @@ class HouseExt BuildingClass* Factory_NavyType; BuildingClass* Factory_AircraftType; + CDTimerClass AISuperWeaponDelayTimer; + //Read from INI bool RepairBaseNodes[3]; @@ -53,6 +55,7 @@ class HouseExt , Factory_VehicleType { nullptr } , Factory_NavyType { nullptr } , Factory_AircraftType { nullptr } + , AISuperWeaponDelayTimer {} , RepairBaseNodes { false,false,false } , LastBuiltNavalVehicleType { -1 } , ProducingNavalUnitTypeIndex { -1 } diff --git a/src/Ext/House/Hooks.cpp b/src/Ext/House/Hooks.cpp index 5cff2ce743..de22efe4d4 100644 --- a/src/Ext/House/Hooks.cpp +++ b/src/Ext/House/Hooks.cpp @@ -271,3 +271,38 @@ DEFINE_HOOK(0x50B669, HouseClass_ShouldDisableCameo, 0x5) return 0; } + +DEFINE_HOOK(0x4F9038, HouseClass_ExpertAI_Superweapons, 0x5) +{ + enum { SkipSWProcess = 0x4FD7A0 }; + + if (RulesExt::Global()->AISuperWeaponDelay.isset()) + return SkipSWProcess; + + return 0; +} + +DEFINE_HOOK(0x4F9038, HouseClass_AI_Superweapons, 0x5) +{ + GET(HouseClass*, pThis, ESI); + + if (!RulesExt::Global()->AISuperWeaponDelay.isset() || pThis->IsControlledByHuman() || pThis->Type->MultiplayPassive) + return 0; + + int delay = RulesExt::Global()->AISuperWeaponDelay.Get(); + + if (delay > 0) + { + auto const pExt = HouseExt::ExtMap.Find(pThis); + + if (pExt->AISuperWeaponDelayTimer.HasTimeLeft()) + return 0; + + pExt->AISuperWeaponDelayTimer.Start(delay); + } + + if (!SessionClass::IsCampaign() || pThis->IQLevel2 >= RulesClass::Instance->SuperWeapons) + pThis->AI_TryFireSW(); + + return 0; +} diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index 7593ae12c0..4b58a262ae 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -77,6 +77,7 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) this->AIChronoSphereSW.Read(exINI, GameStrings::General, "AIChronoSphereSW"); this->AIChronoWarpSW.Read(exINI, GameStrings::General, "AIChronoWarpSW"); this->SubterraneanHeight.Read(exINI, GameStrings::General, "SubterraneanHeight"); + this->AISuperWeaponDelay.Read(exINI, GameStrings::General, "AISuperWeaponDelay"); this->UseGlobalRadApplicationDelay.Read(exINI, GameStrings::Radiation, "UseGlobalRadApplicationDelay"); this->RadApplicationDelay_Building.Read(exINI, GameStrings::Radiation, "RadApplicationDelay.Building"); this->RadBuildingDamageMaxCount.Read(exINI, GameStrings::Radiation, "RadBuildingDamageMaxCount"); @@ -264,6 +265,7 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->AIChronoSphereSW) .Process(this->AIChronoWarpSW) .Process(this->SubterraneanHeight) + .Process(this->AISuperWeaponDelay) .Process(this->UseGlobalRadApplicationDelay) .Process(this->RadApplicationDelay_Building) .Process(this->RadBuildingDamageMaxCount) diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h index 9a254fb41e..aad54ade8c 100644 --- a/src/Ext/Rules/Body.h +++ b/src/Ext/Rules/Body.h @@ -43,6 +43,7 @@ class RulesExt ValueableIdx AIChronoSphereSW; ValueableIdx AIChronoWarpSW; Valueable SubterraneanHeight; + Nullable AISuperWeaponDelay; Valueable UseGlobalRadApplicationDelay; Valueable RadApplicationDelay_Building; Valueable RadBuildingDamageMaxCount; @@ -156,6 +157,7 @@ class RulesExt , AIChronoSphereSW {} , AIChronoWarpSW {} , SubterraneanHeight { -256 } + , AISuperWeaponDelay {} , UseGlobalRadApplicationDelay { true } , RadApplicationDelay_Building { 0 } , RadBuildingDamageMaxCount { -1 }