Перейти к содержимому

Фотография

RemoveStackingEffects doesn't seem to be working?


  • Пожалуйста, авторизуйтесь, чтобы ответить
2 ответов в этой теме

#1
dainbramage

dainbramage
  • Members
  • 469 сообщений
I'm trying to mod dual weapon expert, since it's one of the buggiest abilities out there, and most of the fixes are only oriented on the interaction with friendly fire. The event override works fine, as does most of the script that's copypastad from rules_core. It's just refreshing the duration that's vexing me.

Here's the relevant code from Ability_HandleOnDamageAbilities in ability_h (I've overridden event_type_damaged and called the function fine):

if (IsObjectValid(oAttacker))
    {
        if (IsCreatureSpecialRank(oAttacker))
        {
            if (IsHumanoid(oAttacker))
            {
                //if (nDamageType == DAMAGE_TYPE_PHYSICAL)
                //{
                    if ((GetWeaponStyle(oAttacker) == WEAPONSTYLE_DUAL) && (HasAbility(oAttacker, ABILITY_TALENT_DUAL_WEAPON_EXPERT)))
                    {
                        if (CanCreatureBleed(oDamaged))
                        {
                            if (nAbility != ABILITY_TALENT_DUAL_WEAPON_EXPERT)
                            {
                                //if (oDamaged != oAttacker) //Stop DWE from hurting yourself
                                //{
                                    float fdam = 7.0f + IntToFloat(GetLevel(oAttacker));

                                    RemoveStackingEffects(oDamaged, oAttacker, ABILITY_TALENT_DUAL_WEAPON_EXPERT);
                                    ApplyEffectDamageOverTime(oDamaged, oAttacker, ABILITY_TALENT_DUAL_WEAPON_EXPERT, fdam, 5.0f, DAMAGE_TYPE_PHYSICAL, 0, 1016);

                                    //event eOnHit= Event(EVENT_TYPE_ITEM_ONHIT);
                                    //eOnHit = SetEventCreator(eOnHit, oAttacker);
                                    //eOnHit = SetEventInteger(eOnHit,0, ITEM_PROPERTY_ONHIT_VICIOUS);
                                    //eOnHit = SetEventInteger(eOnHit,1, ((GetLevel(oAttacker)/5)+1) );
                                    //eOnHit = SetEventInteger(eOnHit,2, TRUE);
                                    //DelayEvent(0.0f, oDamaged, eOnHit);
                                //}
                            }
                        }
                    }
                //}
            }
        }
    }

Now, I've been testing this by just turning on aura of pain, with the damage type and attacker != damaged checks commented out (as above). When I do this, it works as expected. Every aura of pain tick refreshes the dot. More importantly, I never have two dots active. Only one floating number at a time from dual weapon expert.

On the other hand, if I hit an enemy twice, it doesn't work right. The enemy gets two dots on him, and every tick there's two floating numbers (or more, if I hit him more than twice). Which would indicate that removestackingeffects isn't working, but it did when I was hitting myself.

Instead of removestacking effects I can make applying the dot conditional on !GetHasEffects, but I'd prefer each hit to refresh the duration.

Any suggestions?

#2
dainbramage

dainbramage
  • Members
  • 469 сообщений
More fiddling with it, and some really strange behaviour.

Removing the effect makes the game report 0 effects between removing it and applying the next effect. However the next effect comprises multiple dots - the sum of as many as have been applied, and they seem to never expire. This is basically the same thing as when the corrupted spider queen kicks your ass with her poison spit, and worse behaviour than if I never try to remove previous effects at all (where they expire as normal). The same happens if I use !GetHasEffects, but only when the previous dot times out. But an infinite number of stacks is still eventually reached.

It seems like when one dot effect is removed, if another one is applied soon after, the new effect gets the properties of the deleted one in addition to its own. Is this documented anywhere, or how to circumvent it?

#3
DarthGizka

DarthGizka
  • Members
  • 867 сообщений

Same sort of thing as getting a Paralysis Explosion from a glyph that has been removed by disarming it (Jarvia's, Keep), only worse.

Logically speaking the DW expert DOT should stack - each successful hit should cause its own laceration, and the damage should not be reduced by armour. That would mean an extra 40 DPS or so at level 25, whereas now the laceration thing is mostly useless.

From that point of view it isn't the DOT logic that needs fixing, it is the erroneous reduction of the damage by armour rating.

Increasing the effect damage in order to account for armour rating would cause new bugs, though. Like when the victim's armour rating changes because of abilities like Sunder Armour and Shattering Shot, or because sustains are turned off (e.g. out of mana, player action). Similar problems would arise if you tried to get around the armour problem by changing the damage type, because of unknown or changing resistances.

A proper fix would require per-tick processing and ignoring ApplyEffectDamageOverTime() entirely.

It is probably easier to argue that non-trivial lacerations are only possible if armour rating is less than 6 and leave things as they are.

If you want to nerf the DOT further by having it refresh duration instead of stacking: since the broken engine doesn't let you replace the original DOT or change its duration, you could simply tack a new, shorter DOT on the end of the old one, with duration set to the difference between the full DOT time and the time left for the currently existing DOT.

Feasibility hinges upon two things:
o possibility of keeping two time values per doer on each victim
o getting control at each tick

On each victim, store two absolute time values for each doer; let's call them LogicalEndOfEffect and EndOfAppliedEffect. The first is set whenever a laceration occurs and it specifies the desired end of your logical effect (e.g. now() + 8 s at level 25). The second is set whenever you call ApplyEffectDamageOverTime(), and it gives the end time of that effect fragment. That value will be equal to LogicalEndOfEffect at the time of call, after that value has been fuzzed as necessary.

There is no need to store the damage as well, since that is level-based like the duration and not subject to sudden, unforeseen changes (no level-up in combat).

At each tick on the victim, compare EndOfAppliedEffect to LogicalEndOfEffect for each doer, and call ApplyEffectDamageOverTime() based on the difference of the two if the current effect fragment has run out.

However, the engine suspends processing at the slightest provocation and it cannot even handle something as basic as spell/ability cooldowns properly. Hence you are bound to hit quite a few brick walls.
 


  • Это нравится: luna1124