• 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] AddTimedEffect(model, x, y, duration)

Level 7
Joined
Oct 21, 2008
Messages
234
AddTimedEffect (string model, real x, real y, real time)
by Zacharias

Include this code in your map and you will gain access to AddTimedEffect. This function gives you the ability to create an effect on a specific point in the map, lasting for a specific duration.

Use this function to start the effect, everything else, including cleaning up, will be done automatically:


name
AddTimedEffect

return type
void

parameter

type
namecomment

string
modelthe effect model you want to use(similar to AddSpecialeffect)

real
xx-coordinate of target point

real
yy-coordinate of target point

real
timeduration

Have fun and give credits ;)

JASS:
globals
    effect array effectarray
    real array effectarrayTime
    integer effectarrayCount = 0
    timer effectarrayTimer = CreateTimer()
endglobals

function exeTimedEffect takes nothing returns nothing
    local integer i = 0
    local integer counted = 0
    //call Print(I2S(effectarrayCount)+" effects in timer")
    if effectarrayCount == 0 then
        call PauseTimer(effectarrayTimer)
        //call Print("stop timer")
    else
        loop
            exitwhen counted>=effectarrayCount
            if effectarray[i] != null then
                set effectarrayTime[i] = effectarrayTime[i]-0.1
                //call Print("time[" + I2S(i) + "]=" + R2S(effectarrayTime[i]))
                if(effectarrayTime[i] <= 0) then
                    call DestroyEffect(effectarray[i])
                    set effectarrayCount=effectarrayCount-1
                    set effectarrayTime[i] = 0
                    set effectarray[i] = null
                    //call Print("destroy "+I2S(i))
                else
                    set counted=counted+1
                endif
            endif
            set i=i+1
        endloop
    endif
endfunction

function AddTimedEffect takes string model, real x, real y, real time returns nothing
    local integer i = 0
    // find free slot
    loop
        exitwhen effectarray[i] == null
        set i=i+1
    endloop
    // add a effect
    //call Print("add effect in slot "+I2S(i))
    set effectarrayCount = effectarrayCount+1
    set effectarray[i] = AddSpecialEffect(model,x,y)
    set effectarrayTime[i] = time
    if effectarrayCount == 1 then
        call TimerStart(effectarrayTimer, 0.1, true, function exeTimedEffect)
        //call Print("start timer")
    endif
endfunction

Note: I didn´t delete the print("") comments, add this simple function to your code and delete the // to ease debug work:

JASS:
function Print takes string str returns nothing
    call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, str)
endfunction
 
Last edited:
Level 14
Joined
Nov 18, 2007
Messages
816
Since nearly every aspect i mentioned when i commented on your StunUnit function applies to this as well, im going to quote myself (deleted unfitting comments).
First of all: I think you should delete this, since theres already a much cleaner version submitted. [...]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[...]
 
For your testing purposes use BJDebugMsg("text"), it's more convenient than writing your own new "print" function.

Also, clean this up with structs is what i would do.
Assuming your using JNGP (because of your declared globals)

The start boolean is also useless...

JASS:
    if effectarrayCount == 0 then
        call TimerStart(effectarrayTimer, 0.1, true, function exeTimedEffect)
    endif

Is more efficient.
 
Level 7
Joined
Oct 21, 2008
Messages
234
Thx for your constrictive critism.

For your testing purposes use BJDebugMsg("text"), it's more convenient than writing your own new "print" function.
Ok, lets learn something (me), why is it better?

Also, clean this up with structs is what i would do.
Assuming your using JNGP (because of your declared globals)
Structs are not compressed in memory, so what do you think of its advantage? It just makes your code easier to read.

The start boolean is also useless...
JASS:
    if effectarrayCount == 0 then
        call TimerStart(effectarrayTimer, 0.1, true, function exeTimedEffect)
    endif
Is more efficient.
Yes, but it doesn´t work. Just look at the few code lines above. effectarrayCount == 1 should work i think. Thx.
 
Level 9
Joined
Mar 25, 2005
Messages
252
Your AddTimedEffect is currently O(n), but could easily be O(1).
Here's how I would refractor your script (untested):
JASS:
library AddTimedEffect

    globals
        private effect array effectarray
        private real array effectarrayTime
        private integer effectarrayCount = 0
        private timer effectarrayTimer = CreateTimer()
        private constant real TIMEOUT = 0.1
    endglobals
    
    private function exeTimedEffect takes nothing returns nothing
        local integer i = effectarrayCount
        //call Print(I2S(effectarrayCount)+" effects in timer")
        loop
            exitwhen i == 0
            set i = i - 1
            set effectarrayTime[i] = effectarrayTime[i] - TIMEOUT
            if (effectarrayTime[i] <= 0) then
                //call Print("destroy "+I2S(i))
                call DestroyEffect(effectarray[i])
                set effectarrayCount = effectarrayCount - 1
                set effectarray[i] = effectarray[effectarrayCount]
                set effectarrayTime[i] = effectarrayTime[effectarrayCount]
            endif
        endloop
        if effectarrayCount == 0 then
            //call Print("stop timer")
            call PauseTimer(effectarrayTimer)
        endif
    endfunction
    
    function AddTimedEffect takes string model, real x, real y, real time returns nothing
        local integer i = effectarrayCount
        set effectarrayCount = effectarrayCount + 1
        //call Print("add effect in slot "+I2S(i))
        set effectarray[i] = AddSpecialEffect(model,x,y)
        set effectarrayTime[i] = time
        if effectarrayCount == 1 then
            call TimerStart(effectarrayTimer, TIMEOUT, true, function exeTimedEffect)
            //call Print("start timer")
        endif
    endfunction
    
endlibrary
 
Level 7
Joined
Oct 21, 2008
Messages
234
Your AddTimedEffect is currently O(n), but could easily be O(1).
Here's how I would refractor your script (untested):....

Thats also O(n), just counting top to bottom, but think of 100 effects added with the same duration. The first [0] will be the first one to be deleted. So bottom->top is more effective in most cases.

Ok this is a good one, destroys effects afterward. But no advantage found, mine isn´t better too for sure.

This system works quite well, but is complex, needs more memory (more arrays), but gives the possibility to cast effects on units.

Refer to my answer in your StunFunction thread for the rest.
Yeah, read them. Nothing special.

Please read my code, try to reconsider it and stop being a wiseacre. Sry for that but you´re just posting and posting without ANY argument ("its better" is not an arguement).
 
Level 9
Joined
Mar 25, 2005
Messages
252
Thats also O(n), just counting top to bottom, but think of 100 effects added with the same duration. The first [0] will be the first one to be deleted.
...

I was referring only to the function AddTimedEffect (my bad), which in my implementation is O(1). Anyways the periodic function of mine is more effective too, since there are no gaps in the arrays.
 
Level 7
Joined
Oct 21, 2008
Messages
234
Just easier to write, instead of making a new function.
Easier to read, write, manage.
So its all about easy reading and writing/managing. But we will loose performance (negligible).

I was referring only to the function AddTimedEffect (my bad), which in my implementation is O(1). Anyways the periodic function of mine is more effective too, since there are no gaps in the arrays.
Oh sry didn´t see that. Yes thats really a O(1). But on the other hand, my cleaning-function is a O(1), yours an O(n). So it doesn´t bring us any advantage right?
 
Level 14
Joined
Nov 18, 2007
Messages
816
Oh sry didn´t see that. Yes thats really a O(1). But on the other hand, my cleaning-function is a O(1), yours an O(n). So it doesn´t bring us any advantage right?

All your functions are O(n).

Did you notice you could convert those two functions to O(1) by using multiple timers (i think performance wise the best option), a heap (low on memory usage) or a linked list ?

Edit: Oh my god, not even a proper deallocation algorithm. You know, I STRONGLY suggest you look at other systems and see how they work, especially when it comes to allocating and deallocating data.
 
Level 7
Joined
Oct 21, 2008
Messages
234
All your functions are O(n).

Did you notice you could convert those two functions to O(1) by using multiple timers (i think performance wise the best option), a heap (low on memory usage) or a linked list ?

Edit: Oh my god, not even a proper deallocation algorithm. You know, I STRONGLY suggest you look at other systems and see how they work, especially when it comes to allocating and deallocating data.

No, cleaning is a O(1), as already said. Multiply timers against O(n), pls read my comment about CPU, strongly recommended for you.
Deallocating algorithm? Any leaks?.... Handles were all deleted safe (globals....).
 
Level 14
Joined
Nov 18, 2007
Messages
816
no. his deallocation algorithm is fully functional. He did not forget anything.
This requires no sorting of any type.
There are people here, who are far more experienced. Just listen carefully, and you might even learn something.
 
Last edited by a moderator:
Level 7
Joined
Oct 21, 2008
Messages
234
JASS:
call DestroyEffect(effectarray[i])
set effectarrayCount = effectarrayCount - 1
set effectarray[i] = effectarray[effectarrayCount]
set effectarrayTime[i] = effectarrayTime[effectarrayCount]
this part should "fill" the leak in the array, but does only shift one entry, but all entries above should be shifted, a loop in a loop -> O(n*(n-1))

Edit: stay cool
 
Level 8
Joined
Aug 6, 2008
Messages
451
The war of the words..


I think it would be easier if this just takes an effect and returns nothing.
That would make it easier for people to create effects only visible for certain players.

Something like SetEffectLifespan takes effect e returns nothing.

It would make it support AddSpecialEffectTarget too.

edit2.
set effectarrayTime = effectarrayTime[effectarrayCount]


This just moves the last Time to free position in array. ( Time was just destroyed, so there is a hole ) This way you dont get any empty spots in your array. Then you just decerease effectarrayCount by one, and you have a solid array with no holes. Only the order of members changes, but that really doesnt matter.

edit. use private variables pls. I hate when I have to type effectarrayTime instead of Time.

edit2. Oh yea, I forgot that you might need real duration for that SetEffectLifespan function :D
 
Last edited:
Top