Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
55664e1
initial commit
Fryone Jul 30, 2023
6b6f924
Immunities (wip)
Fryone Aug 1, 2023
f00d0e6
Docs and fixes
Fryone Aug 1, 2023
3de494f
Merge branch 'develop' into fryone/owner_changer
Fryone Aug 2, 2023
0078e96
Merge branch 'develop' into fryone/owner_changer
Fryone Aug 5, 2023
9215933
Merge branch 'develop' into fryone/owner_changer
Fryone Aug 7, 2023
ddc364c
Merge branch 'develop' into fryone/owner_changer
Fryone Jan 7, 2024
aef9ebb
Merge branch 'develop' into fryone/owner_changer
Fryone Jan 21, 2024
053a3d0
Merge branch 'develop' into fryone/owner_changer
Fryone Feb 13, 2024
a01fd7d
Merge remote-tracking branch 'upstream/develop' into fryone/owner_cha…
Fryone Feb 23, 2024
723551e
Update YRpp
Fryone Feb 23, 2024
1770c6b
Update Detonate.cpp
Fryone Feb 23, 2024
30c3ee4
fix permamc anim not following target
Fryone Feb 24, 2024
0b51abf
updated logic
Fryone Feb 24, 2024
84a4a6c
Merge remote-tracking branch 'upstream/develop' into fryone/owner_cha…
Fryone Feb 27, 2024
75b58dc
Merge branch 'develop' into fryone/owner_changer
Coronia Dec 16, 2025
23e7605
fix mind control anim
Coronia Dec 16, 2025
4eeeff7
remove ChangeOwner.AffectElites
Coronia Dec 18, 2025
f05ebbf
Merge remote-tracking branch 'origin/develop' into fryone/owner_changer
Coronia Dec 18, 2025
e2d0c38
remove ChangeOwnerImmunities
Coronia Dec 18, 2025
66ba905
Merge branch 'fryone/owner_changer' of https://github.com/Fryone/Phob…
Fryone Dec 18, 2025
4541bac
Added timed control
Fryone Dec 20, 2025
e4593a7
update ChangeOwner.Duration
Coronia Dec 22, 2025
63125f9
Merge remote-tracking branch 'upstream/develop' into fryone/owner_cha…
Coronia Dec 22, 2025
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 @@ -499,6 +499,7 @@ This page lists all the individual contributions to the project by their author.
- Damaged unit image changes
- `VoiceDeploy` through hot-key/command bar fix
- Damaged aircraft image changes
- Change target Owner on warhead impact
- **ZivDero**:
- Re-enable the Veinhole Monster and Weeds from TS
- Recreate the weed-charging of SWs like the TS Chemical Missile
Expand Down
19 changes: 19 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2316,6 +2316,25 @@ ImmuneToCrit=false ; boolean
If you set `Crit.Warhead` to the same Warhead it is defined on, or create a chain of Warheads with it that loops back to the first one there is a possibility for the game to get stuck in a loop and freeze or crash afterwards.
```

### Change target Owner on impact

- Warheads can now change targets owner to warhead's owner.
- `ChangeOwner.SetAsMindControl` makes the effect work like permanent mind control, which respects `ImmuneToPsionics`.
- `ChangeOwner.MindControlAnim` determines the mind control anim of this effect, which respects `MindControlRingOffset`.
- If `ChangeOwner.Duration` is set, the target will switch back to its original owner after these many frames has passed. Can't be used on effect with `ChangeOwner.SetAsMindControl=true`.
- If another house changing effect happens within the duration (f. ex. capture, mind control, other `ChangeOwner=true` warheads), this switchback of owner won't happen.
- `ChangeOwner.Duration.PreventChange` determines whether another change owner warhead effect can be applied to the target within the duration of current effect.

In `rulesmd.ini`:
```ini
[SOMEWARHEAD] ; WarheadType
ChangeOwner=false ; boolean
ChangeOwner.SetAsMindControl=false ; boolean
ChangeOwner.MindControlAnim= ; Animation
ChangeOwner.Duration= ; interger
ChangeOwner.Duration.PreventChange=false ; boolean
```

### Convert TechnoType on impact

![image](_static/images/convertwh.gif)
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:
- AutoDeath upon ownership change (by Ollerus)
- [Script Action 14004 for forcing all new actions to target only the main owner's enemy](AI-Scripting-and-Mapping.md#force-global-onlytargethouseenemy-value-in-teams-for-new-attack-move-actions-introduced-by-phobos) (by FS-21)
- [Allow merging AOE damage to buildings into one](New-or-Enhanced-Logics.md#allow-merging-aoe-damage-to-buildings-into-one) (by CrimRecya)
- Change target Owner on warhead impact (by Fryone)

Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
Expand Down
2 changes: 2 additions & 0 deletions src/Ext/House/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ DEFINE_HOOK(0x7015C9, TechnoClass_Captured_UpdateTracking, 0x6)
pTrail->CurrentColor = pNewOwner->LaserColor;
}

pExt->OwnerTimer.Stop();

return 0;
}

Expand Down
10 changes: 10 additions & 0 deletions src/Ext/Techno/Body.Update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ void TechnoExt::ExtData::OnEarlyUpdate()
this->ApplyMindControlRangeLimit();
this->UpdateRecountBurst();
this->UpdateRearmInEMPState();
this->UpdateOwnerTimer();

if (this->AttackMoveFollowerTempCount)
this->AttackMoveFollowerTempCount--;
Expand Down Expand Up @@ -2136,3 +2137,12 @@ void TechnoExt::ExtData::UpdateTintValues()
calculateTint(Drawing::RGB_To_Int(pShieldType->Tint_Color), static_cast<int>(pShieldType->Tint_Intensity * 1000), pShieldType->Tint_VisibleToHouses);
}
}

void TechnoExt::ExtData::UpdateOwnerTimer()
{
if (this->OwnerTimer.Completed())
{
this->OwnerObject()->SetOwningHouse(this->OwnerOriginalOwner);
this->ImmuneToChangeOwner = false;
}
}
5 changes: 4 additions & 1 deletion src/Ext/Techno/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ bool TechnoExt::SimpleDeployerAllowedToDeploy(UnitClass* pThis, bool defaultValu
const bool isLander = pType->DeployToLand && (isJumpjet || isHover);
disallowedLandTypes = isLander ? (LandTypeFlags)(LandTypeFlags::Water | LandTypeFlags::Beach) : LandTypeFlags::None;
}

if (IsLandTypeInFlags(disallowedLandTypes, pThis->GetCell()->LandType))
return false;

Expand Down Expand Up @@ -947,6 +947,9 @@ void TechnoExt::ExtData::Serialize(T& Stm)
.Process(this->SpecialTracked)
.Process(this->FallingDownTracked)
.Process(this->JumpjetStraightAscend)
.Process(this->OwnerTimer)
.Process(this->OwnerOriginalOwner)
.Process(this->ImmuneToChangeOwner)
;
}

Expand Down
7 changes: 7 additions & 0 deletions src/Ext/Techno/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ class TechnoExt
bool FallingDownTracked;

bool JumpjetStraightAscend; // Is set to true jumpjet units will ascend straight and do not adjust rotation or position during it.
CDTimerClass OwnerTimer;
HouseClass* OwnerOriginalOwner;
bool ImmuneToChangeOwner;

ExtData(TechnoClass* OwnerObject) : Extension<TechnoClass>(OwnerObject)
, TypeExtData { nullptr }
Expand Down Expand Up @@ -169,6 +172,9 @@ class TechnoExt
, SpecialTracked { false }
, FallingDownTracked { false }
, JumpjetStraightAscend { false }
, OwnerTimer {}
, OwnerOriginalOwner {}
, ImmuneToChangeOwner { false }
{ }

void OnEarlyUpdate();
Expand Down Expand Up @@ -207,6 +213,7 @@ class TechnoExt
int ApplyForceWeaponInRange(AbstractClass* pTarget);
void ResetDelayedFireTimer();
void UpdateTintValues();
void UpdateOwnerTimer();

void AmmoAutoConvertActions();

Expand Down
13 changes: 13 additions & 0 deletions src/Ext/WarheadType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,12 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)

this->AnimZAdjust.Read(exINI, pSection, "AnimZAdjust");

this->ChangeOwner.Read(exINI, pSection, "ChangeOwner");
this->ChangeOwner_SetAsMindControl.Read(exINI, pSection, "ChangeOwner.SetAsMindControl");
this->ChangeOwner_MindControlAnim.Read(exINI, pSection, "ChangeOwner.MindControlAnim");
this->ChangeOwner_Duration.Read(exINI, pSection, "ChangeOwner.Duration");
this->ChangeOwner_Duration_PreventChange.Read(exINI, pSection, "ChangeOwner.Duration.PreventChange");

// Convert.From & Convert.To
TypeConvertGroup::Parse(this->Convert_Pairs, exINI, pSection, AffectedHouse::All);

Expand Down Expand Up @@ -361,6 +367,7 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
|| this->Convert_Pairs.size() > 0
|| this->InflictLocomotor
|| this->RemoveInflictedLocomotor
|| this->ChangeOwner
|| this->AttachEffects.AttachTypes.size() > 0
|| this->AttachEffects.RemoveTypes.size() > 0
|| this->AttachEffects.RemoveGroups.size() > 0
Expand Down Expand Up @@ -603,6 +610,12 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm)

.Process(this->AnimZAdjust)

.Process(this->ChangeOwner)
.Process(this->ChangeOwner_SetAsMindControl)
.Process(this->ChangeOwner_MindControlAnim)
.Process(this->ChangeOwner_Duration)
.Process(this->ChangeOwner_Duration_PreventChange)

// Ares tags
.Process(this->AffectsEnemies)
.Process(this->AffectsOwner)
Expand Down
14 changes: 14 additions & 0 deletions src/Ext/WarheadType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,12 @@ class WarheadTypeExt

Nullable<int> AnimZAdjust;

Valueable<bool> ChangeOwner;
Valueable<bool> ChangeOwner_SetAsMindControl;
Nullable<AnimTypeClass*> ChangeOwner_MindControlAnim;
Nullable<int> ChangeOwner_Duration;
Valueable<bool> ChangeOwner_Duration_PreventChange;

// Ares tags
// http://ares-developers.github.io/Ares-docs/new/warheads/general.html
Valueable<bool> AffectsEnemies;
Expand Down Expand Up @@ -450,11 +456,19 @@ class WarheadTypeExt
, PlayAnimAboveSurface { false }

, AnimZAdjust {}

, ChangeOwner { false }
, ChangeOwner_SetAsMindControl { false }
, ChangeOwner_MindControlAnim {}
, ChangeOwner_Duration {}
, ChangeOwner_Duration_PreventChange { false }
{ }

void ApplyConvert(HouseClass* pHouse, TechnoClass* pTarget);
void ApplyLocomotorInfliction(TechnoClass* pTarget);
void ApplyLocomotorInflictionReset(TechnoClass* pTarget);
void ApplyOwnerChange(HouseClass* pHouse, TechnoClass* pTarget);

public:
bool CanTargetHouse(HouseClass* pHouse, TechnoClass* pTechno) const;
bool CanAffectTarget(TechnoClass* pTarget) const;
Expand Down
52 changes: 51 additions & 1 deletion src/Ext/WarheadType/Detonate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,13 @@ void WarheadTypeExt::ExtData::DetonateOnOneUnit(HouseClass* pHouse, TechnoClass*
if (!this->CanTargetHouse(pHouse, pTarget) || !this->CanAffectTarget(pTarget))
return;

// Put this at first since it can change the target's house
// Put these at first since they can change the target's house
if (this->RemoveMindControl)
pHouse = this->ApplyRemoveMindControl(pHouse, pTarget);

if (this->ChangeOwner)
this->ApplyOwnerChange(pHouse, pTarget);

// These can change the target's techno types
if (this->Convert_Pairs.size() > 0)
this->ApplyConvert(pHouse, pTarget);
Expand Down Expand Up @@ -469,6 +472,53 @@ HouseClass* WarheadTypeExt::ExtData::ApplyRemoveMindControl(HouseClass* pHouse,
return pHouse;
}

void WarheadTypeExt::ExtData::ApplyOwnerChange(HouseClass* pHouse, TechnoClass* pTarget)
{
auto const pTargetExt = TechnoExt::ExtMap.Find(pTarget);
const bool isMindControl = this->ChangeOwner_SetAsMindControl;
const bool isImmune = pTargetExt->ImmuneToChangeOwner || (isMindControl && pTarget->GetTechnoType()->ImmuneToPsionics) || pTarget->IsMindControlled();

if (!isImmune)
{
auto const pOwner = pTarget->Owner;
pTarget->SetOwningHouse(pHouse, true);
pTargetExt->OwnerOriginalOwner = pOwner;

if (this->ChangeOwner_Duration && !isMindControl)
{
pTargetExt->OwnerTimer.Start(this->ChangeOwner_Duration);

if (this->ChangeOwner_Duration_PreventChange)
pTargetExt->ImmuneToChangeOwner = true;
}

if (isMindControl)
{
pTarget->MindControlledByAUnit = true;

if (const auto pAnimType = this->ChangeOwner_MindControlAnim.Get())
{
CoordStruct location = pTarget->Location;
const bool isBld = pTarget->What_Am_I() == AbstractType::Building;

if (isBld)
location.Z += static_cast<BuildingClass*>(pTarget)->Type->Height * Unsorted::LevelHeight;
else
location.Z += pTarget->GetTechnoType()->MindControlRingOffset;

if (const auto pOwnerAnim = GameCreate<AnimClass>(pAnimType, location))
{
pTarget->MindControlRingAnim = pOwnerAnim;
pOwnerAnim->SetOwnerObject(pTarget);

if (isBld)
pOwnerAnim->ZAdjust = -1024;
}
}
}
}
}

void WarheadTypeExt::ExtData::ApplyCrit(HouseClass* pHouse, TechnoClass* pTarget, TechnoClass* pOwner)
{
const double dice = this->Crit_ApplyChancePerTarget ? ScenarioClass::Instance->Random.RandomDouble() : this->Crit_RandomBuffer;
Expand Down