Skip to content
Draft
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 @@ -466,6 +466,7 @@ This page lists all the individual contributions to the project by their author.
- Customize type selection for IFV
- Fix the issue that units will goto farest location if target is closer than `MinimumRange`
- Fix a bug introduced by Ares where building types that have `UndeploysInto` cannot display `AltCameo` or `AltCameoPCX` even when you infiltrate enemy buildings with `Factory=UnitType`
- Allow customize either `ExpireWeapon` can detonate or not if invoker of AE is dead
- **Apollo** - Translucent SHP drawing patches
- **ststl**:
- Customizable `ShowTimer` priority of superweapons
Expand Down
2 changes: 2 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ This page describes all the engine features that are either new and introduced b
- `ExpireWeapon.TriggerOn` determines the exact conditions upon which the weapon is fired, defaults to `expire` which means only if the effect naturally expires.
- `ExpireWeapon.CumulativeOnlyOnce`, if set to true, makes it so that `Cumulative=true` attached effects only detonate the weapon once period, instead of once per active instance. On `remove` and `expire` condition this means it will only detonate after last instance has expired or been removed.
- `ExpireWeapon.UseInvokerAsOwner` can be used to set the house and TechnoType that created the effect (e.g firer of the weapon that applied it) as the weapon's owner & invoker instead of the object the effect is attached to.
- `ExpireWeapon.InvokerMustAlive`, if set to true, this weapon will disabled when invoker is dead.
- `Tint.Color` & `Tint.Intensity` can be used to set a color tint effect and additive lighting increase/decrease on the object the effect is attached to, respectively.
- `Tint.VisibleToHouses` can be used to control which houses can see the tint effect.
- `FirepowerMultiplier`, `ArmorMultiplier`, `SpeedMultiplier` and `ROFMultiplier` can be used to modify the object's firepower, armor strength, movement speed and weapon reload rate, respectively.
Expand Down Expand Up @@ -115,6 +116,7 @@ ExpireWeapon= ; WeaponType
ExpireWeapon.TriggerOn=expire ; List of expire weapon trigger condition enumeration (none|expire|remove|death|discard|all)
ExpireWeapon.CumulativeOnlyOnce=false ; boolean
ExpireWeapon.UseInvokerAsOwner=false ; boolean
ExpireWeapon.InvokerMustAlive=true ; boolean
Tint.Color= ; integer - R,G,B
Tint.Intensity= ; floating point value
Tint.VisibleToHouses=all ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all)
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ New:
- CellSpread in cylinder shape (by TaranDahl)
- CellSpread damage check if victim is in air or on floor (by TaranDahl)
- OpenTopped range bonus and damage multiplier customization for passengers (by Ollerus)
- Allow customize either `ExpireWeapon` can detonate or not if invoker of AE is dead (by NetsuNegi)
Vanilla fixes:
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)
Expand Down
36 changes: 10 additions & 26 deletions src/Ext/Techno/Body.Update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1823,7 +1823,7 @@ void TechnoExt::ExtData::UpdateAttachEffects()
bool markForRedraw = false;
bool altered = false;
std::vector<std::unique_ptr<AttachEffectClass>>::iterator it;
std::vector<std::pair<WeaponTypeClass*, TechnoClass*>> expireWeapons;
std::vector<ExpireWeaponData> expireWeapons;

for (it = this->AttachedEffects.begin(); it != this->AttachedEffects.end(); )
{
Expand Down Expand Up @@ -1860,14 +1860,9 @@ void TechnoExt::ExtData::UpdateAttachEffects()
if (!pType->Cumulative || !pType->ExpireWeapon_CumulativeOnlyOnce || this->GetAttachedEffectCumulativeCount(pType) < 1)
{
if (pType->ExpireWeapon_UseInvokerAsOwner)
{
if (auto const pInvoker = attachEffect->GetInvoker())
expireWeapons.push_back(std::make_pair(pType->ExpireWeapon, pInvoker));
}
expireWeapons.emplace_back(pType->ExpireWeapon, attachEffect->GetInvoker(), attachEffect->GetInvokerHouse());
else
{
expireWeapons.push_back(std::make_pair(pType->ExpireWeapon, pThis));
}
expireWeapons.emplace_back(pType->ExpireWeapon, pThis, pThis->Owner);
}
}

Expand All @@ -1894,11 +1889,8 @@ void TechnoExt::ExtData::UpdateAttachEffects()

auto const coords = pThis->GetCoords();

for (auto const& pair : expireWeapons)
{
auto const pInvoker = pair.second;
WeaponTypeExt::DetonateAt(pair.first, coords, pInvoker, pInvoker->Owner, pThis);
}
for (auto const& [pWeapon, pInvoker, pInvokerHouse] : expireWeapons)
WeaponTypeExt::DetonateAt(pWeapon, coords, pInvoker, pInvokerHouse, pThis);
}

// Updates self-owned (defined on TechnoType) AttachEffects, called on type conversion.
Expand All @@ -1908,7 +1900,7 @@ void TechnoExt::ExtData::UpdateSelfOwnedAttachEffects()
auto const pTypeExt = this->TypeExtData;
auto const pTechnoType = pTypeExt->OwnerObject();
std::vector<std::unique_ptr<AttachEffectClass>>::iterator it;
std::vector<std::pair<WeaponTypeClass*, TechnoClass*>> expireWeapons;
std::vector<ExpireWeaponData> expireWeapons;
bool altered = false;

// Delete ones on old type and not on current.
Expand All @@ -1927,14 +1919,9 @@ void TechnoExt::ExtData::UpdateSelfOwnedAttachEffects()
if (!pType->Cumulative || !pType->ExpireWeapon_CumulativeOnlyOnce || this->GetAttachedEffectCumulativeCount(pType) < 1)
{
if (pType->ExpireWeapon_UseInvokerAsOwner)
{
if (auto const pInvoker = attachEffect->GetInvoker())
expireWeapons.push_back(std::make_pair(pType->ExpireWeapon, pInvoker));
}
expireWeapons.emplace_back(pType->ExpireWeapon, attachEffect->GetInvoker(), attachEffect->GetInvokerHouse());
else
{
expireWeapons.push_back(std::make_pair(pType->ExpireWeapon, pThis));
}
expireWeapons.emplace_back(pType->ExpireWeapon, pThis, pThis->Owner);
}
}

Expand All @@ -1949,11 +1936,8 @@ void TechnoExt::ExtData::UpdateSelfOwnedAttachEffects()

auto const coords = pThis->GetCoords();

for (auto const& pair : expireWeapons)
{
auto const pInvoker = pair.second;
WeaponTypeExt::DetonateAt(pair.first, coords, pInvoker, pInvoker->Owner, pThis);
}
for (auto const& [pWeapon, pInvoker, pInvokerHouse] : expireWeapons)
WeaponTypeExt::DetonateAt(pWeapon, coords, pInvoker, pInvokerHouse, pThis);

// Add new ones.
const int count = AttachEffectClass::Attach(pThis, pThis->Owner, pThis, pThis, pTypeExt->AttachEffects);
Expand Down
25 changes: 9 additions & 16 deletions src/Ext/Techno/Hooks.ReceiveDamage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ DEFINE_HOOK(0x702050, TechnoClass_ReceiveDamage_AttachEffectExpireWeapon, 0x6)

auto const pExt = TechnoExt::ExtMap.Find(pThis);
std::set<AttachEffectTypeClass*> cumulativeTypes;
std::vector<std::pair<WeaponTypeClass*, TechnoClass*>> expireWeapons;
std::vector<ExpireWeaponData> expireWeapons;

for (auto const& attachEffect : pExt->AttachedEffects)
{
Expand All @@ -301,25 +301,17 @@ DEFINE_HOOK(0x702050, TechnoClass_ReceiveDamage_AttachEffectExpireWeapon, 0x6)
cumulativeTypes.insert(pType);

if (pType->ExpireWeapon_UseInvokerAsOwner)
{
if (auto const pInvoker = attachEffect->GetInvoker())
expireWeapons.push_back(std::make_pair(pType->ExpireWeapon, pInvoker));
}
expireWeapons.emplace_back(pType->ExpireWeapon, attachEffect->GetInvoker(), attachEffect->GetInvokerHouse());
else
{
expireWeapons.push_back(std::make_pair(pType->ExpireWeapon, pThis));
}
expireWeapons.emplace_back(pType->ExpireWeapon, pThis, pThis->Owner);
}
}
}

auto const coords = pThis->GetCoords();

for (auto const& pair : expireWeapons)
{
auto const pInvoker = pair.second;
WeaponTypeExt::DetonateAt(pair.first, coords, pInvoker, pInvoker->Owner, pThis);
}
for (auto const& [pWeapon, pInvoker, pInvokerHouse] : expireWeapons)
WeaponTypeExt::DetonateAt(pWeapon, coords, pInvoker, pInvokerHouse, pThis);

return 0;
}
Expand Down Expand Up @@ -378,16 +370,17 @@ DEFINE_HOOK(0x701E18, TechnoClass_ReceiveDamage_ReflectDamage, 0x7)
if (pType->ReflectDamage_UseInvokerAsOwner)
{
auto const pInvoker = attachEffect->GetInvoker();
const auto pInvokerHouse = pInvoker ? pInvoker->Owner : attachEffect->GetInvokerHouse();

if (pInvoker && EnumFunctions::CanTargetHouse(pType->ReflectDamage_AffectsHouses, pInvoker->Owner, pSourceHouse))
if (pInvokerHouse && EnumFunctions::CanTargetHouse(pType->ReflectDamage_AffectsHouses, pInvokerHouse, pSourceHouse))
{
auto const pWHExtRef = WarheadTypeExt::ExtMap.Find(pWH);
pWHExtRef->Reflected = true;

if (pType->ReflectDamage_Warhead_Detonate)
WarheadTypeExt::DetonateAt(pWH, pSource, pInvoker, damage, pInvoker->Owner);
WarheadTypeExt::DetonateAt(pWH, pSource, pInvoker, damage, pInvokerHouse);
else
pSource->ReceiveDamage(&damage, 0, pWH, pInvoker, false, false, pInvoker->Owner);
pSource->ReceiveDamage(&damage, 0, pWH, pInvoker, false, false, pInvokerHouse);

pWHExtRef->Reflected = false;
}
Expand Down
5 changes: 3 additions & 2 deletions src/Ext/Techno/WeaponHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,10 @@ void TechnoExt::ApplyRevengeWeapon(TechnoClass* pThis, TechnoClass* pSource, War
if (pType->RevengeWeapon_UseInvokerAsOwner)
{
auto const pInvoker = attachEffect->GetInvoker();
const auto pInvokerHouse = pInvoker ? pInvoker->Owner : attachEffect->GetInvokerHouse();

if (pInvoker && EnumFunctions::CanTargetHouse(pType->RevengeWeapon_AffectsHouses, pInvoker->Owner, pSourceOwner))
WeaponTypeExt::DetonateAt(pType->RevengeWeapon, pSource, pInvoker);
if (pInvokerHouse && EnumFunctions::CanTargetHouse(pType->RevengeWeapon_AffectsHouses, pInvokerHouse, pSourceOwner))
WeaponTypeExt::DetonateAt(pType->RevengeWeapon, pSource, pInvoker, pInvokerHouse);
}
else if (EnumFunctions::CanTargetHouse(pType->RevengeWeapon_AffectsHouses, pThisOwner, pSourceOwner))
{
Expand Down
24 changes: 10 additions & 14 deletions src/New/Entity/AttachEffectClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,11 @@ void AttachEffectClass::PointerGotInvalid(void* ptr, bool removed)
{
if (pTechno == pEffect->Invoker)
{
AnnounceInvalidPointer(pEffect->Invoker, ptr);
pEffect->Invoker = nullptr;

if ((pEffect->Type->DiscardOn & DiscardCondition::InvokerDie) != DiscardCondition::None)
pEffect->ShouldBeDiscarded = true;

count--;

if (count <= 0)
Expand Down Expand Up @@ -867,7 +871,7 @@ int AttachEffectClass::RemoveAllOfType(AttachEffectTypeClass* pType, TechnoClass

auto const targetAEs = &pTargetExt->AttachedEffects;
std::vector<std::unique_ptr<AttachEffectClass>>::iterator it;
std::vector<std::pair<WeaponTypeClass*, TechnoClass*>> expireWeapons;
std::vector<ExpireWeaponData> expireWeapons;

for (it = targetAEs->begin(); it != targetAEs->end(); )
{
Expand All @@ -886,14 +890,9 @@ int AttachEffectClass::RemoveAllOfType(AttachEffectTypeClass* pType, TechnoClass
if (!pType->Cumulative || !pType->ExpireWeapon_CumulativeOnlyOnce || stackCount == 1)
{
if (pType->ExpireWeapon_UseInvokerAsOwner)
{
if (auto const pInvoker = attachEffect->Invoker)
expireWeapons.push_back(std::make_pair(pType->ExpireWeapon, pInvoker));
}
expireWeapons.emplace_back(pType->ExpireWeapon, attachEffect->Invoker, attachEffect->InvokerHouse);
else
{
expireWeapons.push_back(std::make_pair(pType->ExpireWeapon, pTarget));
}
expireWeapons.emplace_back(pType->ExpireWeapon, pTarget, pTarget->Owner);
}
}

Expand Down Expand Up @@ -921,11 +920,8 @@ int AttachEffectClass::RemoveAllOfType(AttachEffectTypeClass* pType, TechnoClass

auto const coords = pTarget->GetCoords();

for (auto const& pair : expireWeapons)
{
auto const pInvoker = pair.second;
WeaponTypeExt::DetonateAt(pair.first, coords, pInvoker, pInvoker->Owner, pTarget);
}
for (auto const& [pWeapon, pInvoker, pInvokerHouse] : expireWeapons)
WeaponTypeExt::DetonateAt(pWeapon, coords, pInvoker, pInvokerHouse, pTarget);

return detachedCount;
}
Expand Down
14 changes: 14 additions & 0 deletions src/New/Entity/AttachEffectClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class AttachEffectClass
bool ShouldBeDiscardedNow();
bool IsFromSource(TechnoClass* pInvoker, AbstractClass* pSource) const { return pInvoker == this->Invoker && pSource == this->Source; }
TechnoClass* GetInvoker() const { return this->Invoker; }
HouseClass* GetInvokerHouse() const { return this->InvokerHouse; }
bool IsActive() const { return this->IsOnline && this->IsActiveIgnorePowered(); }

bool IsActiveIgnorePowered() const
Expand Down Expand Up @@ -138,3 +139,16 @@ struct AttachEffectTechnoProperties
, HasCritModifiers { false }
{ }
};

struct ExpireWeaponData
{
WeaponTypeClass* Weapon { nullptr };
TechnoClass* Owner { nullptr };
HouseClass* OwnerHouse { nullptr };

ExpireWeaponData(WeaponTypeClass* pWeapon, TechnoClass* pOwner, HouseClass* pOwnerHouse)
: Weapon(pWeapon)
, Owner(pOwner)
, OwnerHouse(pOwnerHouse)
{ }
};
4 changes: 4 additions & 0 deletions src/New/Type/AttachEffectTypeClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,10 @@ namespace detail
{
parsed |= DiscardCondition::Firing;
}
else if (!_strcmpi(cur, "invokerdie"))
{
parsed |= DiscardCondition::InvokerDie;
}
else
{
Debug::INIParseFailed(pSection, pKey, cur, "Expected a discard condition type");
Expand Down
3 changes: 2 additions & 1 deletion src/New/Type/AttachEffectTypeClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ enum class DiscardCondition : unsigned char
Drain = 0x8,
InRange = 0x10,
OutOfRange = 0x20,
Firing = 0x40
Firing = 0x40,
InvokerDie = 0x80
};

MAKE_ENUM_FLAGS(DiscardCondition);
Expand Down