[JASS] Custom Mana Shield Math Formula Help

For https://www.hiveworkshop.com/threads/improved-mana-shield-spells.371330/

Can someone help me fix this formula so it acts like regular mana shield's inputs? Right now it doesn't work as expected.

JASS:
function Trig_Enhanced_Mana_Shield_Conditions takes nothing returns boolean
    local integer BUFF_ID = 'B000' //Set this to the buff used by Enhanced Mana Shield
    return GetUnitAbilityLevel(udg_DamageEventTarget,BUFF_ID) >  0
endfunction

function Trig_Enhanced_Mana_Shield_Actions takes nothing returns nothing
    local integer AID = 'A000' //Set this to the id of the Enhanced Mana Shield Ability
    local real basemanacost = 1.0 //Set this to the base mana cost per damage point at level 1 [Increasing this should increase shield efficiency meaning less mana cost per point of damage]
    local real manacostperlevel = -0.25 //This is mana cost adjustment for each level beyond 1 [Increasing this should increase shield efficiency meaning less mana cost per point of damage]
    local real mana = GetUnitState(udg_DamageEventTarget,UNIT_STATE_MANA)
    local real lvl = GetUnitAbilityLevel(udg_DamageEventTarget,AID)
    local real shieldefficeny = basemanacost + (manacostperlevel * (lvl -1))
    if mana * shieldefficeny > udg_DamageEventAmount then
        call SetUnitState(udg_DamageEventTarget,UNIT_STATE_MANA,mana - (udg_DamageEventAmount * shieldefficeny))
        set udg_DamageEventAmount = 0.
    else
        call SetUnitState(udg_DamageEventTarget,UNIT_STATE_MANA,0.)
        set udg_DamageEventAmount = udg_DamageEventAmount - (mana * shieldefficeny)
    endif
endfunction

//===========================================================================
function InitTrig_Enhanced_Mana_Shield takes nothing returns nothing
    set gg_trg_Enhanced_Mana_Shield = CreateTrigger(  )
    call TriggerRegisterVariableEvent( gg_trg_Enhanced_Mana_Shield, "udg_ArmorDamageEvent", EQUAL, 1.00 )
    call TriggerAddCondition( gg_trg_Enhanced_Mana_Shield, Condition( function Trig_Enhanced_Mana_Shield_Conditions ) )
    call TriggerAddAction( gg_trg_Enhanced_Mana_Shield, function Trig_Enhanced_Mana_Shield_Actions )
endfunction
 
Hi, so I think there are a couple of different issues happening here.

First, about the shield not turning off I suppose:

The default Mana Shield automatically disables itself when mana reaches 0 (removes the buff + toggles off).
In your implementation you only set mana to 0, but the buff stays active.

Because of that, the moment the unit regenerates even 1 mana, the shield starts absorbing again.
So instead of behaving like a toggle that breaks, it ends up acting like a passive “mini shield” on tiny mana ticks.

You probably want to manually remove the buff and order the ability off when mana is depleted.

the formula:


Code:
if mana * shieldefficeny > udg_DamageEventAmount then


If efficiency represents “mana per damage” (exmpl. 0.5), then multiplying it by mana gives you a scaled mana pool, which isn’t the right comparison.

Example:

50 mana * 0.5 = 25 → compared vs 100 damage
So the shield breaks earlier than it should.

Instead, calculate how much mana is needed for the incoming damage:
manaNeeded = damage * efficiency
Then just check:

if mana >= manaNeeded then



Also, small edge case:

If the unit loses the ability (item drop, morph, etc.), the buff can remain while ability level becomes 0.

That can mess up the scaling (since lvl - 1 becomes negative), and depending on your values you could even hit 0 efficiency, which will break the calculation.

It’s probably worth clamping the minimum efficiency to something above 0.



About the damage event:

You’re currently using ArmorDamageEvent, which runs after armor reduction.

Just keep in mind that this makes it behave differently from default Mana Shield (which is pre-armor), so the effective strength will vary a lot with armor values.

Side note: for the deactivation order, the integer Order ID for 'manashieldoff' is 852590. Using IssueImmediateOrderById is safer than the string 'manashieldoff' because it works regardless of the base ability you used to create the custom spell.
 
Last edited:
Hey, not trying to nitpick, but the invulnerability approach is going to cause problems.
call UnitAddAbility(u, INVULID)


I tested it with Frost Wyrm attacks; since the game tries to apply the frost debuff at the same moment you’re adding invulnerability, it ends up interfering with normal effect application and leaves the unit perma invulnerable.

Same with Storm Bolt: the invulnerability prevents the stun from being applied properly, so secondary effects get skipped rather than “cleanly blocked”.

I think this is one of those cases where handling it directly in the damage event (instead of toggling invulnerability) would be more reliable and avoid these edge cases.

Edit: The code is also suffering from multi unit meltdown:


The script triggers. It sees the Paladin has enough mana, deducts it, and calls UnitAddAbility(u, 'Invul'). The Paladin is now technically Divine Shielded.

Other units: Target Loss (Impervious mana shield has side effects such as units losing attack orders on the target when it blocks damage, as u stated in the resource)

The remaining units were mid-swing. Suddenly, their target is Invulnerable.

UnitAddAbility(u, INVULID), never gets removed in the success block.

The Paladin stays Invulnerable forever until his mana runs out from other sources or a lucky hit happens during a script delay.

 
Last edited:
Hey, not trying to nitpick, but the invulnerability approach is going to cause problems.
call UnitAddAbility(u, INVULID)


I tested it with Frost Wyrm attacks; since the game tries to apply the frost debuff at the same moment you’re adding invulnerability, it ends up interfering with normal effect application and leaves the unit perma invulnerable.

Same with Storm Bolt: the invulnerability prevents the stun from being applied properly, so secondary effects get skipped rather than “cleanly blocked”.

I think this is one of those cases where handling it directly in the damage event (instead of toggling invulnerability) would be more reliable and avoid these edge cases.

Edit: The code is also suffering from multi unit meltdown:


The script triggers. It sees the Paladin has enough mana, deducts it, and calls UnitAddAbility(u, 'Invul'). The Paladin is now technically Divine Shielded.

Other units: Target Loss (Impervious mana shield has side effects such as units losing attack orders on the target when it blocks damage, as u stated in the resource)

The remaining units were mid-swing. Suddenly, their target is Invulnerable.

UnitAddAbility(u, INVULID), never gets removed in the success block.

The Paladin stays Invulnerable forever until his mana runs out from other sources or a lucky hit happens during a script delay.

I'm unable to re-create this, did you remember to update this trigger:
1775583211759.png
 
You're focusing on the wrong issue. Whether it’s a Rifleman or a Frost Wyrm, the issue isn't the name of the attacker; it’s the combat state resolution that your script fails to handle.

Here is what i meant: the technical reality that your 'Arrow Key' test misses;

Event Frequency: The Riflemen in the video prove that your AfterDamageEvent cleanup is too slow for standard high frequency physical attacks. When multiple units attack, the 'Invulnerable' status toggles so fast that it breaks the engine's targeting grid. This is why you see the 'flicker' the units are literally losing their target mid swing.

State Collisions -- The Frost Wyrm: I specifically used a Frost Wyrm because it applies a buff (freezing breath) at the exact moment of impact. Because your script adds Invulnerability during the DAMAGING event, the engine is forced to resolve a 'Buff Application' on an 'Invulnerable' unit simultaneously. This is what causes the Permanent Invulnerability bug seen in the video.

Triggered vs. Physical:
Your arrow-key Priests deal Triggered Spell Damage, which bypasses the standard Attack/Buff/State loop of the WC3 engine.

It's because your test map isn't simulating a real game environment.
 
You're focusing on the wrong issue. Whether it’s a Rifleman or a Frost Wyrm, the issue isn't the name of the attacker; it’s the combat state resolution that your script fails to handle.

Here is what i meant: the technical reality that your 'Arrow Key' test misses;

Event Frequency: The Riflemen in the video prove that your AfterDamageEvent cleanup is too slow for standard high frequency physical attacks. When multiple units attack, the 'Invulnerable' status toggles so fast that it breaks the engine's targeting grid. This is why you see the 'flicker' the units are literally losing their target mid swing.

State Collisions -- The Frost Wyrm: I specifically used a Frost Wyrm because it applies a buff (freezing breath) at the exact moment of impact. Because your script adds Invulnerability during the DAMAGING event, the engine is forced to resolve a 'Buff Application' on an 'Invulnerable' unit simultaneously. This is what causes the Permanent Invulnerability bug seen in the video.

Triggered vs. Physical:
Your arrow-key Priests deal Triggered Spell Damage, which bypasses the standard Attack/Buff/State loop of the WC3 engine.

It's because your test map isn't simulating a real game environment.
Good to know thanks. I should probably just remove Impervious mana shield since its too glitchy.
 
It can be made to work, just not through invulnerability. That approach will always be unstable in real combat scenarios.
See if this works any better. As in see if this removes the permanent invulnerability bug.
 

Attachments

See if this works any better. As in see if this removes the permanent invulnerability bug.
The permanent invulnerability is gone, but because the system is still toggling invulnerability/abilities on and off to block damage, attackers are losing their target acquisition for a brief moment whenever the shield procs. It creates a 'pause' in combat that looks a bit glitchy and disrupts the flow of the engagement.

-Disruption of secondary effects:

Basically the system is technically nullifying the hit or using an invulnerability state (similar to Cloak of Shadows), it’s stripping away negative buffs that should land. Now Frost Wyrm's frost breath doesn’t apply a debuff or standard slow spells are being deleted. This deviates significantly from how a Mana Shield is expected to behave — it should protect hp, not act as a full dispel-immunity, unless you intended. The bash still gets applied briefly because the engine clears the slow buffs instantly because they are modifiers, but the Bash 'stun state' is a physics change that takes a few frames to catch up.

Complexity issue:

The system is currently leaning on several different triggers and sub-systems to work.(Timer Utils and Timed Ability that you added)

Why am I telling you this: Not only is this harder to debug, but spell reviewers generally prefer clean, efficient solutions. A system that uses multiple workarounds to mimic a single ability might get flagged for poor optimization or lack of 'mercy' during the technical review phase.

I think you should move toward a single trigger approach that modifies the damage value directly within the engine. It would be much more stable, keep the paladin as a valid target for debuffs/ engagements, and look much cleaner to a reviewer.

Using Invulnerability as a 'patch' for a Mana Shield is a bit of a rough workaround. Cuz basically it’s like trying to protect a house from a rainstorm by teleporting the house to another dimension and back every time a raindrop falls :vw_death:.


One thing to keep in mind is that invulnerability in the WC3 engine isn't just a simple 'damage off' switch; it’s a State Flag. When that flag is toggled; even for a micro-secon—-it signals the game's internal 'cleanup' and 'targeting' logic to run immediately. Because it's a global flag the AI instantly 'delists' the unit: This is why the attackers are losing acquisition, then regaining it; The moment that flag flips, the attacker’s AI thinks the target is gone and tries to find a new one. The status engine runs a purge because the engine is hard-coded to remove 'hostile' modifiers from an invulnerable unit.
 
Back
Top