• 🏆 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!

[vJASS] Airborne

Level 33
Joined
Apr 24, 2012
Messages
5,113
JASS:
library Airborne/*1.1
*************************************************************************************
*
*   Applies Airborne crowd control to units
*   
*   Comes up with a wrapper
*
*************************************************************************************
*
*   */ uses /*
*
*       */ UnitIndexerGUI /*hiveworkshop.com/forums/jass-resources-412/snippet-gui-unit-indexer-vjass-plugin-268592/
*
*************************************************************************************
*
*   API
*
*       static method is takes unit v returns boolean
*           - Checks whether or not a unit is airborne
*       static method add takes unit v, real duration, real height returns nothing
*           - Applies airborne effect to unit
*       static method remove takes unit v, boolean reset returns nothing
*           - Removes airborne effect from unit. If reset is true, instantly drops unit to it's original height
*       static method isSuspended takes unit v returns boolean
*           - Checks if airborne unit is suspended
*       static method suspend takes unit v, boolean state returns nothing
*           - Suspends unit, stopping chronological progress
*       static method registerOnAir takes code c returns nothing
*           - Registers a function on ON_AIR event. Fires whenever an airborne unit is on air.
*       static method registerOnLift takes code c returns nothing
*           - Registers a function on ON_LIFT event. Fires whenver a unit receives airborne effect.
*       static method registerOnDrop takes code c returns nothing
*           - Registers a function on ON_DROP event. Fires whenever an airborne unit's effect ends or removed.
*       static method getLiftedUnit takes nothing returns unit
*       static method getOnAirUnit takes nothing returns unit
*       static method getDroppedUnit takes nothing returns unit
*           - gets event unit (on their corresponding events)
*
*   Wrappers
*       function IsUnitAirborne takes unit u returns boolean
*       function UnitAddAirborne takes unit u, real duration, real height returns nothing
*       function UnitRemoveAirborne takes unit u, boolean reset returns nothing
*       function IsAirborneUnitSuspended takes unit u returns boolean
*       function SuspendAirborneUnit takes unit u, boolean flag returns nothing
*       function RegisterAirborneOnLiftEvent takes code c returns nothing
*       function RegisterAirborneOnAirEvent takes code c returns nothing
*       function RegisterAirborneOnDropEvent takes code c returns nothing
*
*************************************************************************************
*
*   Credits
*
*       Bribe
*       BlinkBoy
*
*************************************************************************************/
    globals
        private constant real TIMEOUT = 0.031250000
        /*
        *   Strictly disable movement
        *       - if true, prevents units from having their position changed, 
        *           regardless of any method (SetUnitX/Y, SetUnitPosition, etc.)
        */
        private constant boolean STRICT_DISABLE_MOVEMENT = true
        /*
        *   Disable Facing
        */
        private constant boolean DISABLE_FACING = true 
        /*
        *   Cancel Orders
        *       - if true, cancels orders on lift.
        */
        private constant boolean CANCEL_ORDERS = true 
        
        private constant real ON_DROP = 1.0
        private constant real ON_LIFT = 2.0
        private constant real ON_AIR = 3.0
    endglobals
    
    private function Bezier takes real a, real b, real c, real t returns real
        return a + 2.*(b-a)*t + (c -2.*b + a)*t*t
    endfunction

    private function GetBezierControlPoint takes real a, real b, real t returns real
        return 2*t - a/2 - b/2
    endfunction

    private function UnitCheck takes unit u returns boolean
        return u != null
    endfunction
    
    globals
        private trigger tod
        private trigger tol
        private trigger toa
        
        private real e
        
        private unit uod
        private unit uol
        private unit uoa
    endglobals
    
    private module Init
        private static method onInit takes nothing returns nothing
            call init()
        endmethod
    endmodule
    
    struct Airborne extends array
        private unit u
        
        private real dur
        private real max
        
        private real tz
        private real sz
        private real oz
        
        private real x
        private real y
        
        private real facing
        
        private boolean paused
        
        private boolean flag
        
        private static constant timer t = CreateTimer()
        private static thistype array n
        private static thistype array p
        
        static method is takes unit v returns boolean
            return thistype(GetUnitUserData(v)).flag
        endmethod
        
        private method Destroy takes boolean reset returns nothing
            if UnitCheck(u) and flag then
                set uod = u
                set e= ON_DROP
                set e = 0.
                
                call SetUnitPropWindow(u, GetUnitDefaultPropWindow(u)*bj_DEGTORAD)
                if reset then
                    call SetUnitFlyHeight(u, oz, 0.0)
                endif
                if STRICT_DISABLE_MOVEMENT then
                    set x = 0
                    set y = 0
                endif
                if DISABLE_FACING then
                    set facing = 0
                endif
                set flag = false
                set dur = 0
                set max = 0
                set oz = 0
                set tz = 0
                set sz = 0
                set paused = false
                
                set n[p[this]] = n[this]
                set p[n[this]] = p[this]
                
                if n[0] == 0 then
                    call PauseTimer(t)
                endif
            endif
        endmethod
        
        static method remove takes unit v, boolean reset returns nothing
            local thistype this
            if UnitCheck(v) then
                set this = thistype(GetUnitUserData(v))
                if flag then
                    call Destroy(reset)
                endif
            endif
        endmethod
        
        private static method period takes nothing returns nothing
            local thistype this = n[0]
            loop
                exitwhen this == 0
                if UnitCheck(u) and dur < max then
                    if not paused then
                        set dur = dur + TIMEOUT
                    endif
                    if STRICT_DISABLE_MOVEMENT then
                        call SetUnitX(u, x)
                        call SetUnitY(u, y)
                    endif
                    if DISABLE_FACING then
                        call SetUnitFacing(u, facing)
                    endif
                    set uoa = u
                    set e = ON_AIR
                    set e = 0.0
                    
                    call SetUnitFlyHeight(u, Bezier(sz, tz, oz, dur/max), 0)
                else
                    call Destroy(true)
                endif
                set this = n[this]
            endloop
        endmethod
        
        static method add takes unit v, real duration, real height returns nothing
            local thistype this
            if UnitCheck(v) then
                set this = thistype(GetUnitUserData(v))
                set uol = v
                set e = ON_LIFT
                set e = 0.0
                if not flag then
                    set flag = true 
                    call SetUnitPropWindow(u, 0)
                    set n[this] = 0
                    set p[this] = p[0]
                    set n[p[0]] = this
                    set p[0] = this
                    set oz = GetUnitFlyHeight(v)
                    if STRICT_DISABLE_MOVEMENT then
                        set x = GetUnitX(v)
                        set y = GetUnitY(v)
                    endif
                    if DISABLE_FACING then
                        set facing = GetUnitFacing(v)
                    endif
                    if CANCEL_ORDERS then
                        call IssueImmediateOrderById(u, 851972) 
                    endif
                    if UnitAddAbility(v, 'Amrf') and UnitRemoveAbility(v, 'Amrf') then
                    endif
                    if p[this] == 0 then
                        call TimerStart(t, TIMEOUT, true, function thistype.period)
                    endif
                    set paused = false
                    set u = v
                endif
                set dur = 0
                set max = duration
                set sz = GetUnitFlyHeight(v)
                set tz = GetBezierControlPoint(sz, oz, sz + height)
            endif
        endmethod
        
        static method isSuspended takes unit v returns boolean
            local thistype this
            if UnitCheck(v) then
                set this = thistype(GetUnitUserData(v))
                return paused and flag
            endif
            return false
        endmethod
        
        static method suspend takes unit v, boolean state returns nothing
            local thistype this
            if UnitCheck(v) then
                set this = thistype(GetUnitUserData(v))
                if flag then
                    set paused = state
                endif
            endif
        endmethod
        static method registerOnAir takes code c returns nothing
            call TriggerAddCondition(toa, Condition(c))
        endmethod
        static method registerOnLift takes code c returns nothing
            call TriggerAddCondition(tol, Condition(c))
        endmethod
        static method registerOnDrop takes code c returns nothing
            call TriggerAddCondition(tod, Condition(c))
        endmethod
        static method getLiftedUnit takes nothing returns unit
            return uol
        endmethod
        static method getOnAirUnit takes nothing returns unit
            return uoa
        endmethod
        static method getDroppedUnit takes nothing returns unit
            return uod
        endmethod
        private static method init takes nothing returns nothing
            set tod = CreateTrigger()
            set toa = CreateTrigger()
            set tol = CreateTrigger()
            call TriggerRegisterVariableEvent(tol, SCOPE_PRIVATE+"e", EQUAL, ON_LIFT)
            call TriggerRegisterVariableEvent(toa, SCOPE_PRIVATE+"e", EQUAL, ON_AIR)
            call TriggerRegisterVariableEvent(tod, SCOPE_PRIVATE+"e", EQUAL, ON_DROP)
        endmethod
        
        implement Init
    endstruct
    
    function IsUnitAirborne takes unit u returns boolean
        return Airborne.is(u)
    endfunction
    
    function UnitAddAirborne takes unit u, real duration, real height returns nothing
        call Airborne.add(u, duration, height)
    endfunction
    
    function UnitRemoveAirborne takes unit u, boolean reset returns nothing
        call Airborne.remove(u, reset)
    endfunction
    
    function IsAirborneUnitSuspended takes unit u returns boolean
        return Airborne.isSuspended(u)
    endfunction
    
    function SuspendAirborneUnit takes unit u, boolean flag returns nothing
        call Airborne.suspend(u, flag)
    endfunction
    
    function RegisterAirborneOnLiftEvent takes code c returns nothing
        call Airborne.registerOnLift(c)
    endfunction
    
    function RegisterAirborneOnAirEvent takes code c returns nothing
        call Airborne.registerOnAir(c)
    endfunction
    
    function RegisterAirborneOnDropEvent takes code c returns nothing
        call Airborne.registerOnDrop(c)
    endfunction
    
    function GetAirborneEventLiftedUnit takes nothing returns unit
        return Airborne.getLiftedUnit()
    endfunction
    function GetAirborneEventOnAirUnit takes nothing returns unit
        return Airborne.getOnAirUnit()
    endfunction
    function GetAirborneEventDroppedUnit takes nothing returns unit
        return Airborne.getDroppedUnit()
    endfunction
endlibrary
Example:
JASS:
struct test extends array
    private static method onCast takes nothing returns nothing
        local unit u = GetTriggerUnit()
        if IsUnitAirborne(u) then
            if IsAirborneUnitSuspended(u) then
                call SuspendAirborneUnit(u, false)
            else
                call SuspendAirborneUnit(u, true)
            endif
        else
            call UnitAddAirborne(u, 1.5, 500)
        endif
    endmethod
    
    private static method onLift takes nothing returns boolean
        call BJDebugMsg("A unit is lifted")
        return false
    endmethod
    private static method onAir takes nothing returns boolean
        call BJDebugMsg("A unit is on air")
        return false
    endmethod
    private static method onDrop takes nothing returns boolean
        call BJDebugMsg("A unit is dropped")
        return false
    endmethod
    
    private static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddAction(t, function thistype.onCast)
        
        call RegisterAirborneOnLiftEvent(function thistype.onLift)
        call RegisterAirborneOnAirEvent(function thistype.onAir)
        call RegisterAirborneOnDropEvent(function thistype.onDrop)
    endmethod
endstruct

Changelogs:
v1.1
- Added documentation on configurables
- Fixed event variable not working
- Uses single event variable now instead of 3
- Added getters for the event units.
- New demo code :)
 

Attachments

  • Airborne.w3x
    26.1 KB · Views: 77
Last edited:
Level 33
Joined
Apr 24, 2012
Messages
5,113
Is there a difference, besides encapsulation, between this and the
Airbone system you submitted two weeks before in the spell section?

The only reason I made this as a seperate resource is that most people tend to view vJASS systems in this section. Also a minor reason is that some might not know that my Airborne resource in Spell Section won't have a vJASS version.

I can add this to the resource if that's what everyone(majority) wants
 
Shouldn't the unit check actually check if the unit is alive? Or actually from usage I'm unsure what it's actual purpose is.

May I ask what for you credit BlinkBoy?

I'm not a fan of private constant boolean STRICT_DISABLE_MOVEMENT as it's not compatible with any other systems.
I'm not sure it should be an option.
Besides it I think you can screw all these extra sugar statements you do internaly for the user. so:
- move x/y
- cancel order
- set unit facing
...
The code provides events which user can use, and if he also can access to originalX/Y original facing, and the unit in the events, then he can do everything he really needs on his own.

It is a bad habit to use undescriptive names if they are not very clear inside a function scope like "local unit u."

method Destroy
->
method destroy

In destroy function the unit gets back the DefaultPropWindow, but it could get back the actual PropWindow it had onRegistration.

It makes no sense to call UnitCheck function on destroy because the destroy will also be called when UnitCheck returns false onPeriod.

Shouldn't the height change stop if the instance is paused?

It could optionaly use AutoFly.
 
Top