• 🏆 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] - Dummy Cast System [Workprint]

About:
This system is made to create easy dummy spell casting.
It uses my new Library AutoCasts which controls cast handling.

Testmap:
MyDummy Testmap


JASS:
// |'°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
// |'
// |' AutoCasts
// |' '""""""""""""'
// |' Made by: dhk_undead_lord
// |'
// |' Usage:
// |' Use this system to easily create
// |' automated spell casts.
// |'
// |'°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
library AutoCasts

    globals
        private constant real CAST_TIMER_INTERVALL = 0.03
    endglobals

    struct CastLibrary
        static Cast array toCast[8191]
        static integer index = 0
        static timer theCountdown = CreateTimer()

        public static method check takes nothing returns nothing
            local integer i = 0
            local Cast c = 0

            loop
                set c = CastLibrary.index

                set c.toCastDelay = c.toCastDelay - CAST_TIMER_INTERVALL

                if c.toCastDelay <= 0.00 then
                    call c.castInstant()

                    // Remove instance
                    set i = i - 1
                    call CastLibrary.removeCast(c)
                endif

                exitwhen i >= CastLibrary.index
                set i = i + 1
            endloop
        endmethod

        public static method addCast takes Cast c, real time returns nothing
            set c.toCastDelay = time
            set c.key = CastLibrary.index

            set CastLibrary.toCast[CastLibrary.index] = c
            set CastLibrary.index = CastLibrary.index + 1

            if CastLibrary.index == 1 then
                call TimerStart(CastLibrary.theCountdown, CAST_TIMER_INTERVALL, true, function CastLibrary.check)
            endif
        endmethod

        private static method removeCast takes Cast c returns nothing
            set CastLibrary.toCast[c.key] = CastLibrary.toCast[CastLibrary.index]
            set CastLibrary.index = CastLibrary.index - 1
        endmethod
    endstruct

    struct Cast
        unit theDummy
        integer abilityID
        integer level
        widget target
        real tarX
        real tarY
        string order

        real toCastDelay

        integer key

        public static method create takes nothing returns Cast
            return Cast.allocate()
        endmethod

        public method setCast takes unit dummy, integer abilityID, integer level, widget target, real tarX, real tarY, string order returns nothing
            set .theDummy = dummy
            set .abilityID = abilityID
            set .level = level
            set .target = target
            set .tarX = tarX
            set .tarY = tarY
            set .order = order
        endmethod

        private method cast takes nothing returns nothing
            call UnitAddAbility(.theDummy, .abilityID)
            call SetUnitAbilityLevel(.theDummy, .abilityID, .level)
            if .target != null then
                call IssueTargetOrder(.theDummy, .order, .target)
            elseif .tarX != 0.00 and .tarY != 0.00 then
                call IssuePointOrder(.theDummy, .order, .tarX, .tarY)
            else
                call IssueImmediateOrder(.theDummy, .order)
            endif
        endmethod

        public method castDelayed takes real time returns nothing
            call CastLibrary.addCast(this, time)
        endmethod

        public method castInstant takes nothing returns nothing
            call .cast()
        endmethod
    endstruct

endlibrary

JASS:
// |'°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
// |'
// |' MyDummy System
// |' '""""""""""""'
// |' Made by: dhk_undead_lord
// |'
// |' Usage:
// |' Use this system to easily create and cast
// |' dummyspells.
// |'
// |' Howto:
// |' Check example to see how this is casted
// |'
// |'°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
library MyDummy initializer init requires AutoCasts

    globals
        // #> IDS
        private constant integer DUMMY_ID = 'hmpr'
        private constant integer LOCUST_ID = 'Aloc'
        private constant integer TIMED_LIFE_ID = 'B000'

        // #> Numeric values
        private constant real TIMED_LIFE_TIME = 25.00
        private constant integer INVISIBILTY_AMOUNT = 255

        // #> Booleans
        private constant boolean FULL_MANA = true
        private constant boolean USE_TIMED_LIFE = true
        private constant boolean USE_LOCUST = true
        private constant boolean USE_INVISIBILITY = true

        // #> Triggers
        private constant trigger ON_DEATH = CreateTrigger()
    endglobals


    struct Dummy
        boolean hasLocust
        boolean hasTimedLife
        boolean hasInvisibility
        boolean hasFullMana
        unit theUnit

        Cast theCast

        public static method createAndCastInstant takes player thePlayer, real unitX, real unitY, real unitF, integer abilityID, integer level, widget target, real tarX, real tarY, string order returns Dummy
            local Dummy dmy = Dummy.createAndCast(thePlayer, unitX, unitY, unitF, abilityID, level, target, tarX, tarY, order)
            call dmy.theCast.castInstant()
            return dmy
        endmethod

        public static method createAndCastDelayed takes player thePlayer, real unitX, real unitY, real unitF, integer abilityID, integer level, widget target, real tarX, real tarY, string order, real time returns Dummy
            local Dummy dmy = Dummy.createAndCast(thePlayer, unitX, unitY, unitF, abilityID, level, target, tarX, tarY, order)
            call dmy.theCast.castDelayed(time)
            return dmy
        endmethod

        // General creation of a dummy
        private static method createAndCast takes player thePlayer, real unitX, real unitY, real unitF, integer abilityID, integer level, widget target, real tarX, real tarY, string order returns Dummy
            local Dummy dmy = Dummy.create(thePlayer, unitX, unitY, unitF)
            set dmy.theCast = Cast.create()
            call dmy.theCast.setCast(dmy.theUnit, abilityID, level, target, tarX, tarY, order)
            return dmy
        endmethod

        public static method create takes player thePlayer, real unitX, real unitY, real unitF returns Dummy
            local Dummy dmy = Dummy.allocate()

            set dmy.theUnit = CreateUnit(thePlayer, DUMMY_ID, unitX, unitY, unitF)

            // =========== LOCUST =============
            set dmy.hasLocust = USE_LOCUST
            if USE_LOCUST then
                call UnitAddAbility(dmy.theUnit, LOCUST_ID)
            endif

            // ========== TIMED LIFE ==========
            set dmy.hasTimedLife = USE_TIMED_LIFE
            if USE_TIMED_LIFE then
                call UnitApplyTimedLife(dmy.theUnit, TIMED_LIFE_ID, TIMED_LIFE_TIME)
            endif

            // ========== INVISIBILITY ==========
            set dmy.hasInvisibility = USE_INVISIBILITY
            if USE_INVISIBILITY then
                call SetUnitVertexColor(dmy.theUnit, 255, 255, 255, 255 - INVISIBILTY_AMOUNT)
            endif

            // ========== INVISIBILITY ==========
            set dmy.hasFullMana = FULL_MANA
            if FULL_MANA then
                call SetUnitState(dmy.theUnit, UNIT_STATE_MANA, GetUnitState(dmy.theUnit, UNIT_STATE_MAX_MANA))
            endif

            return dmy
        endmethod

        public method onDestroy takes nothing returns nothing
            call RemoveUnit(.theUnit)
            call .theCast.destroy()
        endmethod

    endstruct

    private function remove takes nothing returns nothing
        if GetUnitTypeId(GetTriggerUnit()) == DUMMY_ID then
            call RemoveUnit(GetTriggerUnit())
        endif
    endfunction

    private function init takes nothing returns nothing
        call TriggerRegisterAnyUnitEventBJ(ON_DEATH, EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddAction(ON_DEATH, function remove)
    endfunction

endlibrary

scope Test initializer init


    private function example takes nothing returns nothing
        call BJDebugMsg("Wird ausgeführt")

        call Dummy.createAndCastDelayed(Player(0), 0., 0., 270., 'AHfs', 3, null, 0.01, 0.01, "flamestrike", 2.)
        // ^ Create a Dummy unit for Player with ID 0 (Player 1), at X = 0., Y = 0.,
        // Facing = 270. which casts on widget = null, X = 275., Y = 190. the
        // ability with Spell-cast-id = "flamestrike"

    endfunction

    private function init takes nothing returns nothing
        call TimerStart(CreateTimer(), 0.01, false, function example)
    endfunction

endscope
 
Last edited:
Level 8
Joined
Aug 6, 2008
Messages
451
Omg..

You should never ever create dummies during the game time.

-Use some nice dummy stack for channeling spells.

-Use one global dummy, created at map init, to cast all your non channeling spells.

Thats how it is supposed to be done.
 
Level 8
Joined
Aug 6, 2008
Messages
451
CreateUnit is much much slower than SetUnitX + SetUnitY, thats why one dummy method pwns when you have to cast, lets say 20 stormbolts at the same time.

Also, you dont have to worry about leaking or timed life stuff or anything like that.

To get unit cast spells instantly, you obviously need to get rid of the all factors that make casting non instant. o_O ( lols, obviously )

These are for example:

-spell casting time
-unit casting animation time thingies
-units facing angle

there might be more, I dont remember. If you dont feel like searching all of those, copy the dummy unit from my AssAssTidies test map: link
 
Viikuna, with making one global dummy you loose MUI.

Spells like Chain lightning, channeling spells in general or
delayed spells (flamestrike, shadow strike) will not work with your
method.

Also spells can have more then 1 dummy, for example mass banish at the
same time.

AND THE FINAL NOTE:
It is just an example how to use this system!

You can also create only one DUMMY unit at the init, and
use it to cast spells like you said.

It doesn't matter, its just the system.
 
Level 11
Joined
Feb 22, 2006
Messages
752
I don't see how this makes using dummy channeling spells any easier than xecast. And delayed casting can be achieved so easily with xecast and TimerUtils it's not worth approving this just for that.

And xecast's syntax is just better than this and provides more options like user-defined sources, casting on AOE, and casting on groups.

By the way, there's ONE knockback system here.
 
Top