@@ -51,13 +51,16 @@ AttachEffectClass::AttachEffectClass(AttachEffectTypeClass* pType, TechnoClass*
51
51
if (this ->InitialDelay <= 0 )
52
52
this ->HasInitialized = true ;
53
53
54
- this ->Duration = this ->DurationOverride != 0 ? this ->DurationOverride : this -> Type ->Duration ;
54
+ this ->Duration = this ->DurationOverride != 0 ? this ->DurationOverride : pType ->Duration ;
55
55
56
- if (this -> Type ->Duration_ApplyFirepowerMult && this ->Duration > 0 && pInvoker)
56
+ if (pType ->Duration_ApplyFirepowerMult && this ->Duration > 0 && pInvoker)
57
57
this ->Duration = Math::max (static_cast <int >(this ->Duration * pInvoker->FirepowerMultiplier * TechnoExt::ExtMap.Find (pInvoker)->AE .FirepowerMultiplier ), 0 );
58
58
59
- if (this ->Type ->Duration_ApplyArmorMultOnTarget && this ->Duration > 0 ) // count its own ArmorMultiplier as well
60
- this ->Duration = Math::max (static_cast <int >(this ->Duration / pTechno->ArmorMultiplier / TechnoExt::ExtMap.Find (pTechno)->AE .ArmorMultiplier / this ->Type ->ArmorMultiplier ), 0 );
59
+ if (pType->Duration_ApplyArmorMultOnTarget && this ->Duration > 0 ) // count its own ArmorMultiplier as well
60
+ this ->Duration = Math::max (static_cast <int >(this ->Duration / pTechno->ArmorMultiplier / TechnoExt::ExtMap.Find (pTechno)->AE .ArmorMultiplier / pType->ArmorMultiplier ), 0 );
61
+
62
+ if (pInvoker)
63
+ TechnoExt::ExtMap.Find (pInvoker)->AttachedEffectInvokerCount ++;
61
64
62
65
AttachEffectClass::Array.emplace_back (this );
63
66
}
@@ -70,25 +73,50 @@ AttachEffectClass::~AttachEffectClass()
70
73
AttachEffectClass::Array.erase (it);
71
74
72
75
this ->KillAnim ();
76
+
77
+ if (this ->Invoker )
78
+ TechnoExt::ExtMap.Find (this ->Invoker )->AttachedEffectInvokerCount --;
73
79
}
74
80
75
81
void AttachEffectClass::PointerGotInvalid (void * ptr, bool removed)
76
82
{
77
83
auto const abs = static_cast <AbstractClass*>(ptr);
78
- auto const absType = abs->WhatAmI ();
79
84
80
- if (absType == AbstractType::Anim )
85
+ if (auto const pAnim = abstract_cast<AnimClass*, true >(abs) )
81
86
{
82
- for (auto pEffect : AttachEffectClass::Array )
87
+ if (auto const pAnimExt = AnimExt::ExtMap. Find (pAnim) )
83
88
{
84
- if (ptr == pEffect->Animation )
85
- pEffect->Animation = nullptr ;
89
+ if (pAnimExt->IsAttachedEffectAnim )
90
+ {
91
+ for (auto const pEffect : AttachEffectClass::Array)
92
+ {
93
+ if (pAnim == pEffect->Animation )
94
+ {
95
+ pEffect->Animation = nullptr ;
96
+ break ; // one anim must be used by less than one AE
97
+ }
98
+ }
99
+ }
86
100
}
87
101
}
88
102
else if ((abs->AbstractFlags & AbstractFlags::Techno) != AbstractFlags::None)
89
103
{
90
- for (auto pEffect : AttachEffectClass::Array)
91
- AnnounceInvalidPointer (pEffect->Invoker , ptr);
104
+ auto const pTechno = abstract_cast<TechnoClass*, true >(abs);
105
+
106
+ if (int count = TechnoExt::ExtMap.Find (pTechno)->AttachedEffectInvokerCount )
107
+ {
108
+ for (auto const pEffect : AttachEffectClass::Array)
109
+ {
110
+ if (pTechno == pEffect->Invoker )
111
+ {
112
+ AnnounceInvalidPointer (pEffect->Invoker , ptr);
113
+ count--;
114
+
115
+ if (count <= 0 )
116
+ break ;
117
+ }
118
+ }
119
+ }
92
120
}
93
121
}
94
122
@@ -314,7 +342,7 @@ void AttachEffectClass::CreateAnim()
314
342
if (!this ->HasCumulativeAnim )
315
343
return ;
316
344
317
- int count = TechnoExt::ExtMap.Find (this ->Techno )->GetAttachedEffectCumulativeCount (this ->Type );
345
+ const int count = TechnoExt::ExtMap.Find (this ->Techno )->GetAttachedEffectCumulativeCount (this ->Type );
318
346
pAnimType = this ->Type ->GetCumulativeAnimation (count);
319
347
}
320
348
else
@@ -327,18 +355,22 @@ void AttachEffectClass::CreateAnim()
327
355
328
356
if (!this ->Animation && pAnimType)
329
357
{
330
- auto const pAnim = GameCreate<AnimClass>(pAnimType, this ->Techno ->Location );
358
+ auto const pTechno = this ->Techno ;
359
+ auto const pAnim = GameCreate<AnimClass>(pAnimType, pTechno->Location );
331
360
332
- pAnim->SetOwnerObject (this -> Techno );
333
- auto const pOwner = this ->Type ->Animation_UseInvokerAsOwner ? this ->InvokerHouse : this -> Techno ->Owner ;
334
- pAnim-> Owner = pOwner;
335
- pAnim-> RemainingIterations = 0xFFu ;
336
- this -> Animation = pAnim ;
361
+ pAnim->SetOwnerObject (pTechno );
362
+ pAnim-> Owner = this ->Type ->Animation_UseInvokerAsOwner ? this ->InvokerHouse : pTechno ->Owner ;
363
+
364
+ auto const pAnimExt = AnimExt::ExtMap. Find (pAnim) ;
365
+ pAnimExt-> IsAttachedEffectAnim = true ;
337
366
338
367
if (this ->Type ->Animation_UseInvokerAsOwner )
339
- AnimExt::ExtMap. Find (pAnim) ->SetInvoker (this ->Invoker , this ->InvokerHouse );
368
+ pAnimExt ->SetInvoker (this ->Invoker , this ->InvokerHouse );
340
369
else
341
- AnimExt::ExtMap.Find (pAnim)->SetInvoker (this ->Techno );
370
+ pAnimExt->SetInvoker (pTechno);
371
+
372
+ pAnim->RemainingIterations = 0xFFu ;
373
+ this ->Animation = pAnim;
342
374
}
343
375
}
344
376
@@ -636,12 +668,14 @@ AttachEffectClass* AttachEffectClass::CreateAndAttach(AttachEffectTypeClass* pTy
636
668
currentTypeCount++;
637
669
match = attachEffect;
638
670
639
- if (pType->Cumulative && (!attachParams.CumulativeRefreshSameSourceOnly || (attachEffect->Source == pSource && attachEffect->Invoker == pInvoker)))
671
+ if (!pType->Cumulative )
672
+ break ;
673
+ else if (!attachParams.CumulativeRefreshSameSourceOnly || (attachEffect->Source == pSource && attachEffect->Invoker == pInvoker))
640
674
cumulativeMatches.push_back (attachEffect);
641
675
}
642
676
}
643
677
644
- if (pType-> Cumulative )
678
+ if (cumulativeMatches. size () > 0 )
645
679
{
646
680
if (pType->Cumulative_MaxCount >= 0 && currentTypeCount >= pType->Cumulative_MaxCount )
647
681
{
@@ -654,18 +688,15 @@ AttachEffectClass* AttachEffectClass::CreateAndAttach(AttachEffectTypeClass* pTy
654
688
}
655
689
else
656
690
{
657
- if (cumulativeMatches.size () > 0 )
658
- {
659
- AttachEffectClass* best = nullptr ;
691
+ AttachEffectClass* best = nullptr ;
660
692
661
- for (auto const & ae : cumulativeMatches)
662
- {
663
- if (!best || ae->Duration < best->Duration )
664
- best = ae;
665
- }
666
-
667
- best->RefreshDuration (attachParams.DurationOverride );
693
+ for (auto const & ae : cumulativeMatches)
694
+ {
695
+ if (!best || ae->Duration < best->Duration )
696
+ best = ae;
668
697
}
698
+
699
+ best->RefreshDuration (attachParams.DurationOverride );
669
700
}
670
701
671
702
return nullptr ;
@@ -685,7 +716,7 @@ AttachEffectClass* AttachEffectClass::CreateAndAttach(AttachEffectTypeClass* pTy
685
716
}
686
717
else
687
718
{
688
- targetAEs.push_back (std::make_unique<AttachEffectClass>(pType, pTarget, pInvokerHouse, pInvoker, pSource, attachParams.DurationOverride , attachParams.Delay , attachParams.InitialDelay , attachParams.RecreationDelay ));
719
+ targetAEs.emplace_back (std::make_unique<AttachEffectClass>(pType, pTarget, pInvokerHouse, pInvoker, pSource, attachParams.DurationOverride , attachParams.Delay , attachParams.InitialDelay , attachParams.RecreationDelay ));
689
720
auto const pAE = targetAEs.back ().get ();
690
721
691
722
if (!currentTypeCount && pType->Cumulative && pType->CumulativeAnimations .size () > 0 )
@@ -817,7 +848,8 @@ int AttachEffectClass::RemoveAllOfType(AttachEffectTypeClass* pType, TechnoClass
817
848
818
849
if (pType->ExpireWeapon && (pType->ExpireWeapon_TriggerOn & ExpireWeaponCondition::Remove) != ExpireWeaponCondition::None)
819
850
{
820
- if (!pType->Cumulative || !pType->ExpireWeapon_CumulativeOnlyOnce || pTargetExt->GetAttachedEffectCumulativeCount (pType) < 2 )
851
+ // can't be GetAttachedEffectCumulativeCount(pType) < 2, or inactive AE might make it stack more than once
852
+ if (!pType->Cumulative || !pType->ExpireWeapon_CumulativeOnlyOnce || stackCount == 1 )
821
853
expireWeapons.push_back (pType->ExpireWeapon );
822
854
}
823
855
@@ -831,6 +863,11 @@ int AttachEffectClass::RemoveAllOfType(AttachEffectTypeClass* pType, TechnoClass
831
863
}
832
864
833
865
it = targetAEs->erase (it);
866
+
867
+ if (!pType->Cumulative )
868
+ break ;
869
+
870
+ stackCount--;
834
871
}
835
872
else
836
873
{
0 commit comments