Snippet MakeUnitSway

Vestras

Retired
Reaction score
248
Yeah, I solved it.
This is a pretty simple function(s), making the unit sway. The swaying isn't very smooth, I hope you don't mind.

JASS:
library MakeUnitSway

private keyword Data

globals
    private constant integer ENABLE_FLY='Amrf'
    // The Raven Form ability which enables flying
    private constant real INTERVAL=0.03
    // The timer interval. 0.03 is suggested, less can cause lag
    private constant real DIVIDE=100
    // d.z is divided with this
    private constant real RATE=5000
    // The "time" the unit is about getting from and to the ground/fly height
// Necessary globals
private Data array D
private integer N=0
private timer T=CreateTimer()
endglobals

//! WARNING WARNING WARNING WARNING WARNING WARNING WARNING
//! Real Snippet Code! 
//! Don't touch if you don't know what you are doing!
//! WARNING WARNING WARNING WARNING WARNING WARNING WARNING

private struct Data
    unit swayer
    real z
    real max
    real min
    real height
    boolean hasReachedMax
endstruct

private function Callback takes nothing returns nothing
    local Data d
    local integer i=N
    loop
        exitwhen i<=0
        set d=D<i>
            if (d.z&lt;d.min) then
                set d.z=(d.z+(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
                set d.hasReachedMax=false
            elseif (d.z&gt;d.max) then
                set d.z=(d.z-(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
                set d.hasReachedMax=true
            elseif (d.z&gt;d.min and d.hasReachedMax==false) then
                set d.z=(d.z+(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
            elseif (d.z&gt;d.min) and (d.hasReachedMax==true) then
                set d.z=(d.z-(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
            endif
        set i=i-1
    endloop
endfunction

function MakeUnitSway takes unit whichUnit, real max, real min returns nothing
    local Data d=Data.create()
    set d.swayer=whichUnit
    set d.height=GetUnitFlyHeight(whichUnit)
    call UnitAddAbility(whichUnit,ENABLE_FLY)
    call SetUnitFlyHeight(whichUnit,min,RATE)
    set d.z=min-1
    call UnitRemoveAbility(whichUnit,ENABLE_FLY)
    set d.max=max
    set d.min=min
    set d.hasReachedMax=false
    set N=N+1
    set D[N]=d
    if N==1 then
        call TimerStart(T,INTERVAL,true,function Callback)
    endif
endfunction

function StopUnitSway takes unit whichUnit returns nothing
    local Data d
    local integer i=N
    loop
        exitwhen i&lt;=0
        set d=D<i>
        if d.swayer==null then
            call BJDebugMsg(&quot;|cffff0000MakeUnitSway|r: invalid unit.&quot;)
            return
        endif
        set D<i>=D[N]
        set N=N-1
        if N==0 then
            call PauseTimer(T)
        endif
        call SetUnitFlyHeight(d.swayer,d.height,RATE)
        call d.destroy()
        set i=i-1
    endloop
endfunction

private function TimedCallback takes nothing returns nothing
    local Data d
    local integer i=N
    loop
        exitwhen i&lt;=0
        set d=D<i>
        call StopUnitSway(d.swayer)
        set D<i>=D[N]
        set N=N-1
        set i=i-1
    endloop
    call DestroyTimer(GetExpiredTimer())
endfunction

function MakeUnitSwayTimed takes unit whichUnit, real max, real min, real duration returns nothing
    local Data d=Data.create()
    set d.swayer=whichUnit
    set N=N+1
    set D[N]=d
        call MakeUnitSway(whichUnit,max,min)
        call TimerStart(CreateTimer(),duration,false,function TimedCallback)
endfunction

endlibrary</i></i></i></i></i>
 

saw792

Is known to say things. That is all.
Reaction score
280
Wouldn't mind seeing some screenies of this before I try it out myself.
 

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
Haven't tried it nor will do anytime soon, mostly because I'm lazy. A few things I
noticed by quickly going through the code:

1) Try to make it not require any specific attachment systems.

2) Make so that it uses a global timer instead of one for each instance.

3)

JASS:
    private constant real TIME=5000


How about making that into seconds instead? And what if someone would want a different one for different spells or anything?
 

Vestras

Retired
Reaction score
248
@ Saw:

Hmm, there isn't really anything to get screenies of.

@ Larcenist

1) How? Should I make it into a struct?
2) That would make it non-MUI.
3) Actually, it isn't time, it's the rate of the SetUnitFlyHeight(...) function.
 

saw792

Is known to say things. That is all.
Reaction score
280
2) Global timers allow spells to be MUI if used correctly. I'll let somebody else explain it since I'm not that great at it.

Anyway, I think I misunderstood what this is supposed to do. Define 'swaying'.
 

Vestras

Retired
Reaction score
248
Hmm... I mean that it goes from one point in the air to another, like increase height, decrease, increase, decrease and so on...
 

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
2) Global timers allow spells to be MUI if used correctly. I'll let somebody else explain it since I'm not that great at it.

Anyway, I think I misunderstood what this is supposed to do. Define 'swaying'.

JASS:
private keyword Data

globals
    private timer T = CreateTimer()
    private integer N = 0
    private Data array D
endglobals

...
...

private function StopUnitSway takes ...
    local integer i = N
    local Data d
    ...
    ...
    loop
        exitwhen i &lt;= 0
            set d = Data<i>
            //Do stuff
            if (Whatever you use to destroy) == true then
                call SetUnitFlyHeight(d.swayer,d.height,TIME)
                call d.destroy()
                set D<i> = D[N]
                set N = N - 1
                if N == 0 then
                    call PauseTimer(T)
                endif
            endif
        set i = i - 1
    endloop
endfunction

function MakeUnitSway takes ...
    local Data d = ...
    ....
    set N = N + 1
    if N == 1 then
        call TimerStart(T, ...)
        set D[N] = d
    endif
endfunction</i></i>


You get the idea. Might be errors since it rapidly freehanded.

3) Actually, it isn't time, it's the rate of the SetUnitFlyHeight(...) function.

I'm not stupid... What I said is that you should make it so that the user can declare this in seconds, rather than rate.
 

Vestras

Retired
Reaction score
248
Okay... I thought I got it, but no...
It doesn't get the data, it doesn't do anything.

JASS:
library MakeUnitSway

private keyword Data

globals
    private constant integer ENABLE_FLY=&#039;Amrf&#039;
    // The Raven Form ability which enables flying
    private constant real INTERVAL=0.03
    // The timer interval. 0.03 is suggested, less can cause lag
    private constant real DIVIDE=100
    // d.z is divided with this
    private constant real TIME=5000
    // The &quot;time&quot; the unit is about getting from and to the ground/fly height
// Necessary globals
private Data array D
private integer N
private timer T=CreateTimer()
endglobals

//! WARNING WARNING WARNING WARNING WARNING WARNING WARNING
//! Real Snippet Code! 
//! Don&#039;t touch if you don&#039;t know what you are doing!
//! WARNING WARNING WARNING WARNING WARNING WARNING WARNING

private struct Data
    unit swayer
    real z
    real max
    real min
    real height
    boolean hasReachedMax
endstruct

private function Callback takes nothing returns nothing
    local Data d
    local integer i=N
    loop
        exitwhen i&lt;=0
        set d=D<i>
        call UnitAddAbility(d.swayer,ENABLE_FLY)
            if (d.z&lt;d.min) then
                set d.z=(d.z+(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
                set d.hasReachedMax=false
            elseif (d.z&gt;d.max) then
                set d.z=(d.z-(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
                set d.hasReachedMax=true
            elseif (d.z&gt;d.min and d.hasReachedMax==false) then
                set d.z=(d.z+(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
            elseif (d.z&gt;d.min) and (d.hasReachedMax==true) then
                set d.z=(d.z-(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
            endif
        set D<i>=D[N]
        set N=N-1
        call UnitRemoveAbility(d.swayer,ENABLE_FLY)
        set i=i-1
    endloop
endfunction

function MakeUnitSway takes unit whichUnit, real max, real min returns nothing
    local Data d=Data.create()
    set d.swayer=whichUnit
    set d.height=GetUnitFlyHeight(whichUnit)
    call UnitAddAbility(whichUnit,ENABLE_FLY)
    call SetUnitFlyHeight(whichUnit,min,TIME)
    set d.z=min-1
    call UnitRemoveAbility(whichUnit,ENABLE_FLY)
    set d.max=max
    set d.min=min
    set d.hasReachedMax=false
    set N=N+1
    if N==1 then
        set D[N]=d
        call TimerStart(T,INTERVAL,true,function Callback)
    endif
endfunction

function StopUnitSway takes unit whichUnit returns nothing
    local Data d
    local integer i=N
    loop
        exitwhen i&lt;=0
        set d=D<i>
        if d.swayer==null then
            call BJDebugMsg(&quot;|cffff0000MakeUnitSway|r: invalid unit.&quot;)
            return
        endif
        set D<i>=D[N]
        set N=N-1
        if N==0 then
            call PauseTimer(T)
        endif
        call SetUnitFlyHeight(d.swayer,d.height,TIME)
        call d.destroy()
        set i=i-1
    endloop
endfunction

private function TimedCallback takes nothing returns nothing
    local Data d
    local integer i=N
    loop
        exitwhen i&lt;=0
        set d=D<i>
        call StopUnitSway(d.swayer)
        set D<i>=D[N]
        set N=N-1
        set i=i-1
    endloop
    call DestroyTimer(GetExpiredTimer())
endfunction

function MakeUnitSwayTimed takes unit whichUnit, real max, real min, real duration returns nothing
    local Data d=Data.create()
    set d.swayer=whichUnit
    set N=N+1
    set D[N]=d
        call MakeUnitSway(whichUnit,max,min)
        call TimerStart(CreateTimer(),duration,false,function TimedCallback)
endfunction

endlibrary</i></i></i></i></i></i>
 

Flare

Stops copies me!
Reaction score
662
JASS:
    if N==1 then
        set D[N]=d

Set D[N] outside of the if (otherwise the data will only be set when an instance occurs when no other instance is running) - shame on Larcenist for having made that mistake :p

And you haven't initialized N (sadly you can't increment an uninitialized variable)

JASS:
private function Callback takes nothing returns nothing
    local Data d
    local integer i=N
    loop
        exitwhen i&lt;=0
        set d=D<i>
        call UnitAddAbility(d.swayer,ENABLE_FLY)
            if (d.z&lt;d.min) then
                set d.z=(d.z+(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
                set d.hasReachedMax=false
            elseif (d.z&gt;d.max) then
                set d.z=(d.z-(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
                set d.hasReachedMax=true
            elseif (d.z&gt;d.min and d.hasReachedMax==false) then
                set d.z=(d.z+(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
            elseif (d.z&gt;d.min) and (d.hasReachedMax==true) then
                set d.z=(d.z-(d.z/DIVIDE))
                call SetUnitFlyHeight(d.swayer,d.z,0)
            endif
        set D<i>=D[N]
        set N=N-1
        call UnitRemoveAbility(d.swayer,ENABLE_FLY)
        set i=i-1
    endloop
endfunction</i></i>

Read through the callback function from Larcenist's code - you're not supposed to decrease N, unless you are removing an instance (whereas you're decreasing it as if it were a loop counter)

[del]And, when you decrease N by 1, i should be increased by 1 (otherwise you are skipping the top-most instance which was moved down to the empty slot for that timer execution)[/del]
Oops, forgot that you were counted down (the single decrease to i is only needed when counting up)

JASS:
function StopUnitSway takes unit whichUnit returns nothing
    local Data d
    local integer i=N
    loop
        exitwhen i&lt;=0
        set d=D<i>
        if d.swayer==null then
            call BJDebugMsg(&quot;|cffff0000MakeUnitSway|r: invalid unit.&quot;)
            return
        endif
        set D<i>=D[N]
        set N=N-1
        if N==0 then
            call PauseTimer(T)
        endif
        call SetUnitFlyHeight(d.swayer,d.height,TIME)
        call d.destroy()
        set i=i-1
    endloop</i></i>

Do you even realise what you're doing there? It's far from what's intended, just by looking at it :rolleyes:

And there's no real need for 'Amrf' to be a constant, since every map should have that (if it doesn't...), and there wouldn't be any need for people to choose Amrf over Arav (since they're both gonna do the same thing)
 

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
And, when you decrease N by 1, i should be increased by 1 (otherwise you are skipping the top-most instance which was moved down to the empty slot for that timer execution)

Lies, not when running i backwards.

@Vestras: Check through my code (except my noob-mistake with the D[N] declaring ^^), you didn't even do half of what I really did.
 

Flare

Stops copies me!
Reaction score
662
Lies, not when running i backwards.

@Vestras: Check through my code (except my noob-mistake with the D[N] declaring ^^), you didn't even do half of what I really did.
Ye, I [noparse][del][/del][/noparse]'ed it there :p

JASS:
    if d.swayer==null then
        call BJDebugMsg(&quot;|cffff0000MakeUnitSway|r: invalid unit.&quot;)
// !!!
        return
    endif

From what I know, an empty return (not sure what exactly to call it) can cause desyncs on a Mac - make the function return an integer or something, and return 0 at all times, which would solve that problem
 

Joker(Div)

Always Here..
Reaction score
86
From what I know, an empty return (not sure what exactly to call it) can cause desyncs on a Mac - make the function return an integer or something, and return 0 at all times, which would solve that problem
Where you hear this?
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Flare said:
From what I know, an empty return (not sure what exactly to call it) can cause desyncs on a Mac - make the function return an integer or something, and return 0 at all times, which would solve that problem

Considering Skip Remaining Actions does exactly this, I really doubt this.

Isn't this what your function is doing, Vestras?

systemkj6.jpg


You do realize this can be done by using the SetUnitFlyHeight using the Min/Max values, and a given time, right?

This system isn't much use without making the edges more rounded. It is already set up to do so, just needs a little bit of math.
 

Darius34

New Member
Reaction score
30
It's not an empty return that causes desyncs - it's a non-existent one.

JASS:
function foo takes nothing returns boolean
    call BJDebugMsg(&quot;Blah&quot;)
endfunction

Something like this.

You do realize this can be done by using the SetUnitFlyHeight using the Min/Max values, and a given time, right?
QFT.

The arguments: switch min and max? Somehow seems more intuitive that way.
 

AceHart

Your Friendly Neighborhood Admin
Reaction score
1,495
> Where you hear this?

Returning nothing in a condition function can do bad things. A Mac exclusive.


Anyone care to explain what "swaying units" actually is?
 

quraji

zap
Reaction score
144
If Darthfett's diagram represents your snippet, I think this is a better alternative:

JASS:
library unitbob

globals
    constant integer FlyID = &#039;Amrf&#039;
    private gamecache gc = InitGameCache(&quot;unitbob&quot;)
endglobals

private function H2I takes handle h returns integer
    return h
    return 0
endfunction

struct unitbob
    unit u
    real offset
    real rate
    real origz
    timer t
    
    static method callback takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local unitbob ub = unitbob(GetStoredInteger(gc, I2S(H2I(t)), &quot;ub&quot;))
        
        call SetUnitFlyHeight(ub.u, GetUnitFlyHeight(ub.u) + ub.offset, ub.rate)
        set ub.offset = -ub.offset
    endmethod

    static method create takes unit u returns unitbob
        local unitbob ub = unitbob.allocate()
        
        set ub.u = u
        set ub.origz = GetUnitFlyHeight(u)
        set ub.t = CreateTimer()
        call UnitAddAbility(u, FlyID)
        call UnitRemoveAbility(u, FlyID)
      
        return ub
    endmethod
    
    method stop takes nothing returns nothing
        call PauseTimer(.t)
        call SetUnitFlyHeight(.u, .origz, 0.)
    endmethod
    
    method start takes real offset, real rate returns nothing
        set .offset = offset
        set .rate = rate
        
        call StoreInteger(gc, I2S(H2I(.t)), &quot;ub&quot;, this)
        call PauseTimer(.t)
        call TimerStart(.t, .offset/.rate, true, function unitbob.callback) 
        call SetUnitFlyHeight(.u, GetUnitFlyHeight(.u) + .offset, .rate)
        set .offset = -.offset 
    endmethod 
endstruct

endlibrary


I just wrote it here then made sure it compiled and bobbed the unit, I didn't test it much. Just bobs the unit up and down without "sliding" it (periodically changing FlyHeight - it lets the native do that), and requires no attachment system. The struct can easily be made a member of a data struct for PUI or whatever.

If you like this alternative better, feel free to take it and add/change what you like. I just thought it was a shame to make this more complicated than it is, seeing as Blizz has a native for it ;)
 

Flare

Stops copies me!
Reaction score
662
Where you hear this?

Considering Skip Remaining Actions does exactly this, I really doubt this.
Can't remember where exactly I saw it, but I definitely remember seeing someone saying it (I think it was emjlr3, not 100% sure though)

It's not an empty return that causes desyncs - it's a non-existent one.

JASS:
function foo takes nothing returns boolean
    call BJDebugMsg(&quot;Blah&quot;)
endfunction
That'd give you a syntax error :p - syntax checker does point out the lack of a return IIRC (unless I'm dreaming about random errors >_<)
 

Vestras

Retired
Reaction score
248
Updated.
The reason why I used a timer, and not Blizz' native, was that I actually wanted a bit of help making it smoother, and I knew that Blizz' native couldn't do that... So, anybody got an alternative?

The snippet doesn't use any systems!
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top