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

[System] Dummy Cast

Level 7
Joined
Apr 30, 2011
Messages
359
JASS:
//========================================================================================
//      
//      Dummy Cast
//      -*- overcold_ice -*-
//      
//     -[*] Requirements:
//          - JNGP
//          - latest version of JassHelper
//      
//          For your dummy-casting needs
//      Provides instant casting and normal casting functions.
//      
//     -[*] API:
//      
//      constant integer DUMMY_CAST_TARGET_NONE  = 0
//      constant integer DUMMY_CAST_TARGET_POINT = 1
//      constant integer DUMMY_CAST_TARGET_UNIT  = 2
//      
//      struct DummyCast extends array
//          
//          player  owner               // the owner of the dummy unit
//          real    x, y                // the position of the dummy unit
//          integer AbilId, AbilLv      // the ability that will be casted
//          string  order               // the ability's cast order
//          boolean instant             // true  => instant cast (no casting time)
//                                      // false => normal cast (casting time included)
//          
//          integer target              // the targeting type of the spell
//                                      // can be non-target, point-target, unit-target
//                                      // (use constants above, or just their values)
//          real    tX, tY              // location coordinates for point-target spell
//          unit    tU                  // target unit for unit-target spell
//          
//          static method allocate takes nothing returns DummyCast
//          method deallocate takes nothing returns nothing
//              creator/destructor of the struct
//          
//          method cast takes nothing returns boolean
//              cast the spell
//          
//          method castRect takes rect r returns boolean
//              cast the spell (on random locations in rect r). if the spell is unit
//              targeting, casts the spell on all units in the rect
//          method castRectUnit takes rect r, boolexpr f returns boolean
//              cast the spell (positioned/targeted) on every units in rect r that
//              pass filter f
//          
//          method castCircle takes real x, real y, real r returns boolean
//              cast the spell (on random locations in a circle with center [x, y] and
//              radius r). if the spell is unit targeting, casts the spell on all units
//              in the circle
//          method castCircleUnit takes real x, real y, real r, boolexpr f returns boolean
//              cast the spell (positioned/targeted) on every units in a circle with
//              center [x, y] and radius r that pass filter f
//          
//          they all returns true if at least 1 dummy caster casts the spell successfully
//      
//========================================================================================
library DummyCast
    
    globals
        //================================================================================
        //  C A L I B R A T I O N  S E C T I O N
        //================================================================================
        private constant player  DEFAULT_DUMMY_OWNER = Player(15)   // default owner
        private constant boolean DEFAULT_DUMMY_CAST  = false        // default for instant casting
                                                                    // true  => instant cast
                                                                    // false => normal cast
        
        private constant integer DUMMY_CASTER_ID     = 'dumy'
        //================================================================================
        
        constant integer DUMMY_CAST_TARGET_NONE  = 0
        constant integer DUMMY_CAST_TARGET_POINT = 1
        constant integer DUMMY_CAST_TARGET_UNIT  = 2
    endglobals
    
    private module InitDummyCast
        private static method onInit takes nothing returns nothing
            set .instantCaster = CreateUnit(DEFAULT_DUMMY_OWNER, DUMMY_CASTER_ID, 0, 0, 0)
            call TriggerAddCondition(.t, Condition(function thistype.onEndCast))
        endmethod
    endmodule
    
    struct DummyCast extends array
        player    owner
        real          x
        real          y
        integer  abilId
        integer  abilLv
        string    order
        boolean instant
        
        integer  target
        real         tX
        real         tY
        unit         tU
        
        private         thistype r
        private static   integer c = 0
        
        static method allocate takes nothing returns thistype
            local thistype this = thistype(0).r
            
            if this == 0 then
                set .c   = .c + 1
                set this = .c
            else
                set thistype(0).r = this.r
            endif
            
            return this
        endmethod
        
        method deallocate takes nothing returns nothing
            set        this.r = thistype(0).r
            set thistype(0).r = this
            
            set this.owner   = DEFAULT_DUMMY_OWNER
            set this.x       = 0
            set this.y       = 0
            set this.abilId  = 0
            set this.abilLv  = 1
            set this.order   = ""
            set this.instant = DEFAULT_DUMMY_CAST
            
            set this.tX = 0
            set this.tY = 0
            set this.tU = null
        endmethod
        
        private static unit     instantCaster
        
        private static group    g = CreateGroup()
        private static trigger  t = CreateTrigger()
        
        private static thistype array i [8190]
        
        private method getCaster takes nothing returns unit
            local unit u = FirstOfGroup(.g)
            
            if u == null then
                set u = CreateUnit(this.owner, DUMMY_CASTER_ID, this.x, this.y, 0)
                call TriggerRegisterUnitEvent(.t, u, EVENT_UNIT_SPELL_ENDCAST)
            else
                call GroupRemoveUnit(.g, u)
            endif
            
            return u
        endmethod
        
        private static method onEndCast takes nothing returns boolean
            local unit u = GetTriggerUnit()
            
            call GroupAddUnit(.g, u)
            call UnitRemoveAbility(u, .i [GetHandleId(u)].abilId)
            
            set u = null
            
            return false
        endmethod
        
        implement InitDummyCast
        
        //================================================================================
        //  A P I
        //================================================================================
        private static group eg = CreateGroup()
        
        method cast takes nothing returns boolean
            local unit    u
            local boolean b
            
            if instant then
                set u = .instantCaster
                call SetUnitX(u, this.x)
                call SetUnitY(u, this.y)
            else
                set  u = this.getCaster()
                set .i [GetHandleId(u)] = this
            endif
            
            call UnitAddAbility(u, this.abilId)
            call SetUnitAbilityLevel(u, this.abilId, this.abilLv)
            
            if this.target == 0 then
                set b = IssueImmediateOrder(u, this.order)
            elseif this.target == 1 then
                set b = IssuePointOrder(u, this.order, this.tX, this.tY)
            else
                set b = IssueTargetOrder(u, this.order, this.tU)
            endif
            
            if instant then
                call UnitRemoveAbility(u, this.abilId)
            endif
            
            set u = null
            
            return b
        endmethod
        
        //! textmacro DummyCast___OnUnitCastBasic
            loop
                set u = FirstOfGroup(.eg)
                exitwhen u == null
                
                call GroupRemoveUnit(.eg, u)
                
                if this.target == 0 then
                    set tx = this.x
                    set ty = this.y
                    set this.x = GetUnitX(u)
                    set this.y = GetUnitY(u)
                elseif this.target == 1 then
                    set tx = this.tX
                    set ty = this.tY
                    set this.tX = GetUnitX(u)
                    set this.tY = GetUnitY(u)
                else
                    set tu = this.tU
                    set this.tU = u
                endif
                
                if not b then
                    set b = this.cast()
                else
                    call this.cast()
                endif
                
                if this.target == 0 then
                    set this.x = tx
                    set this.y = ty
                elseif this.target == 1 then
                    set this.tX = tx
                    set this.tY = ty
                else
                    set this.tU = tu
                endif
            endloop
        //! endtextmacro
        
        //! textmacro DummyCast___OnLocCastBasic
            if this.target == 0 then
                set tx = this.x
                set ty = this.y
                set this.x = xc
                set this.y = yc
                
                set b = this.cast()
                
                set this.x = tx
                set this.y = ty
            else
                set tx = this.tX
                set ty = this.tY
                set this.tX = xc
                set this.tY = yc
                
                set b = this.cast()
                
                set this.tX = tx
                set this.tY = ty
            endif
        //! endtextmacro
        
        method castRectUnit takes rect r, boolexpr f returns boolean
            local unit    u
            local boolean b
            
            local real   tx
            local real   ty
            local unit   tu
            
            call GroupEnumUnitsInRect(.eg, r, f)
            
            //! runtextmacro DummyCast___OnUnitCastBasic()
            
            call GroupClear(.eg)
            set tu = null
            
            return b
        endmethod
        
        method castRect takes rect r returns boolean
            local real xc = GetRandomReal(GetRectMinX(r), GetRectMaxX(r))
            local real yc = GetRandomReal(GetRectMinY(r), GetRectMaxY(r))
            
            local real tx
            local real ty
            
            local boolean b
            
            if this.target == 2 then
                return this.castRectUnit(r, null)
            endif
            
            //! runtextmacro DummyCast___OnLocCastBasic()
            
            return b
        endmethod
        
        method castCircleUnit takes real x, real y, real r, boolexpr f returns boolean
            local unit    u
            local boolean b
            
            local real   tx
            local real   ty
            local unit   tu
            
            call GroupEnumUnitsInRange(.eg, x, y, r, f)
            
            //! runtextmacro DummyCast___OnUnitCastBasic()
            
            set tu = null
            
            return b
        endmethod
        
        method castCircle takes real x, real y, real r returns boolean
            local real rr = GetRandomReal(0, r)
            local real ra = GetRandomReal(0, 6,28)
            local real xc = x + rr * Cos(ra)
            local real yc = y + rr * Sin(ra)
            
            local real tx
            local real ty
            
            local boolean b
            
            if this.target == 2 then
                return this.castCircleUnit(x, y, r, null)
            endif
            
            //! runtextmacro DummyCast___OnLocCastBasic()
            
            return b
        endmethod
        //================================================================================
    endstruct
endlibrary
 
Last edited:
Level 17
Joined
Apr 27, 2008
Messages
2,455
Add this line in the jasshelper.conf of your JNGP (the one directly in your JNGP folder, not in the subfolder "jasshelper") :

[forcemethodevaluate]

And you will see.

Honestly, this feature would be activated by default for jasshelper.
 
JASS:
library DummyCast
    
    globals
        private constant integer DUMMY_CASTER_ID = 'dumy'
        //This unit is null. You haven't even tested the map. I think I will schedule
        //this to be graveyarded since the 3 other pending resources have at least been
        //tested.
        @private constant unit    DUMMY_CASTER    = CreateUnit(Player(15), DUMMY_CASTER_ID, 0, 0, 0)@
        private constant integer HEIGHT_ENABLER  = 'Amrf'
    endglobals
    
    struct InstantCast extends array
        unit     dummy
        player   owner
        real         x
        real         y
        real         z
        real      face
        integer abilId
        integer abilLv
        string   order
        
        private method onAllocate takes nothing returns nothing
            set this.dummy = DUMMY_CASTER
            set this.owner = Player(15)
        endmethod
        
        private method onDeallocate takes nothing returns nothing
            set this.dummy = null
            set this.owner = null
        endmethod
        
        //! runtextmacro DummyCast___Allocation()
        
        //! textmacro DummyCast___InstantAPI takes TARGET, TAKES, ORDER, ARG
        method t$TARGET$ takes $TAKES$ returns boolean
            local boolean b
            
            @call UnitAddAbility(this.dummy, HEIGHT_ENABLER)
            call UnitRemoveAbility(this.dummy, HEIGHT_ENABLER)@ //Pointless, the dummy doesn't need a height.
            
            @call SetUnitOwner(this.dummy, this.owner, false)@ //Pointless
            call SetUnitX(this.dummy, this.x)
            call SetUnitY(this.dummy, this.y)
            @call SetUnitFlyHeight(this.dummy, this.z, 0)@ //Pointless
            @call SetUnitFacing(this.dummy, this.face)@ //Pointless
            
            call UnitAddAbility(this.dummy, this.abilId)
            call SetUnitAbilityLevel(this.dummy, this.abilId, this.abilLv)
            set b = Issue$ORDER$Order(this.dummy, this.order$ARG$)
            call UnitRemoveAbility(this.dummy, this.abilId)
            
            return b
        endmethod
        //! endtextmacro
        
        //Consider running similar functions to a seperate function to avoid
        //duplicating compiled text like you do here:
        //! runtextmacro DummyCast___InstantAPI(  "None",        "nothing", "Immediate",       "")
        //! runtextmacro DummyCast___InstantAPI( "Point", "real x, real y",     "Point", ", x, y")
        //! runtextmacro DummyCast___InstantAPI("Widget",       "widget w",    "Target",    ", w")
    endstruct
    
    struct TimedCast extends array
        player   owner
        real         x
        real         y
        real         z
        real      face
        integer abilId
        integer abilLv
        string   order
        
        real  duration
        
        private        unit           dummy
        private static thistype array ins [8190]
        
        private method onAllocate takes nothing returns nothing
            set this.owner = Player(15)
        endmethod
        
        private method onDeallocate takes nothing returns nothing
            call RemoveUnit(this.dummy)
            set this.owner = null
        endmethod
        
        //You should be using the same allocator for both structs.
        @//! runtextmacro DummyCast___Allocation()@
        
        private static method expire takes nothing returns nothing
            call .ins [GetHandleId(GetExpiredTimer())].deallocate()
        endmethod
        
        //! textmacro DummyCast___TimedAPI takes TARGET, TAKES, ORDER, ARG
        method t$TARGET$ takes real duration$TAKES$ returns boolean
            local boolean b
            local timer   t = CreateTimer()
            local unit    d = CreateUnit(this.owner, DUMMY_CASTER_ID, this.x, this.y, this.face)
            
            call UnitAddAbility(d, HEIGHT_ENABLER)
            call UnitRemoveAbility(d, HEIGHT_ENABLER)
            call SetUnitFlyHeight(d, this.z, 0)
            
            call UnitAddAbility(d, this.abilId)
            call SetUnitAbilityLevel(d, this.abilId, this.abilLv)
            set b = Issue$ORDER$Order(d, this.order$ARG$)
            call UnitRemoveAbility(d, this.abilId)
            
            call TimerStart(t, this.duration, false, function thistype.expire)
            set .ins [GetHandleId(t)] = this
            set this.dummy = d
            
            set t = null
            set d = null
            
            return b
        endmethod
        //! endtextmacro
        
        //! runtextmacro DummyCast___TimedAPI(  "None",                 "", "Immediate",       "")
        //! runtextmacro DummyCast___TimedAPI( "Point", ", real x, real y",     "Point", ", x, y")
        //! runtextmacro DummyCast___TimedAPI("Widget",       ", widget w",    "Target",    ", w")
    endstruct
endlibrary
 
JASS:
        private static method onEndCast takes nothing returns boolean
            @local unit u = GetTriggerUnit()@ //Not nulled?
            
            call GroupAddUnit(.g, u)
            call UnitRemoveAbility(u, .i [GetHandleId(u)].abilId)
            
            return false
        endmethod

At this point I'm going to consider that you don't even care about this resource. It's proved because you didn't even test it (with the CreateUnit in the globals block for example), and you have random bugs that I don't even want to spend the time looking over because of the fact you haven't tested this yourself. Since this thing already has been submitted by several others, and yours honestly does not offer something new, I don't feel any sympathy if I graveyard this.

Scheduled for graveyarding in 7 days.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
I really do not like the setup API, at least you should have explained how this can be launched, just like this...
JASS:
local DummyCast this = 0
set this.owner = Player(0)
set this.abilId = 'ACfb'
set this.abilLv = 1
set this.order = "firebolt"
set this.instant = false
call this.tWidget(target)

instead of this...
JASS:
//player  owner             // the owner of the dummy unit
//real    x, y                // the position of the dummy unit
//integer AbilId, AbilLv     // the ability that will be casted
//string  order               // the ability's cast order
//boolean instant          // true  => instant cast (no casting time)
//                              // false => normal cast (casting time included)
 
Top