• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Detect mana loss?

Status
Not open for further replies.
Level 5
Joined
May 12, 2014
Messages
133
I want to create a trigger that can detect when a hero with a certain item loses mana. How would I go about this?
- It should be somewhat generic. Any hero can acquire said item and use it.
- It applies to all forms of losing mana: spellcasts, mana burn, mana drain, triggered mana loss, etc.
attachment.php


I'm not even sure how to start making a trigger for this, does anyone have an idea or awesome system to recommend?
 

Attachments

  • RingofLight.png
    RingofLight.png
    332.4 KB · Views: 227
Level 22
Joined
Feb 6, 2014
Messages
2,466
You could periodically check the mana of the Hero and store the current mana in a variable. When the next loop run and if the current mana is less than the stored previous mana, then your hero has its mana decreased. Though it will not be able to detect it instantly, but a 0.03 second delay seems fine in my opinion.
 
Level 5
Joined
May 12, 2014
Messages
133
My biggest problem with that is when the hero might regain mana within that brief delay.
ex: I have another item (another ring item, lol) that gains stacks of power upon taking magic damage. At 100 stacks it would activate, healing the hp and mp of the hero by 100.
Now if a demon hunter came along and mana burns the hero, he might activate this item. So the hero with the ring of light would only gain ~12 stacks instead of the ~37 stacks he deserves. (default mana burn drains 150 mana and deals up to the same amount).
 
Level 7
Joined
Nov 19, 2015
Messages
283
You would only be accurate if you triggered every single spell

or

Have triggers for every source of mana loss

Here is an idea


Unit starts the effect of an ability

Unit has item

set mana_after = mana of unit
set mana_stored = mana_stored + ((Mana_before - mana after)*0.25)
If mana_after>= mana_stored
then
mana of unit = mana of unit - mana_stored
else
mana_stored = mana_stored + mana of unit
mana of unit = 0

Set mana_before=mana of unit





Unit starts the effect of an ability

ability = mana drain
target unit has item

Do a similar thing from above
 
Level 5
Joined
May 12, 2014
Messages
133
You would only be accurate if you triggered every single spell

or

Have triggers for every source of mana loss

Here is an idea


Unit starts the effect of an ability

Unit has item

set mana_after = mana of unit
set mana_stored = mana_stored + ((Mana_before - mana after)*0.25)
If mana_after>= mana_stored
then
mana of unit = mana of unit - mana_stored
else
mana_stored = mana_stored + mana of unit
mana of unit = 0

Set mana_before=mana of unit





Unit starts the effect of an ability

ability = mana drain
target unit has item

Do a similar thing from above

You know, that is a pretty cute idea. I might try this and see what happens.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,180
Detect when it casts abilities or spends mana. These abilities have their mana cost then hard coded into triggers for lookup (eg in a hashtable with parent of ability type and key of unique string). That would be the simplest I would imagine. Every time such a mana consumer is used you increment the item's charge counter by the amount the consumer used.
 
Level 7
Joined
Nov 19, 2015
Messages
283
Detect when it casts abilities or spends mana. These abilities have their mana cost then hard coded into triggers for lookup (eg in a hashtable with parent of ability type and key of unique string). That would be the simplest I would imagine. Every time such a mana consumer is used you increment the item's charge counter by the amount the consumer used.

But if you have a million spells then it might take a while to write it all out. It would be fine for people who trigger most of their spells.

Also don't forget about mana regen (not jsut mana loss). Set a periodic for mana regen over time. You may loss a tiny amount of mana in between the intervals but shouldn't matter too much. Also items and other mana regen sources.
 
Level 5
Joined
May 12, 2014
Messages
133
Detect when it casts abilities or spends mana. These abilities have their mana cost then hard coded into triggers for lookup (eg in a hashtable with parent of ability type and key of unique string). That would be the simplest I would imagine. Every time such a mana consumer is used you increment the item's charge counter by the amount the consumer used.

Yeah, I might do it this way. Kingkwong's way worked perfectly except in one fairly common case. Some of the spells in my map cost extra mana such as "15% of remaining mana" or 20% of current mana". His way actually fails to include that extra mana.

I'll see how hashtables works and see how it goes. 1st time using a hashtable myself, so hope for the best!
 
Level 7
Joined
Nov 19, 2015
Messages
283
Yeah, I might do it this way. Kingkwong's way worked perfectly except in one fairly common case. Some of the spells in my map cost extra mana such as "15% of remaining mana" or 20% of current mana". His way actually fails to include that extra mana.

I'll see how hashtables works and see how it goes. 1st time using a hashtable myself, so hope for the best!

Add a condition than ignores the triggered abilities.
Add the mana store thingy after your take %mana cost off the unit.
It actually makes it easier when your spells are triggered. Better if they were all triggered.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,180
But if you have a million spells then it might take a while to write it all out. It would be fine for people who trigger most of their spells.
Yes, but there is apparently a way to automatically fetch all this data. Not sure if it still works in JNGP though.
Also don't forget about mana regen (not jsut mana loss). Set a periodic for mana regen over time. You may loss a tiny amount of mana in between the intervals but shouldn't matter too much. Also items and other mana regen sources.
Yes but that is usually positive, and such mana losses might not want to be considered for the item as then abilities like mana burn will convert into healing with it.
 
Level 5
Joined
May 12, 2014
Messages
133
Add a condition than ignores the triggered abilities.
Add the mana store thingy after your take %mana cost off the unit.
It actually makes it easier when your spells are triggered. Better if they were all triggered.

Oh, don't worry about that, at least 98% of my spells are triggered. The other 2% is probably AOE dummy stuns.:goblin_good_job:
 
Level 7
Joined
Nov 19, 2015
Messages
283
Oh, don't worry about that, at least 98% of my spells are triggered. The other 2% is probably AOE dummy stuns.:goblin_good_job:

Then it probs is best to store them all.

Save real as stringID(mana) of handle of ability in Spell Hash

Something like that, where you can store all sorts of stuff too.
 
Level 12
Joined
Nov 3, 2013
Messages
989
How about adding every unit with the item to a unit group and updating a real variable every 0.03 seconds with current mana.

Every time unit from unit group starts effect of ability, is damaged by unit with feedback (using DDS) or target of mana burn ability, compare it's current mana with it's corresponding mana variable.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
There is a way that you can detect mana change... it is working very well but is a bit of an overkill for WC3.
However, because you wont need it for that many units, you can have this without having lagg issues.

Another thing that I wanted to mention is that there is 0 need of triggering all spell's mana cost... just dont unless you want to go make real spells.

But the question is, Do you want
a, this to only detect mana taken from spell cost (with possible other things that can be added) (does not include stuff like mana drain, only the COST of abilities)?
b, it to detect ALL mana consumes, including triggered "Set mana = mana - x", spells like mana burn/feedback/etc, mana drain spells, etc?
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
You hold on right there.
I will be right back.

EDIT:
Ok, first of all...
Your method isn't really a "working" method because you won't be able to use this to detect mana consumption.
Next to that, your "unitHasItemOfType()" isn't nearly as good as a scripted one or even the BJ function of it.
Also... MUI :(
If that is not enough, redirecting function calls are just... I dont even know what to call it with your usage.
Also... is there any reason to turn off the trigger before showing the message?

And as a side note... you should definately use a temp variable for "Triggering unit"... as soon as you understand that you should use "Triggering unit" over "Ordered unit".
 
Last edited:
Level 5
Joined
May 12, 2014
Messages
133
Man, what did I miss out on? I go to sleep for one night and suddenly there are like 10 more replies. I must be on the the other side of the world.
But the question is, Do you want
a, this to only detect mana taken from spell cost (with possible other things that can be added) (does not include stuff like mana drain, only the COST of abilities)?
b, it to detect ALL mana consumes, including triggered "Set mana = mana - x", spells like mana burn/feedback/etc, mana drain spells, etc?

The answer is B. However, if that is far too much work, I'm open to options A and nerfing the item a bit.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
plus side is I learn people can still read an encrypted file, but how?

You should not make such rash assumptions...
What makes you believe I fall in the group "people"?
As far as my dictionary goes, "people" only contains human beings.

EDIT:
This will do for now.
I will try to make the code a bit more pretty but in the meantime, you should just use this for now.

It requires a unit indexer.
You have 3 global variables.
1, The event.
2, The unit that has its mana changed.
3, The amount of mana that has been changed.

To use the event, just create a trigger and make the event "Game - ManaDetection_Event becomes equal to <x>"
If <x> is 1, it will run when a unit has gained mana.
If <x> is -1, it will run when a unit has lost mana.
(Be aware that this will run for all units that you added to it so you want to have a check if the unit has your item before you want to store the value and stuff.)

To add the event to a unit, you use "Custom script: call AddManaDetectionEvent(<unit>)"
And to remove the event from a unit, you use "Custom script: call RemoveManaDetectionEvent(<unit>)"
Where <unit> is the unit that has to be checked.
You have to do this when your unit picks up an item, enters the map, dies, revives, loses an item, etc.
For your spell, (Acquires an item :: Add) (Loses an item OR Unit dies :: Remove)
There is one problem that you have to check if the unit has other items of that type before you remove him from the events.
Because if he has 2 items and loses 1, he should still have the event.

The values are not completely accurate, but I have to search through my systems to find the exact minimum change value for the trigger.
Then I can round it to the nearest integer to find the (probably) exact value.

But in any case, just try out the map!
 

Attachments

  • ManaDetection.w3x
    23.2 KB · Views: 101
Last edited:
Level 5
Joined
May 12, 2014
Messages
133
Just got out of school. I'll check out what sort of magic you have conjured and let you know how it goes.

EDIT: This is insanely broken (OP-wise I mean, not that it's unusable). I even tried to break it by giving mana potions a mana cost. Still takes the mana that it costed.
It takes it from triggers as well. Having a spell cost 50 + 15% of current mana will still be detected. That's pretty epic.

So this can use any unit indexer right? The only trigger I need to import is ManaDetectionEvent? I already have Bribe's inside of my map.

The only off thing is that the measurement can be off by up to 1 point, but who da heck cares about that? integers would just cut off the 0.25 that you should've gotten, and no ones gonna notice a missing 0.1 stack.
I'd give you rep, but I think those are for humans only. (in reality, I just can't give you anymore)
 
Last edited:
Level 24
Joined
Aug 1, 2013
Messages
4,657
Yea, you only have to copy and paste the ManaDetectionEvent trigger and if you would like that, the custom scripts that are used to call it.

Also, the mana cost of the potion is completely understandable...
Why would it not be?
You remove the mana first and then you add the mana from the potion...
They are two different actions that are done instead of one action and calculationg the actual mana loss/gain and use one update of the mana.
So that is also something you should take in mind with your triggers.
Dont do:
Set mana of unit to mana of unit - 50
Set mana of unit to mana of unit - 0.15*mana of unit
but instead do
Set manacost = 50
Set manacost = manacost + 0.15*mana of unit
Set mana of unit to mana of unit - manacost

Here is an updated version with integer accuracy of the taken/added mana.
(Ofcourse the same can be done for health... I am good!)
Just replace the current script with this:
JASS:
globals
    trigger array manaDetection_trigger
    real array manaDetection_lastMana
    hashtable manaDetection_hashtable = InitHashtable()
endglobals

library ManaDetection
    function ManaDetection_Callback takes nothing returns boolean
        local integer id = LoadInteger(manaDetection_hashtable, GetHandleId(GetTriggeringTrigger()), 0)
        local real mana
        
        set mana = GetUnitState(udg_UDexUnits[id], UNIT_STATE_MANA)
        set udg_ManaDetection_Unit = udg_UDexUnits[id]
        if mana > manaDetection_lastMana[id] then
            set udg_ManaDetection_Change = R2I(mana - manaDetection_lastMana[id] + 0.5)
            if udg_ManaDetection_Change > 2 then
                set udg_ManaDetection_Event = 0
                set udg_ManaDetection_Event = 1
            endif
        else
            set udg_ManaDetection_Change = R2I(manaDetection_lastMana[id] - mana + 0.5)
            if udg_ManaDetection_Change > 2 then
                set udg_ManaDetection_Event = 0
                set udg_ManaDetection_Event = -1
            endif
        endif
        
        set manaDetection_lastMana[id] = GetUnitState(udg_UDexUnits[id], UNIT_STATE_MANA)
        call DestroyTrigger(manaDetection_trigger[id])
        set manaDetection_trigger[id] = CreateTrigger()
        call TriggerRegisterUnitStateEvent(manaDetection_trigger[id], udg_UDexUnits[id], UNIT_STATE_MANA, LESS_THAN, manaDetection_lastMana[id] - 0.1)
        call TriggerRegisterUnitStateEvent(manaDetection_trigger[id], udg_UDexUnits[id], UNIT_STATE_MANA, GREATER_THAN, manaDetection_lastMana[id] + 0.1)
        call TriggerAddCondition(manaDetection_trigger[id], Filter(function ManaDetection_Callback))
        call SaveInteger(manaDetection_hashtable, GetHandleId(manaDetection_trigger[id]), 0, id)
        
        return false
    endfunction

    function AddManaDetectionEvent takes unit whichUnit returns boolean
        local integer id = GetUnitUserData(whichUnit)
        if id == 0 or manaDetection_trigger[id] != null then
            return false
        endif
        
        set manaDetection_lastMana[id] = GetUnitState(whichUnit, UNIT_STATE_MANA)
        set manaDetection_trigger[id] = CreateTrigger()
        call TriggerRegisterUnitStateEvent(manaDetection_trigger[id], whichUnit, UNIT_STATE_MANA, LESS_THAN, manaDetection_lastMana[id] - 0.1)
        call TriggerRegisterUnitStateEvent(manaDetection_trigger[id], whichUnit, UNIT_STATE_MANA, GREATER_THAN, manaDetection_lastMana[id] + 0.1)
        call TriggerAddCondition(manaDetection_trigger[id], Filter(function ManaDetection_Callback))
        call SaveInteger(manaDetection_hashtable, GetHandleId(manaDetection_trigger[id]), 0, id)
        
        return true
    endfunction
    function RemoveManaDetectionEvent takes unit whichUnit returns boolean
        local integer id = GetUnitUserData(whichUnit)
        local real mana
        if id == 0 or manaDetection_trigger[id] == null then
            return false
        endif
        
        call RemoveSavedInteger(manaDetection_hashtable, GetHandleId(manaDetection_trigger[id]), 0)
        call DestroyTrigger(manaDetection_trigger[id])
        set manaDetection_trigger[id] = null
        
        return true
    endfunction
endlibrary
 
Level 5
Joined
May 12, 2014
Messages
133
Well I didn't really know what you were doing with the system. If there was a delay, then the mana cost of a mana potion would have ruined it. As I am but a GUI user, I understand very little of JASS.

Speaking of which, have you considered turning this into a submitted system? This thing is awesome and I'm sure plenty of other people could use it.

Thanks again! <3
 
Status
Not open for further replies.
Top