diff --git a/CREDITS.md b/CREDITS.md index ff4254c04c..b86d35bf9b 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -498,6 +498,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 diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index c1547abe9c..33bd308f94 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -2298,6 +2298,20 @@ 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`. + +In `rulesmd.ini`: +```ini +[SOMEWARHEAD] ; WarheadType +ChangeOwner=false ; boolean +ChangeOwner.SetAsMindControl=false ; boolean +ChangeOwner.MindControlAnim= ; Animation +``` + ### Convert TechnoType on impact ![image](_static/images/convertwh.gif) diff --git a/docs/Whats-New.md b/docs/Whats-New.md index baf3c1e532..89b2b2fa71 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -469,6 +469,7 @@ New: - [CellSpread damage check if victim is in air or on floor](New-or-Enhanced-Logics.md#cellspread-enhancement) (by TaranDahl) - OpenTopped range bonus and damage multiplier customization for passengers (by Ollerus) - AutoDeath upon ownership change (by Ollerus) +- 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) diff --git a/src/Ext/WarheadType/Body.cpp b/src/Ext/WarheadType/Body.cpp index f3d54ee630..b9426577c7 100644 --- a/src/Ext/WarheadType/Body.cpp +++ b/src/Ext/WarheadType/Body.cpp @@ -308,6 +308,10 @@ 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"); + // Convert.From & Convert.To TypeConvertGroup::Parse(this->Convert_Pairs, exINI, pSection, AffectedHouse::All); @@ -359,6 +363,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 @@ -599,6 +604,10 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm) .Process(this->AnimZAdjust) + .Process(this->ChangeOwner) + .Process(this->ChangeOwner_SetAsMindControl) + .Process(this->ChangeOwner_MindControlAnim) + // Ares tags .Process(this->AffectsEnemies) .Process(this->AffectsOwner) diff --git a/src/Ext/WarheadType/Body.h b/src/Ext/WarheadType/Body.h index fdef381aa8..7602822032 100644 --- a/src/Ext/WarheadType/Body.h +++ b/src/Ext/WarheadType/Body.h @@ -212,6 +212,10 @@ class WarheadTypeExt Nullable AnimZAdjust; + Valueable ChangeOwner; + Valueable ChangeOwner_SetAsMindControl; + Nullable ChangeOwner_MindControlAnim; + // Ares tags // http://ares-developers.github.io/Ares-docs/new/warheads/general.html Valueable AffectsEnemies; @@ -446,11 +450,17 @@ class WarheadTypeExt , PlayAnimAboveSurface { false } , AnimZAdjust {} + + , ChangeOwner { false } + , ChangeOwner_SetAsMindControl { false } + , ChangeOwner_MindControlAnim {} { } 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; diff --git a/src/Ext/WarheadType/Detonate.cpp b/src/Ext/WarheadType/Detonate.cpp index d64548ebd1..1427873c5c 100644 --- a/src/Ext/WarheadType/Detonate.cpp +++ b/src/Ext/WarheadType/Detonate.cpp @@ -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); @@ -469,6 +472,42 @@ HouseClass* WarheadTypeExt::ExtData::ApplyRemoveMindControl(HouseClass* pHouse, return pHouse; } +void WarheadTypeExt::ExtData::ApplyOwnerChange(HouseClass* pHouse, TechnoClass* pTarget) +{ + const bool isMindControl = this->ChangeOwner_SetAsMindControl; + const bool isImmune = (isMindControl && pTarget->GetTechnoType()->ImmuneToPsionics) || pTarget->IsMindControlled(); + + if (!isImmune) + { + pTarget->SetOwningHouse(pHouse, 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(pTarget)->Type->Height * Unsorted::LevelHeight; + else + location.Z += pTarget->GetTechnoType()->MindControlRingOffset; + + if (const auto pOwnerAnim = GameCreate(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;