• 🏆 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] [Snipet] CoreDummy

Level 9
Joined
Jun 21, 2012
Messages
432
JASS:
library CoreDummy/*
***********************************************************************************************
*
*   *******************************************************************************************
*
*   */ uses /*
*       */ optional ARGB /* wc3c.net/showthread.php?t=101858 
*
*   *******************************************************************************************
*
*   CoreDummy
*   ¯¯¯¯¯¯¯¯¯
*   v0.1.1.1
*   by Thelordmarshall
*
*   Create dummies for your spells.
*   
*   Pros:
*   ¯¯¯¯
*       - reduce the loading time of your map (by using one or less dummies)
*       - instant xy and z facing
*       - not use SetUnitLookAt
*       - all caster/dummy utilities in one library
*       - disables your unit indexer system on create dummies to prevent unnecessary indexes
*       - error message when dummy is killed/removed; only in DEBUB_MODE
*
*   Cons:
*   ¯¯¯¯
*       - no GUI friendly
*       - only 8191 instances (need more?)
*
*   API:
*   ¯¯¯
*   struct Dummy extends array
*
*       Creator/Destructor
*       ------------------
*       static method create takes player owner, real x, real y, real angle returns Dummy
*       method destroy takes nothing returns nothing
*
*       Operators/Configuration
*       -----------------------
*       public boolean hiddenDestroy
*
*       method operator unit takes nothing returns unit
*       method operator data takes nothing returns integer
*       method operator data= takes integer d returns nothing
*       method operator model= takes string fx returns nothing
*       method operator scale takes nothing returns real
*       method operator scale= takes real s returns nothing
*       method operator x takes nothing returns real
*       method operator y takes nothing returns real
*       method operator z takes nothing returns real
*       method operator x= takes real x returns nothing
*       method operator y= takes real y returns nothing
*       method operator z= takes real z returns nothing
*       method operator xyAngle takes nothing returns real
*       method operator zAngle takes nothing returns real
*       method operator xyAngle= takes real a returns nothing
*       method operator zAngle= takes real a returns nothing
*       method operator owner takes nothing returns player
*       method operator owner= takes player p returns nothing
*       method operator playerColor= takes playercolor c returns nothing
*       method operator color= takes ARGB c returns nothing
*         - if library ARGB exist
*
*       Methods
*       -------
*       method setColor takes integer r, integer g, integer b, integer a returns nothing
*          - if library ARGB does not exist
*       method flashTarget takes string fx returns nothing
*           - create/destroy fx on dummy
*       method flashPoint takes string fx returns nothing
*           - create/destroy fx on dummy position
*       method setPosition takes real x, real y returns nothing
*       method setAbility takes integer abilId, integer lvl returns nothing
*
*       Caster Methods
*       --------------
*       static method cast takes unit source, integer abilId, integer lvl, integer order returns boolean
*       static method castTarget takes unit source, integer abilId, integer lvl, integer order, widget t returns boolean
*       static method castPoint takes unit source, integer abilId, integer lvl, integer order, real x, real y returns boolean
*       
*   Credits:
*   ¯¯¯¯¯¯¯
*       - Vexorian: old CasterSystem, xedummy, the insert/remove angle methods
*         and the dummy.mdx model
*
**********************************************************************************************/
    
    //CONFIGURATION
    //===============================================================================
    globals
        constant integer         DUMMY_ID                 = 'e000'
        private constant integer STACK_SIZE               = 256
        private constant real    DEFAULT_DUMMY_SCALE      = 1.00
        private constant real    DEFAULT_DUMMY_FLY_HEIGHT = 70.00
        private constant real    DUMMY_HIDDEN_FLY_HEIGHT  = 9999.00
        private constant real    CASTER_REMOVE_DELAY      = 0.50
    endglobals
    
    //put here the enable/disable function of your unit indexer system
    //! textmacro UNIT_INDEXER_CONFIG takes ENABLED
        set UnitIndexer.enabled = $ENABLED$ //enable/disable UnitIndexer, UnitDex, etc...
    //! endtextmacro
    
    private function FlyEnablerConfig takes unit u returns boolean
        return UnitAddAbility(u, 'Amrf') and UnitRemoveAbility(u, 'Amrf')
    endfunction
    //===============================================================================
    //ENDCONFIGURATION
    
    globals
        private timer delayTimer=CreateTimer()
        private constant integer RESOLUTION=12
        private constant player OWNER=Player(15)
        private constant group STACK=CreateGroup()
        private unit array stack
        private unit array delay_unit
        private real array angle
        private integer array next
        private integer array prev
        private integer array size
        private integer array first
        private integer array last
        private integer array list
        private integer array dummy_next
        private integer array delay_dummy
        private integer delay_next=0
    endglobals
    
    //! textmacro Dummy_debug takes DEBUG,NATIVE,DEBUG_STR
    debug function $DEBUG$ takes unit u returns nothing
        debug if(IsUnitInGroup(u,STACK))then
            debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"[CoreDummy] warning: a dummy "+"$DEBUG_STR$")
        debug endif
    debug endfunction
    debug hook $NATIVE$ $DEBUG$
    //! endtextmacro
    
    //! runtextmacro Dummy_debug("KillDummy_debug","KillUnit","has been killed")
    //! runtextmacro Dummy_debug("RemoveDummy_debug","RemoveUnit","has been removed from map")

    struct Dummy extends array
        public boolean hiddenDestroy
        private unit dummy
        private real zangle
        private real d_scale
        private effect effect
        private integer ability
        
        private static method operator alloc takes nothing returns integer
            local thistype this=list[0]
            if(0==list[this])then
				set list[0]=this+1
			else
				set list[0]=list[this]
			endif
			return this
        endmethod
        
        private static method getIndex takes real a returns integer
            if(a<0)then
                set a=a+360
            elseif(a>360)then
                set a=360
            endif
            return R2I(a/360*RESOLUTION)+1
        endmethod

        private method insert takes integer a returns nothing
            call SetUnitFacing(stack[this],angle[a])
            if(0==size[a])then
                set first[a]=this
            else
                set dummy_next[last[a]]=this
            endif
            set last[a]=this
            set dummy_next[this]=0
            if(size[a]>size[next[a]])then
                set this=first[a]
                set first[a]=dummy_next[this]
                call .insert(next[a])
            elseif(size[a]>size[prev[a]])then
                set this=first[a]
                set first[a]=dummy_next[this]
                call .insert(prev[a])
            else
                set size[a]=size[a]+1
            endif
        endmethod
        
        private static method remove takes integer a returns integer
            local integer this
            if(0==size[a])then
                call newDummy(angle[a])
            endif
            if(size[a]<size[next[a]])then
                set this=last[a]
                set last[a]=remove(next[a])
                set dummy_next[this]=last[a]
                call SetUnitFacing(stack[last[a]],angle[a])
            elseif(size[a]<size[prev[a]])then
                set this=last[a]
                set last[a]=remove(prev[a])
                set dummy_next[this]=last[a]
                call SetUnitFacing(stack[last[a]],angle[a])
            else
                set size[a]=size[a]-1
                if(0==size[a])then
                    set last[a]=0
                endif
            endif
            set this=first[a]
            set first[a]=dummy_next[this]
            set dummy_next[this]=0
            return this
        endmethod
        
        private static method newDummy takes real a returns nothing
            local thistype this=alloc
            //! runtextmacro UNIT_INDEXER_CONFIG("false")
            set stack[this]=CreateUnit(OWNER,DUMMY_ID,0,0,a)
            //! runtextmacro UNIT_INDEXER_CONFIG("true")
            call .insert(getIndex(a))
            call UnitAddAbility(stack[this],'Aloc')
            call FlyEnablerConfig(stack[this])
            call GroupAddUnit(STACK,stack[this])
        endmethod
        
        //! textmacro DummyOperator takes METHOD,VAR_TYPE,RETURNED,ACTION,USE_STRING,EXTRA_SYMBOL,EXTRA_ACTION
        method $METHOD$ takes $VAR_TYPE$ returns $RETURNED$
            $ACTION$$USE_STRING$"origin")$EXTRA_SYMBOL$)
            $EXTRA_ACTION$
        endmethod
        //! endtextmacro
        
        //! runtextmacro DummyOperator("operator unit","nothing","unit","return .dummy","//","//","//")
        //! runtextmacro DummyOperator("operator data","nothing","integer","return GetUnitUserData(.dummy)","//","//","//")
        //! runtextmacro DummyOperator("operator data=","integer i","nothing","call SetUnitUserData(.dummy,i)","//","//","")
        //! runtextmacro DummyOperator("operator model=","string s","nothing","set.effect=AddSpecialEffectTarget(s,.dummy,","","//","")
        //! runtextmacro DummyOperator("operator scale","nothing","real","return .d_scale","//","//","//")
        //! runtextmacro DummyOperator("operator scale=","real s","nothing","call SetUnitScale(.dummy,s,s,s)","//","//","set .d_scale=s")
        //! runtextmacro DummyOperator("operator x","nothing","real","return GetUnitX(.dummy)","//","//","//")
        //! runtextmacro DummyOperator("operator y","nothing","real","return GetUnitY(.dummy)","//","//","//")
        //! runtextmacro DummyOperator("operator z","nothing","real","return GetUnitFlyHeight(.dummy)","//","//","//")
        //! runtextmacro DummyOperator("operator x=","real x","nothing","call SetUnitX(.dummy,x)","//","//","//")
        //! runtextmacro DummyOperator("operator y=","real y","nothing","call SetUnitY(.dummy,y)","//","//","//")
        //! runtextmacro DummyOperator("operator z=","real z","nothing","call SetUnitFlyHeight(.dummy,z,0.)","//","//","//")
        //! runtextmacro DummyOperator("operator xyAngle","nothing","real","return GetUnitFacing(.dummy)","//","//","//")
        //! runtextmacro DummyOperator("operator xyAngle=","real a","nothing","call SetUnitFacing(.dummy,a)","//","//","//")
        //! runtextmacro DummyOperator("operator zAngle","nothing","real","return .zangle","//","//","//")
        //! runtextmacro DummyOperator("operator owner","nothing","player","return GetOwningPlayer(.dummy)","//","//","//")
        //! runtextmacro DummyOperator("operator owner=","player p","nothing","call SetUnitOwner(.dummy,p,true)","//","//","//")
        //! runtextmacro DummyOperator("operator playerColor=","playercolor c","nothing","call SetUnitColor(.dummy,c)","//","//","//")
        //! runtextmacro DummyOperator("flashTarget","string fx","nothing","call DestroyEffect(AddSpecialEffectTarget(fx,.dummy,","","","//")
        //! runtextmacro DummyOperator("flashPoint","string fx","nothing","call DestroyEffect(AddSpecialEffect(fx,GetUnitX(.dummy),GetUnitY(.dummy)))","//","//","//")
        //! runtextmacro DummyOperator("setPosition","real x, real y","nothing","set .x=x","//","//","set .y=y")

        static if(LIBRARY_ARGB)then
            //! runtextmacro DummyOperator("operator color=","ARGB c","nothing","call c.recolorUnit(.dummy)","//","//","//")
        else
            //! runtextmacro DummyOperator("setColor","integer r, integer g, integer b, integer a","nothing","call SetUnitVertexColor(.dummy,r,g,b,a)","//","//","//")
        endif
        
        method operator zAngle= takes real a returns nothing
            local integer i=R2I(a*bj_RADTODEG+90.5)
            set .zangle=a
            if(i>=180)then
                set i=179
            elseif(i<0)then
                set i=0
            endif
            call SetUnitAnimationByIndex(.dummy,i)
        endmethod

        method setAbility takes integer abilId, integer lvl returns nothing
            if(0!=.ability)then
                call UnitRemoveAbility(.dummy,.ability)
            endif
            set .ability=abilId
            call UnitAddAbility(.dummy,.ability)
            call SetUnitAbilityLevel(.dummy,.ability,lvl)
        endmethod
        
        private static method onDelay takes nothing returns nothing
            local integer i=delay_next
            loop
                if(null==delay_unit[i])then
                    call Dummy(delay_dummy[i]).destroy()
                else
                    call IssueImmediateOrderById(delay_unit[i],851972)
                    call RemoveUnit(delay_unit[i])
                    set delay_unit[i]=null
                endif
                exitwhen(1==i)
                set i=i-1
            endloop
            set delay_next=0
            call PauseTimer(delayTimer)
        endmethod
        
        private static method startDelay takes Dummy d, unit u returns nothing
            set delay_next=delay_next+1
            set delay_unit[delay_next]=u
            set delay_dummy[delay_next]=d
            call TimerStart(delayTimer,CASTER_REMOVE_DELAY,false,function thistype.onDelay)
        endmethod
        
        //! textmacro Dummy_cast takes METHOD,ARGUMENTS,ORDER_FUNCTION
        static method $METHOD$ takes $ARGUMENTS$ returns boolean
            local Dummy d=create(GetOwningPlayer(source),GetUnitX(source),GetUnitY(source),0)
            call d.setAbility(abilId,lvl)
            call startDelay(d,null)
            return $ORDER_FUNCTION$
        endmethod
        //! endtextmacro
        
        //! runtextmacro Dummy_cast("cast","unit source, integer abilId, integer lvl, integer order","IssueImmediateOrderById(d.unit,order)")
        //! runtextmacro Dummy_cast("castTarget","unit source, integer abilId, integer lvl, integer order, widget t","IssueTargetOrderById(d.unit,order,t)")
        //! runtextmacro Dummy_cast("castPoint","unit source, integer abilId, integer lvl, integer order, real x, real y","IssuePointOrderById(d.unit,order,x,y)")

        static method create takes player owner, real x, real y, real angle returns Dummy
            local integer a=getIndex(angle)
            local thistype this=remove(a)
            set .dummy=stack[this]
            call .setPosition(x,y)
            call SetUnitFacing(.dummy,angle)
            call SetUnitOwner(.dummy,owner,true)
            set .z=DEFAULT_DUMMY_FLY_HEIGHT
            set .scale=DEFAULT_DUMMY_SCALE
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            local integer int
            if(null!=.dummy)then
                set list[this]=list[0]
                set list[0]=this
                set stack[this]=null
                if(0!=.ability)then
                    call UnitRemoveAbility(.dummy,.ability)
                endif
                if(null!=.effect)then
                    call DestroyEffect(.effect)
                    set .effect=null
                endif
                if(integer(this)>STACK_SIZE)then
                    call GroupRemoveUnit(STACK,.dummy)
                    call startDelay(0,.dummy)
                else
                    set int=alloc
                    set stack[int]=.dummy
                    call Dummy(int).insert(getIndex(GetUnitFacing(.dummy)))
                    call SetUnitOwner(.dummy,OWNER,true)
                    call SetUnitAnimationByIndex(.dummy,90)
                    call SetUnitVertexColor(.dummy,255,255,255,255)
                    if(.hiddenDestroy)then
                        set .z=DUMMY_HIDDEN_FLY_HEIGHT
                        set .hiddenDestroy=false
                    endif
                endif
                set .dummy=null
            debug else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"[CoreDummy] error: attempted to destroy null dummy")
            endif
        endmethod
        
        private static method onInit takes nothing returns nothing
            local integer i=0
            local integer a=1
            set list[0]=1
            loop
                exitwhen(RESOLUTION==i)
                set i=i+1
                set prev[i]=i-1
                set next[i]=i+1
                set angle[i]=(i-.5)*(360/RESOLUTION)
            endloop
            set prev[1]=i
            set next[i]=1
            set i=STACK_SIZE
            loop
                exitwhen(0==i)
                call newDummy(angle[a])
                set a=next[a]
                set i=i-1
            endloop
        endmethod
    endstruct
endlibrary
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
I can list minimum 3 dummy libraries off-hand. Hence explain why anyone should
use CoreDummy over:
1.) xe_dummy ( Vexorian )
2.) Dummy ( Nestharus )
3.) MissileRecycler ( Bribe )

Side note: ARGB is not a valid pro.

What I saw at a glance, is that you don't provide any dummy protection time in order to restore the original set angle facing.
( units need maximum 0.73 seconds to turn. )

Also when reading your API, it came clear that you wish users to use your functions i.e to set/get a dummy's position.
Quite bad performance, considering you use this for i.e a missile system.

Remove all these really unessesary operators and stick to a minimum, which is
create(x, y, z, face) and destroy(). All the rest is crap.
 
Level 9
Joined
Jun 21, 2012
Messages
432
1) xe_dummy: old, requires xe_basic and if you want to use other components such as move, scale, rotate, cast spells you should implement xecas and xefx.

2) Dummy: is based only to create/destroy dummy.

3) MissileRecycler: only has GetRecycledMissile/RecycleMissile.

This library is designed to address all Dummy fields without implementing some extra resources.

All craped fields as you say are required for a truly comprehensive dummy system. You can not have a dummy system where you have the need to create extra code to cast spells or move/rotate/scale your dummy unit.

Why ARGB is not a valid pro?

What I saw at a glance, is that you don't provide any dummy protection time in order to restore the original set angle facing.
( units need maximum 0.73 seconds to turn. )

Recycled dummy are stacked and until there is not another unit with the requested angle (also feature dummies with adjacent angles), another new dummy is created. I tested CoreDummy firing a dummy missile every 0.06 seconds traveling a distance of 800 at a speed of 1500 and never gets to create a new unit, obviously this also depends on the size of the stack.

However still must have some things I need to improve.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
1) xe_dummy: old, requires xe_basic and if you want to use other components such as move, scale, rotate, cast spells you should implement xecas and xefx.
Queen is also old, but still gold. Old is definitly a bad argument of yours.
Ok to the fact that you need the whole xe package. Btw xe_basic are just 4/5 constants.

2) Dummy: is based only to create/destroy dummy.

3) MissileRecycler: only has GetRecycledMissile/RecycleMissile.
Is precise what we want from a dummy library. Every extra functionality is garbage.

Unit is accessible via method operator unit takes nothing returns unit
this one is good and required. Let's talk about following operator overloadings.

1.) data= / data. We strictly ban the usage of UnitUserData as it is reserved to UnitIndexers.

2.) model= is ok, but can also be done in each library. Sometimes I want two effects on my dummy.

3.) scale? Just use SetUnitScale if you need it.

4.) x/y/z x=/y=/z= Cost-effectiveness considerations! You add a lot of overhead for low usage.
Personally I wonder where the benefit of operator x/y over GetUnitX()/GetUnitY() is.

5.) Owner. Dummies should never change their owner. If required you can assign a pseudo owner. That can be done externally.

6.) FlashTarget/... no comment.

However still must have some things I need to improve.
Yes
 
Top