• 🏆 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) [vJass] SpellBar - Caster Bar for Spells

Hey.

Some time ago I made the CustomBar.
Now I have made a new system, the SpellBar!

It creates SpellProgress bar for your hero skills. Automaticly gets removed on spell finish and/or aborts.

Requires CustomBar and ARGB in order to work.
(Both included)

Please give credits, comments and such.
System request by: corley

Update1: Added more documentation and is now more user friendly.

JASS:
//*|------------------------------------------------------------------------------------|>
//*| SpellBar v.1.00 |>
//*| by dhk_undead_lord aka Anachron |>
//*| |>
//*| ABOUT: |>
//*| This system provides you with the ability to create RPG cast |>
//*| bars, such as in World of Warcraft. |>
//*| |>
//*| WHAT YOU NEED: |>
//*| You need JassNewGenPack to use this vJASS system. |>
//*| (Download it here: http://www.wc3c.net/showthread.php?goto=newpost&t=90999) |>
//*| |>
//*| STEPS TO IMPORT: |>
//*| I.) Copy this code. |>
//*| II.) Paste it into the head of your map. |>
//*| (Therefor go to the Trigger Editor, select the mapname and paste |>
//*| into the area on the right) |>
//*| III.) Save your map! |>
//*| (With File - Save Map (S) or control + S. DO NOT SAVE WITH SAVE AS!) |>
//*| IV.) You got it! You imported the system. |>
//*| |>
//*| To make sure this system works, you should try a few tests! |>
//*|------------------------------------------------------------------------------------|>
library SpellBar initializer init requires CustomBar

    //=!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#
    //: Change anything below to what you need!
    //=!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#

    //: The customizeable constants.
    //: I hope the names are self-explaining.
    globals
        private constant real TIMER_TICK = 0.03
    endglobals

    //=!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#
    //: I don't recommend changing code below this!
    //=!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#
    globals
        //==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
        //: System data.
        //==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
        private hashtable SpellBarInstances = InitHashtable()
        private trigger SystemTrigger = CreateTrigger()

    endglobals

    public function updateSpellBar takes CustomBar cb returns nothing
        local SpellBar sb = SpellBar(LoadInteger(SpellBarInstances, GetHandleId(cb.target), 0))
        set cb.txtBar.percentage = (sb.elapsed / sb.max) * 100
    endfunction

    public function showCheck takes player owner, player cur returns boolean
        return IsPlayerAlly(owner, cur) or owner == cur
    endfunction

    //: A struct which contains all SpellBar
    //: information we need.
    struct SpellBar
        //==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        //: SpellBar members
        //==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        private CustomBar cb = 0
        public real elapsed = 0.
        public real max = 0.
        public unit han = null

        //==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        //: Static members
        //==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        private static timer TIMER = CreateTimer()
        private static thistype array INSTANCES[8191]
        private static integer INDEX = 0

        //==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        //: SpellBar methods
        //==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        private static method drainInst takes thistype this returns boolean
            if .elapsed < .max then
                set .elapsed = .elapsed + TIMER_TICK
                return false
            else
                call .destroy()
                return true
            endif
        endmethod

        private static method drain takes nothing returns nothing
            local integer i = 0

            loop
                exitwhen i >= thistype.INDEX

                if thistype.drainInst(thistype.INSTANCES[i]) then
                    set i = i - 1
                endif

                set i = i + 1
            endloop

            if thistype.INDEX <= 0 then
                call PauseTimer(thistype.TIMER)
            endif
        endmethod

        public static method create takes unit u, integer i, real dur, CustomBar b returns thistype
            local thistype this = thistype.allocate()
            local ARGB left = 0
            local ARGB right = 0
            local CustomBar c = 0

            //: Set variables
            set .han = u
            set .max = dur

            //: Save the CustomBar
            set .cb = b

            set thistype.INSTANCES[.INDEX] = this
            set thistype.INDEX = thistype.INDEX + 1
            if thistype.INDEX == 1 then
                call TimerStart(thistype.TIMER, TIMER_TICK, true, function thistype.drain)
            endif
            call SaveInteger(SpellBarInstances, GetHandleId(u), 0, integer(this))

            return this
        endmethod

        private method onDestroy takes nothing returns nothing
            set thistype.INSTANCES[integer(this)] = thistype.INSTANCES[thistype.INDEX]
            set thistype.INDEX = thistype.INDEX - 1
            call FlushChildHashtable(SpellBarInstances, GetHandleId(.han))
            call .cb.destroy()
        endmethod
    endstruct

//: Handles the SpellBar removing
//: if unit gets an new order while casting.
    private function eventHandler takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local integer i = GetHandleId(u)
        local integer sbID = LoadInteger(SpellBarInstances, i, 0)
        local SpellBar sb = SpellBar(sbID)

        if sb.han != null then
            call sb.destroy()
        endif
    endfunction

    //: This function now registers any order which is able to
    //: interrupt the spell cast. Default is everything.
    private function init takes nothing returns nothing
        local integer i = 0

        call TriggerAddAction(SystemTrigger, function eventHandler)

        loop
            exitwhen i >= 15

            call TriggerRegisterPlayerUnitEvent(SystemTrigger, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
            call TriggerRegisterPlayerUnitEvent(SystemTrigger, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
            call TriggerRegisterPlayerUnitEvent(SystemTrigger, Player(i), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)

            set i = i + 1
        endloop
    endfunction

endlibrary



JASS:
scope SpellBarTest initializer init

    private function newSpellBar takes nothing returns nothing
        local CustomBar c       = 0
        local ARGB      left    = 0
        local ARGB      right   = 0
        
        //: =-------------------=
        //: Initialize CustomBar
        //: =-------------------=
        //: Add Colors
        set left = ARGB.create(255, 8, 74, 16)
        set right = ARGB.create(255, 214, 255, 230)
        //: I Highly suggest to not touch this->
        set c = CustomBar.create(GetTriggerUnit(), CustomBar_iChange.SpellBar_updateSpellBar)
        //: Add a gradient
        call c.txtBar.addGradient(left, right, 1, 25)
        //: Show the CustomBar to this playergroup
        call c.Show(bj_FORCE_ALL_PLAYERS, CustomBar_iShow.SpellBar_showCheck)
        //: Display the CustomBar.
        call c.showCB()
        //: Now change our CustomBar to display the Spellname aswell.
        set c.txtBar.limiterVisible = true
        set c.txtBar.limiterSymbolRight = ""
        set c.txtBar.limiterSymbolLeft = GetObjectName('AHhb') + "\n"
        
        //: Actually creates the SpellBar
        call SpellBar.create(GetTriggerUnit(), 'AHhb', 2.00, c)
    endfunction

    private function holyLightOnly takes nothing returns boolean
        return GetSpellAbilityId() == 'AHhb'
    endfunction

    private function init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0

        call TriggerAddAction(t, function newSpellBar)
        call TriggerAddCondition(t, Condition(function holyLightOnly))

        loop
            exitwhen i >= 15

            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_CHANNEL, null)
            set i = i + 1
        endloop

        set t = null
    endfunction

endscope




Keywords:
Spell, Bar, Ability, Custom, Awesome, RPG, WoW, World of Warcraft, Role Play Gaming
Contents

Spellbar v.1.01 (Map)

Reviews
14:28, 5th Nov 2009 The_Reborn_Devil: The code looks pretty good and there's nothing wrong with this as far as I can see. It's pretty easy to make a SpellBar with your system, but I don't think it's easy enough for everyone. All this is a little...

Moderator

M

Moderator

14:28, 5th Nov 2009
The_Reborn_Devil:

The code looks pretty good and there's nothing wrong with this as far as I can see. It's pretty easy to make a SpellBar with your system, but I don't think it's easy enough for everyone.
All this is a little much I think for some of our users:
JASS:
local CustomBar c = 0
        local ARGB left = 0
        local ARGB right = 0

        //: =-------------------=
        //: Initialize CustomBar
        //: =-------------------=
        //: Add Colors
        set left = ARGB.create(255, 8, 74, 16)
        set right = ARGB.create(255, 214, 255, 230)
        //: I Highly suggest to not touch this->
        set c = CustomBar.create(GetTriggerUnit(), CustomBar_iChange.SpellBar_updateSpellBar)
        //: Add a gradient
        call c.txtBar.addGradient(left, right, 1, 25)
        //: Show the CustomBar to this playergroup
        call c.Show(bj_FORCE_ALL_PLAYERS, CustomBar_iShow.SpellBar_showCheck)
        //: Display the CustomBar.
        call c.showCB()
        //: Now change our CustomBar to display the Spellname aswell.
        set c.txtBar.limiterVisible = true
        set c.txtBar.limiterSymbolRight = ""
        set c.txtBar.limiterSymbolLeft = GetObjectName('AHhb') + "\n"

        //: Actually creates the SpellBar
        call SpellBar.create(GetTriggerUnit(), 'AHhb', 2.00, c)
Yes, I'm aware of the fact that you need to have a lot of functions to make it as customizable as it its, but it could be easier.

Status: Approved
Rating: Recommended

If you make it even more user-friendly then I will consider giving this the rating "Highly Recommended".
 
In my test the walk away did not interrupt the spell cast...?!


no it doesn't!!
if you order the unit to walk away while he casts using the bar, he isn't following the order and the bar stays active.

only the STOP order aborts the channeling
Guys really: If you order them to move / patrol whatever the spell cast continues,
that is normal. (Such as wc3 spell cast)

THAT is wc3!
 
Last edited:
Level 10
Joined
Apr 3, 2006
Messages
535
Hey Anachron, just wanted to say thanks for doing this sytem and changing the documentation to be newb friendly for people like me, and also massive thanks for the tech support :p +rep dude u really do deserve it.
 
Level 14
Joined
Nov 18, 2007
Messages
816
//: I Highly suggest to not touch this->
Dont let the user do it?

This is horribly scoped. Why allow a user to change the elapsed member? Or the max member? Or the han member (whatever that one is)?

Theres no documentation AT ALL. What are the things i can do with it? The example doesnt show everything.

Also, having the create a CustomBar AND a SpellBar seems horribly complicated. Simplify the API, please.
 
Dont let the user do it?
Why not?

This is horribly scoped. Why allow a user to change the elapsed member? Or the max member? Or the han member (whatever that one is)?
Han = Handle = The actual unit.
Max and elapsed are also changeable because some effects could just reset the castpoint.

Theres no documentation AT ALL. What are the things i can do with it? The example doesnt show everything.
Its commented. And it really does.

Also, having the create a CustomBar AND a SpellBar seems horribly complicated. Simplify the API, please.
Those are 2 diffrent things. The spellbar actually has a CustomBar.

Later you will see why my Librarys are reuseable and yours not. Its mainly because I don't bound librarys to each other, that really sucks.
 
Level 14
Joined
Nov 18, 2007
Messages
816
Because someone will fuck it up. Hide the low level shit from morons.
Thats why making the han member private is a good idea. To hell with the option to change the unit casting dynamically. Its not needed and only bloats the library's API.

Changing the max and elapsed members also isnt needed. Not at all. Its a useless feature.

And your example doesnt show everything. max, elapsed and han are a good example. Theyre listed nowhere, except in the code, and frankly, noone will look over the code to learn the API. Thats why you document code.

I freaking know the SpellBar has a CustomBar. You could simplify it by automagically creating a CustomBar inside a SpellBar. Less confusion for the user.
 
Because someone will fuck it up. Hide the low level shit from morons.
I have got a few replies to my system, and for example corley doesn't know lot about jass, but he is learning.

That's why making the han member private is a good idea. To hell with the option to change the unit casting dynamically. Its not needed and only bloats the library's API.
I will not remove functionality just because one doesn't need it at all. I already used it in an spell manipulator (Unit casts backwards).

Changing the max and elapsed members also isnt needed. Not at all. Its a useless feature.
See last.

And your example doesn't show everything. max, elapsed and han are a good example. They're listed nowhere, except in the code, and frankly, no one will look over the code to learn the API. That's why you document code.
The example shows how you can configure an advanced Bar.

I freaking know the SpellBar has a CustomBar. You could simplify it by automatically creating a CustomBar inside a SpellBar. Less confusion for the user.
I had it like that at first but I decided to give the user the possibility to create the CustomBar themself, to generate user specialized bars.
 
Level 6
Joined
Feb 26, 2008
Messages
171
Is it possible to make only visible to the player casting the spell??? Would make a big plus :O :D And you could also write Casting over the head of the caster so that ennemies knows that they're casting a spell but they can't see if they're pretty done casting the spell or have just started (hope you understand)

Just make a boolean and if true then (for the map maker options) it'll allow this.

In other words: show bar to everybody =>
FALSE = your current system, showing the bar to everyone, even ennemies
TRUE = my suggestion, shows the bar to allies only, the ennemies will see ''Casting'' floating text over the Caster.
 
Is it possible to make only visible to the player casting the spell??? Would make a big plus :O :D

Just make a boolean and if true then (for the map maker options) it'll allow this.

In other words: show bar to everybody =>
FALSE = your current system, showing the bar to everyone, even ennemies
TRUE = my suggestion, shows the bar to allies only, the ennemies will see ''Casting'' floating text over the Caster.

JASS:
call c.Show(bj_FORCE_ALL_PLAYERS, CustomBar_iShow.SpellBar_showCheck)
Use your own function here that returns true and use the force of the player you need.

And you could also write Casting over the head of the caster so that ennemies knows that they're casting a spell but they can't see if they're pretty done casting the spell or have just started (hope you understand)
Well, this is really individual and would blow up the system. Its really easy to add it yourself since this has nothing to do with Bars anymore.
 
Level 5
Joined
Dec 8, 2008
Messages
102
if you base your spells on for example 'storm bolt', then you cant move while you cast, the only casting system with casting bars like in wow works with the spell 'channeling' because while channeling you can move^^ but the negative thing about this is that every spell has to be triggered/scriptet and so its nothing for unexperienced people or gui users
 
if you base your spells on for example 'storm bolt', then you cant move while you cast, the only casting system with casting bars like in wow works with the spell 'channeling' because while channeling you can move^^ but the negative thing about this is that every spell has to be triggered/scriptet and so its nothing for unexperienced people or gui users
Dude, that's not my fault, that's wc3.

And how the hell would you get the casting time of a spell?
 
Level 1
Joined
Jul 14, 2008
Messages
3
anachron need help i am new at jazz how can i use this on my custom spells? it only works on holy light. is that aHhb spells code? if it is can i learn spells code?
 
Last edited:
Level 3
Joined
Mar 14, 2011
Messages
32
theres a serious problem with the system

when two units start to cast a spell consecutively, after first one finishes

bunch of double types appear and crash the game
 
Top