Skip to content
3 changes: 3 additions & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -642,3 +642,6 @@ This page lists all the individual contributions to the project by their author.
- **Damfoos** - extensive and thorough testing
- **Dmitry Volkov** - extensive and thorough testing
- **Rise of the East community** - extensive playtesting of in-dev features
- **ahasasjeb**
- fix: Pause AI building production under EMP (respect ImmuneToEMP)
- EMP effect on spawner aircraft generation with toggle control
12 changes: 12 additions & 0 deletions docs/Fixed-or-Improved-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ This page describes all ingame logics that are fixed or improved in Phobos witho
- Fixed building and defense tab hotkeys not enabling the placement mode after *Cannot build here.* triggered and the placement mode cancelled.
- Fixed buildings with `UndeployInto` playing `EVA_NewRallypointEstablished` on undeploying.
- Fixed buildings with `Naval=yes` ignoring `WaterBound=no` to be forced to place onto water.
- Fixed AI buildings with `ImmuneToEMP=no` continuing production (infantry, vehicles, buildings) while under EMP; production is now paused for the EMP duration. Buildings with `ImmuneToEMP=yes` are unaffected and continue producing as before.
- EMP effect on spawner aircraft generation can now be controlled via `EMP.PausesSpawning`. When enabled (default), buildings with `ImmuneToEMP=no` no longer continue spawner aircraft generation while under EMP; spawning is paused for the EMP duration. Buildings with `ImmuneToEMP=yes` are unaffected and continue spawning as before.
- Fixed AI Aircraft docks bug when Ares tag `[GlobalControls] -> AllowParallelAIQueues=no` is set.
- Fixed laser drawing code to allow for thicker lasers in house color draw mode.
- Fixed `DeathWeapon` not detonating properly.
Expand Down Expand Up @@ -510,6 +512,16 @@ AINodeWallsOnly=false ; boolean
AICleanWallNode=false ; boolean
```

### EMP effect on spawner aircraft generation

- By default buildings with spawner functionality (aircraft carriers) and `ImmuneToEMP=no` pause aircraft spawning while under EMP. This behavior can be disabled to restore vanilla behavior where EMP does not affect spawner aircraft generation.

In `rulesmd.ini`:
```ini
[General]
EMP.PausesSpawning=yes ; boolean
```

### Aircraft docking direction

- It is now possible to customize the landing direction for docking aircraft via `AircraftDockingDir(N)` (`N` optionally replaced by 0-based index for each `DockingOffset` separately, `AircraftDockingDir` and `AircraftDockingDir0` are synonymous and will be used if direction is not set for a specific offset) on the dock building. This overrides the aircraft's own [landing direction](#landing-direction) setting and defaults to `[AudioVisual] -> PoseDir`.
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ Phobos fixes:
- Fixed an issue that `FireAngle` was not taken into account when drawing barrel in `TurretShadow` (by CrimRecya)

Fixes / interactions with other extensions:
- Pause AI building production and spawner aircraft under EMP (by ahasasjeb)
- Allowed `AuxBuilding` and Ares' `SW.Aux/NegBuildings` to count building upgrades (by Ollerus)
- Taking over Ares' AlphaImage respawn logic to reduce lags from it (by NetsuNegi)
```
Expand Down
2 changes: 2 additions & 0 deletions src/Ext/Rules/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI)
this->DistributeTargetingFrame_AIOnly.Read(exINI, GameStrings::General, "DistributeTargetingFrame.AIOnly");

this->InfantryAutoDeploy.Read(exINI, GameStrings::General, "InfantryAutoDeploy");
this->EMP_PausesSpawning.Read(exINI, GameStrings::General, "EMP.PausesSpawning");

// Section AITargetTypes
int itemsCount = pINI->GetKeyCount("AITargetTypes");
Expand Down Expand Up @@ -572,6 +573,7 @@ void RulesExt::ExtData::Serialize(T& Stm)
.Process(this->AttackMove_StopWhenTargetAcquired)
.Process(this->Parasite_GrappleAnim)
.Process(this->InfantryAutoDeploy)
.Process(this->EMP_PausesSpawning)
;
}

Expand Down
2 changes: 2 additions & 0 deletions src/Ext/Rules/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ class RulesExt
int TintColorBerserk;

Valueable<bool> InfantryAutoDeploy;
Valueable<bool> EMP_PausesSpawning;

ExtData(RulesClass* OwnerObject) : Extension<RulesClass>(OwnerObject)
, Storage_TiberiumIndex { -1 }
Expand Down Expand Up @@ -468,6 +469,7 @@ class RulesExt

, Parasite_GrappleAnim {}
, InfantryAutoDeploy { false }
, EMP_PausesSpawning { true }
{ }

virtual ~ExtData() = default;
Expand Down
20 changes: 19 additions & 1 deletion src/Ext/Techno/Body.Update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <Kamikaze.h>
#include <JumpjetLocomotionClass.h>
#include <FlyLocomotionClass.h>
#include <BuildingClass.h>
#include <FactoryClass.h>

#include <Ext/Anim/Body.h>
#include <Ext/Bullet/Body.h>
Expand Down Expand Up @@ -1627,8 +1629,9 @@ void TechnoExt::ExtData::UpdateTemporal()
void TechnoExt::ExtData::UpdateRearmInEMPState()
{
const auto pThis = this->OwnerObject();
const bool underEMP = pThis->IsUnderEMP();

if (!pThis->IsUnderEMP() && !pThis->Deactivated)
if (!underEMP && !pThis->Deactivated)
return;

const auto pTypeExt = this->TypeExtData;
Expand All @@ -1638,6 +1641,21 @@ void TechnoExt::ExtData::UpdateRearmInEMPState()

if (pThis->ReloadTimer.InProgress() && pTypeExt->NoReload_UnderEMP.Get(RulesExt::Global()->NoReload_UnderEMP))
pThis->ReloadTimer.StartTime++;

// Freeze AI-controlled factory production while building is EMPed
if (auto const pBuilding = abstract_cast<BuildingClass*, true>(pThis))
{
if (pBuilding->Owner && !pBuilding->Owner->IsControlledByHuman())
{
if (auto const pFactory = pBuilding->Factory)
{
if (pFactory->Object && pFactory->Production.Rate > 0)
{
pFactory->Production.Timer.StartTime++;
}
}
}
}
}

void TechnoExt::ExtData::UpdateRearmInTemporal()
Expand Down
11 changes: 10 additions & 1 deletion src/Ext/Techno/Hooks.Misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

#include <SpawnManagerClass.h>
#include <TunnelLocomotionClass.h>
#include <BuildingClass.h>

#include <Ext/Anim/Body.h>
#include <Ext/TechnoType/Body.h>
#include <Ext/Scenario/Body.h>
#include <Ext/WeaponType/Body.h>
#include <Ext/Bullet/Body.h>
#include <Ext/Rules/Body.h>

#pragma region SlaveManagerClass

Expand Down Expand Up @@ -155,6 +161,9 @@ DEFINE_HOOK(0x6B78D3, SpawnManagerClass_Update_Spawns, 0x6)
auto const pOwner = pThis->Owner;
auto const pTypeExt = TechnoExt::ExtMap.Find(pOwner)->TypeExtData;

if (const auto pOwnerType = pOwner->GetTechnoType(); pOwnerType && pOwnerType->SpawnRegenRate <= 0)
return 0;

if (pTypeExt->Spawns_Queue.empty())
return 0;

Expand All @@ -170,7 +179,7 @@ DEFINE_HOOK(0x6B78D3, SpawnManagerClass_Update_Spawns, 0x6)
}
}

if (vec.empty() || !vec[0])
if (vec.empty())
return 0;

R->EAX(vec[0]->CreateObject(pOwner->Owner));
Expand Down
2 changes: 1 addition & 1 deletion src/Ext/Techno/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ DEFINE_HOOK(0x6F9FA9, TechnoClass_AI_PromoteAnim, 0x6)

if (pThis->Veterancy.GetRemainingLevel() == Rank::Veteran && pVeteranAnim)
promAnim = GameCreate<AnimClass>(pVeteranAnim, pThis->GetCenterCoords());
else if (pEliteAnim)
else if (pThis->Veterancy.GetRemainingLevel() == Rank::Elite && pEliteAnim)
promAnim = GameCreate<AnimClass>(pEliteAnim, pThis->GetCenterCoords());

if (promAnim)
Expand Down