• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[vJass] StunUnit(unit, duration, showeffect)

Level 7
Joined
Oct 21, 2008
Messages
234
StunUnit( unit u, real time, boolean show)
by Zacharias

Include this code in your map and you can stun any unit for a specific time (unit is paused). It´s also possible to display the stun effect (e.g. as in thunderclab) by the parameter show.

Use this function to start stun on an unit, everything else will be done automatically:


name
StunUnit

return type
void

parameter

type
namecomment

unit
utarget unit

real
timeduration

boolean
showshow stun effect

Have fun and give credits ;)

JASS:
globals
    integer stunCount=0
    unit array stunUnits
    real array stunTime
    effect array stunEffect
    timer stunTimer =  CreateTimer()
endglobals

function exeStunTimer takes nothing returns nothing
    local integer i = 0
    local integer count = 0
    loop
        exitwhen count>=stunCount
        if stunUnits[i]!=null then
            if stunTime[i]<=0 then
                // destroy effect
                if stunEffect[i] != null then
                    call DestroyEffect(stunEffect[i])
                    set stunEffect[i] = null
                endif
                //wake up
                call PauseUnit(stunUnits[i],false)
                set stunUnits[i]=null
                set stunCount=stunCount-1
            else
                set stunTime[i] = stunTime[i]-0.1
                set count=count+1
            endif
        endif
        set i=i+1
    endloop
    if stunCount== 0 then
        call PauseTimer(stunTimer)
    endif
endfunction

function StunUnit takes unit u, real time, boolean show returns nothing
    local integer i=0
    local boolean start = false
    //call Print("stun "+GetUnitName(u))
    
    loop
        exitwhen stunUnits[i]==null
        set i=i+1
    endloop
    call PauseUnit(u, true)
    set stunCount=stunCount+1
    set stunUnits[i] = u
    set stunTime[i] = time
    
    if show then
        set stunEffect[i] = AddSpecialEffectTarget("Abilities\\Spells\\Human\\Thunderclap\\ThunderclapTarget.mdl",u,"overhead")
    else
        set stunEffect[i] = null
    endif
    
    if stunCount==1 then
        call TimerStart(stunTimer,0.1,true, function exeStunTimer)
    endif
endfunction
 
Last edited:
Level 14
Joined
Nov 18, 2007
Messages
816
okay....
First of all: I think you should delete this, since theres already a much cleaner version submitted. And this is not a real stun, more a timed pause of a unit. And you use an inefficient approach (multiple timers would be better)

Some more things:
- please learn to scope your code (read more about libraries in the JassHelper Manual).
- Once you use libraries, make use of the private keyword.
- Please use TimerUtils, and dont destroy Timers. Your current usage of timers will result in a game crash.
- Make the effect and the attachmentpoint parameters of your exported function
 
Level 7
Joined
Oct 21, 2008
Messages
234
okay....
First of all: I think you should delete this, since theres already a much cleaner version submitted. And this is not a real stun, more a timed pause of a unit.
Ok please give a link to this "cleaner version", didn´t found it, sry.
And you use an inefficient approach (multiple timers would be better)
Multiple timers? Omg what a waste of performance.... there is also a limit of timers in wc3.

Some more things:
- please learn to scope your code (read more about libraries in the JassHelper Manual).
- Once you use libraries, make use of the private keyword.
Didn´t want to use libraries, since it is not necessary at all, doesn´t improve performance or any other advantage.The private keyword isn´t necessary too, since those 4 vars (+1 handle) wont flood the memory.
- Please use TimerUtils, and dont destroy Timers. Your current usage of timers will result in a game crash.
TimerUtils just destroys the timer "save". Means it checks if stack is full and if timer is held.
- Make the effect and the attachmentpoint parameters of your exported function
Don´t want to make an useable-in-all-situations-stun. Just posting a simple, usefull, effective and fast (performance!) function to stun.

This system works perfectly in my map, which is now online for more then a half year. No errors till now.
 
Level 8
Joined
Aug 6, 2008
Messages
451
Pause is pretty anoying sometimes because it disables some passive abilities etc.

Use some dummy with stormbolt, stun duration 0 ( lasts forever ) and then remove buff when time runs out.

One timer is the way to go. No need to use any attachment systems.
 
Level 8
Joined
Aug 6, 2008
Messages
451
I think Void once said that there is some way to make buff not to be visible. I dont really remember it anymore, though.
 
Level 14
Joined
Nov 18, 2007
Messages
816
Ok please give a link to this "cleaner version", didn´t found it, sry.[...]
http://www.hiveworkshop.com/forums/f414/simple-stun-system-95543/
Edit: Oh, well, im noticing a few flaws with this system. Wait a bit and ill recode it.
JASS:
library SimpleStunSystem uses TimerUtils
    globals
        private constant integer DUMMYUNITID = 'h000' // the rawcode of dummy unit
        private constant integer STUNABILID = 'A000' // the rawcode of simple stun ability
        private constant integer STUNBUFFID = 'B000' // the rawcode of simple stun buff
        
        // This is shit. Don't touch shit.
        
        public integer Total=0
        private timer array T
        private unit array U
    endglobals

    private function End takes nothing returns nothing
        local integer i=GetTimerData(GetExpiredTimer())
        call UnitRemoveAbility(U[i],STUNBUFFID) // unstun the unit.
        // some recycling
        set Total=Total-1
        set T[i]=T[Total]
        call SetTimerData(T[Total], i)
        set U[i]=U[Total]
        set T[Total]=null
        set U[Total]=null
        call ReleaseTimer(GetExpiredTimer())
    endfunction


    // ************************************************************************************************
    // * Main and only function available outside this library
    // *
    // * PARAMETERS:
    // * * unit u: the unit to stun
    // * * real d: the duration of the stun
    // * * boolean StunMagicImmune: checks whether Magic Immune units can be stunned
    // * * boolean StunMechanic: checks whether Mechanic units can be stunned
    // * * boolean stack: checks whether this stun can be stacked onto an existing one (by this system).
    // *
    // * EXAMPLE:
    // * * call StunUnit(u, 2, false, true, true)
    // * This stuns u for 2 seconds if there isnt already another stun caused by this system,
    // * else the stun will be stacked. Magic immune units can't be stunned, but mechanic units can.
    // *
    // ************************************************************************************************
    function StunUnit takes unit u,real d, boolean StunMagicImmue, boolean StunMechanic, boolean stack returns boolean
        local unit s
        local integer i = 0
        if (not StunMagicImmue or IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)==false) and (not StunMechanic or IsUnitType(u, UNIT_TYPE_MECHANICAL)==false) and d>0.05 and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false then // IsUnitType()==true/false due to a blizzard bug; not needed for UNIT_TYPE_HERO
            
            loop
                exitwhen U[i]==u or i>=Total
                set i=i+1
            endloop
            
            if i<Total then
                if stack then
                    call PauseTimer(T[i])
                    call TimerStart(T[i],d+TimerGetRemaining(T[i]),false,function End)
                    return true
                else
                    if d>TimerGetRemaining(T[i]) then
                        call PauseTimer(T[i])
                        call TimerStart(T[i],d,false,function End)
                        return true
                    endif
                    return false
                endif
            endif
            
            set T[Total]=NewTimer()
            set U[Total]=u
            
            set s = CreateUnit(GetOwningPlayer(u),DUMMYUNITID,GetUnitX(u),GetUnitY(u),0)
            call UnitAddAbility(s,STUNABILID)
            call UnitRemoveAbility(s, 'amov')
            call UnitApplyTimedLife(s, 'BTLF', 1.)
            call IssueInstantTargetOrderById(s,852095,u,u) // stun the unit.
            set s = null
            
            call SetTimerData(T[Total], Total)
            call TimerStart(T[Total],d,false,function End)
            set Total=Total+1
            return true
        endif
        return false
    endfunction
endlibrary

[...]Multiple timers? Omg what a waste of performance.... there is also a limit of timers in wc3.[...]
Afaik, theres no limit on the number of timers you can create (at least, ive never heard of anyone running into that limit). And thats actually not a waste. I suggest you use your brain.
On a side note: A heap would be even more efficient.

[...]Didn´t want to use libraries, since it is not necessary at all, doesn´t improve performance or any other advantage.The private keyword isn´t necessary too, since those 4 vars (+1 handle) wont flood the memory.[...]
flood the memory? Thats not the point of libraries. I use libraries for access management and unified naming. And i think restricting access to variables the user shouldnt change is a pretty big advantage.

[...]TimerUtils just destroys the timer "save". Means it checks if stack is full and if timer is held.[...]
TimerUtils doesnt destroy timers (well, it does but only if you screwed it up).

[...]Don´t want to make an useable-in-all-situations-stun. Just posting a simple, usefull, effective and fast (performance!) function to stun.[...]
Your stun is simple, though not useful or effective or fast.

I know this system works. But im saying you couldve done it better.

---

[...]One timer is the way to go. No need to use any attachment systems.
No. Use TimerUtils. And make good use of it (multiple timers).
 
Last edited:
Level 7
Joined
Oct 21, 2008
Messages
234
That pretty sucks as you can´t bring any argument for your position.

Afaik, theres no limit on the number of timers you can create (at least, ive never heard of anyone running into that limit).
There is a limit, see TimerUtils reference, or src code.
And thats actually not a waste. I suggest you use your brain.
On a side note: A heap would be even more efficient.
Use my brain? Ok wc3 processes timer-events not by parallel thread processing (multi-threading), it´s calculated serial. Therefor less timers- better performance. I suggest you to study how a computer works, esspecially the CPU.

flood the memory? Thats not the point of libraries. I use libraries for access management and unified naming. And i think restricting access to variables the user shouldnt change is a pretty big advantage.
Advantage? It would blow up the code by assignment-operators (structs) which werent necessary at all, since there are just 5 vars.

TimerUtils doesnt destroy timers (well, it does but only if you screwed it up).
Sry i wanted to say its just checking if the timer is paused or if stack (see first comment) is full. Timer is paused in my code, no need for rechecking that. Timer stack full - well that would crash the whole map, since the timer is GLOBAL. Please read manual.
Your stun is simple, though not useful or effective or fast.
Its simple, its effective and usefull for maybe other guys.

No. Use TimerUtils. And make good use of it (multiple timers).
Just like saying use visual studio for programming c++. Advantage? Oh i don´t know but use it! :eekani:

Please be so kindly and bring forward arguments, statements that have been proven.
 
Level 8
Joined
Aug 6, 2008
Messages
451
IMO you should use static timer loop and struct arrays. ( See Silvenons knockback system in this site. )

And use Table ( or some other gamecache thingie ) to find units Data in case it is allready stunned.
 
Level 7
Joined
Oct 21, 2008
Messages
234
IMO you should use static timer loop and struct arrays. ( See Silvenons knockback system in this site. )
As already sad structs wont bring ANY advantage in this case.
Static timer loops? Don´t know what you mean with that. Please describe what this should be and why it would be good.

And use Table ( or some other gamecache thingie ) to find units Data in case it is allready stunned.
Ok thats an idea.
 
Level 8
Joined
Aug 6, 2008
Messages
451
As already sad structs wont bring ANY advantage in this case.

That is true kind of. Arrays do the same thing, structs just make the code look cleaner and more happy.

Please describe what this should be and why it would be good.

When stun duration reaches 0, you need to remove your struct from an array. ( You just use many arrays instead of one struct array )

When stun x ends, you just move the last stun struct StunData[stunCount] to the place of StunData[x]. Then you just decerease stunCount by one.

This way your array wont have any empty spots between Datas.
 
Level 14
Joined
Nov 18, 2007
Messages
816
Today, 12:04 AM (The time i posted my first comment)

Last edited by Zacharias; Today at 01:15 PM.. Reason: title (The last time you edited your post)

You were destroying timers (and nulling them afterwards) when i posted my comment. If you insist, ill have to ask some admin for proof.

Where did you deduce that there is a limit on the number of timers you can create? Where?

Well, you should start counting the cpu cycles your system uses and then guess how many cpu cycles multiple timers use.

Libraries!=structs. Those two are completely different. I never said you should use structs.
 
Level 7
Joined
Oct 21, 2008
Messages
234
That is true kind of. Arrays do the same thing, structs just make the code look cleaner and more happy.
Well it´s just wonderfull easy now, right? Structs will always cause a little lack of performance, as all libraries.
When stun duration reaches 0, you need to remove your struct from an array. ( You just use many arrays instead of one struct array )
Since arrays are some kind of dynamic allocated in wc3 (otherwise we would have to set a limit), it doesen't matter.
When stun x ends, you just move the last stun struct StunData[stunCount] to the place of StunData[x]. Then you just decerease stunCount by one.
This way your array wont have any empty spots between Datas.
Ahhhh you mean a sorted array. Well the bottleneck is to sort those things. Since we never need 4000 stuns over 400 seconds, its faster to loop through several steps as to re-sort EVERYTIME a stun finishes.
 
Level 8
Joined
Aug 6, 2008
Messages
451
Well, I cant really say anyting about speed unless I find myself not so lazy to do some benchmarking. (You are probably right, though )

You could add functions for getting stun duration ( so people dont have to play with arrays ) and the last unit who stunned your unit.

Adding some effect every x seconds would be a cool feature too. People could loop some sick explosion effects and stuff like that.

edit. Check Anitarfs ABuff system for more ideas. I think he has some cool stun module for that system which handles all the stunning.

edit2. And put your code to library. Dont forget to make things private or public, or whatever you need.
 
Level 7
Joined
Oct 21, 2008
Messages
234
You could add functions for getting stun duration ( so people dont have to play with arrays ) and the last unit who stunned your unit.
Well i just want to let this be some kind of basic instrument. Anyone can take this code and prepare it for his own purpose, add functions etc
No one has to play with arrays, jsut use the StunUnit function ;)
Adding some effect every x seconds would be a cool feature too. People could loop some sick explosion effects and stuff like that.
Yeah that can be done, by self-coding. As i said, don´t want to publish a it-can-do-everything-stun-compilation-library as it is mostly not necessary.

edit. Check Anitarfs ABuff system for more ideas. I think he has some cool stun module for that system which handles all the stunning.
Ok.
edit2. And put your code to library. Dont forget to make things private or public, or whatever you need.
See above ^^
 
Level 8
Joined
Aug 6, 2008
Messages
451
Well i just want to let this be some kind of basic instrument. Anyone can take this code and prepare it for his own purpose, add functions etc

I tought this was meant for GUI users who dont know too much Jass.

Well, if you are planning to make this easy to prepare it for own purposes, you should definetly use structs, because it would make this easier to modify.

Struct attachment systems use structs, it is easier to store structs to gamecache than do it for normal variables and users might also want to extend stun struct or play with interfaces or something like that.
 
Level 7
Joined
Oct 21, 2008
Messages
234
I tought this was meant for GUI users who dont know too much Jass.
Well, if you are planning to make this easy to prepare it for own purposes, you should definetly use structs, because it would make this easier to modify.
Struct attachment systems use structs, it is easier to store structs to gamecache than do it for normal variables and users might also want to extend stun struct or play with interfaces or something like that.

Oh sry no, that is probably my failure. Its not intended for GUI users, just a code snippet. You see i´m always arguing with performance, since GUI does not improve performance i simply don´t support it :wink:
The gamecash 'issue' is a good point. I didn´t use gamecash at all, since i´m always using timers with minimal duration, where its much faster to access the variable directly then over addressing, since it is not native at all.
 
Level 14
Joined
Nov 18, 2007
Messages
816
Oh well, i just noticed you dont allocate or deallocate data the best way possible. Refer to the sample i linked to or the code i posted for a decent algorithm.

And once again: Use multiple timers (+attaching), its best performance wise (count the cpu cycles needed!).
 
Level 7
Joined
Oct 21, 2008
Messages
234
Oh well, i just noticed you dont allocate or deallocate data the best way possible. Refer to the sample i linked to or the code i posted for a decent algorithm.
Great you know my code well. Read-Think-Write.
And once again: Use multiple timers (+attaching), its best performance wise (count the cpu cycles needed!).
count the cycles needed?
Ok, when i use 200 timers, the cpu will check (the accuracy of wc3 is equal to frame-period) every 0.035s (~29frms) if one of the 200 timers ends (time of creation minus curTime). Thats quite more work than to check every 0.1 seconds (in my case) if one of 200 array-entries (remeber, array can be accessed much faster than handels e.g. timers) is null.
 
Level 14
Joined
Nov 18, 2007
Messages
816
remember you are softcoding this in Jass, and timers are hardcoded in C/C++. Now whats more efficient? Jass or C/C++?
And btw: youre recreating the code blizzard probably used themselves for timers. I see no point in doing that.
 
Level 7
Joined
Oct 21, 2008
Messages
234
remember you are softcoding this in Jass, and timers are hardcoded in C/C++. Now whats more efficient? Jass or C/C++?
And btw: youre recreating the code blizzard probably used themselves for timers. I see no point in doing that.
One point for you. But loops will be processed by the cpu no matter if they are directly coded or not.
Yes i´m probably recoding it, since it is necessary. Timer array vs timer-timers xD
 
Top