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

CastBarSystem v1.12

JASS:
library CastBarSystem
/*                       CastBar System v1.12
                            by Flux
                http://www.hiveworkshop.com/forums/members/flux/
                
        CastBarSystem allows you to easily create and modifies CastBars.
        
        Required skill to use:
            * Minimum JASS scripting skills, if you know how to remove
              leaks, you can easily use this system. 
              To know how this system works, you need vJASS knowledge.
        
        Features:
            * CastBar comes with a name and time remaining displayed as
              a floating text.
            * Customizable colors of CastBar and CastBar text.
            * CastBars can be free-floating, attached to unit or attached
              to a player's camera.
            * Provides event APIs allowing you to easily detect when a
              CastBar has expired.
        
    **************   HOW TO USE:   **************************
    1. Copy the variable "CastBar_Expires" to your map then copy 
       the CastBarSystem Trigger. Make sure you have Jass New Gen Pack 
       for this to work because it is written in vJASS. 
       
    2.1 If you are satisfied with the CastBar design, import Bar.blp and 
        LightningData.slk to your map as well. Make sure you have
        the same path as shown here (Press F12).
    
    2.2 If you want a different/custom design, create your own artwork
        and LightningData.slk. Then configure BAR_ID based on your
        values in LightningData.slk. Make sure the texture you create 
        is white-filled color for you to change the color.
       
    Read more here on how to customize lightning effects so you can
    make your own design for a CastBar.
       
    http://www.hiveworkshop.com/forums/general-mapping-tutorials-278/how-customise-lightning-effects-203171/
       
    3. Configure and read the API provided.
    
*/  
    globals
    //CONFIGURATION
        //Initial Height of created CastBars
        private constant real DEFAULT_HEIGHT = 50.0
        //Initial Height of created CastBars attached to unit
        private constant real DEFAULT_HEIGHT_IN_UNIT = 150.0
        //The size of the floating text in the center of the CastBar
        private constant real DEFAULT_TEXT_SIZE = 0.025
        //The visual appearance of the CastBar
        private constant string BAR_ID = "CBAR"
        
    //--------------------- SET THE COLOR OF THE CAST BAR ------------------
        //Set the default color of the Cast Bar. Value is between 0 and 1
        //In this current setting, CastBars will have a green color by default
        
        //RGB of empty CastBar
        private constant real EMPTY_RED = 0.5
        private constant real EMPTY_GREEN = 0
        private constant real EMPTY_BLUE = 0
        //RGB of full CastBar by default
        private constant real FULL_RED = 0
        private constant real FULL_GREEN = 1
        private constant real FULL_BLUE = 0
    
    //--------------------- SET THE TEXT COLOR OF THE CAST BAR ----------------
        //Determines the defualt initial and final color of the CastBar's text
        //In this current setting, text colors will start in fully red color and end up
        //in fully green color. Value is between 0 and 255.
        private constant integer TEXT_RED1 = 255
        private constant integer TEXT_GREEN1 = 0
        private constant integer TEXT_BLUE1 = 0
        private constant integer TEXT_RED2 = 0
        private constant integer TEXT_GREEN2 = 255 
        private constant integer TEXT_BLUE2 = 0
    endglobals
/*
        
==========================   Application Program Interface:   ===========================

------------------------------------CREATE CASTBAR------------------------------------
    CREATE CASTBAR INPUT ARGUMENTS
    - real time: How long the CastBar will last.
    - real barLength: The horizontal length of the CastBar.
    - string whichName: The name in the center of the CastBar
    - boolean emptyToFull: Determines the direction flow of the CastBar. If set to true, the
        CastBar will start empty and fills as time goes. Setting it to false result to
        opposite effect.
    - boolean visibleInFog: Determines when the CastBar can be seen through Fog and BlackMask

* function CreateCastBarAtPos takes real x, real y, real time, real barLength, 
  string whichName, boolean emptyToFull, boolean visibileInFog returns CastBar
    - Create a CastBar at a certain position by specifiying the x and y coordinate.

* function CreateCastBarAtLoc takes location l, real time, real barLength, 
  string whichName, boolean emptyToFull, boolean visibileInFog returns CastBar
    - Create a CastBar at a certain location.
    
* function CreateCastBarAtUnit takes unit whichUnit, real time, real barLength, 
  string whichName, boolean emptyToFull, boolean visibileInFog returns CastBar
    - Create a CastBar attached to a unit. The CastBar will follow the unit.
    
* function CreateCastBarAtPlayer takes player whichPlayer, real cameraOffset, real time, 
  real barLength, string whichName, boolean emptyToFull, boolean visibileInFog returns CastBar
    - Create a CastBar attached to a player's camera. The CastBar will follow the camera of the player.
      The cameraOffset determines the position of the CastBar relative to the center of the camera.
      CastBar created through this function is only visible to the player.
-------------------------------------------------------------------------------------------------
    
* function DestroyCastBar takes CastBar cb returns nothing
    - Destroy a CastBar. Note that expiring CastBar are automatically destroyed.

* function CastBarDetach takes CastBar cb, unit whichUnit returns nothing
    - Detach a CastBar from a unit so that the CastBar will no longer follow the unit.
    
* function CastBarMove takes CastBar cb, real x, real y returns nothing
    - Move a CastBar to a certain position. Does not work if the CastBar is attached to a unit.

* function CastBarReset takes CastBar cb returns nothing
    - Reset the timer of a CastBar. Also caused the CastBar to be unpaused.

* function CastBarShowText takes CastBar cb, boolean flag returns nothing
    - Modifies the visibility of the CastBar text. Works in local blocks and can be used
      with GetLocalPlayer()
    
* function CastBarShow takes CastBar cb, boolean flag returns nothing
    - Modifies the visibility of a CastBar. Works in local blocks and can be used with 
      GetLocalPlayer(). This also modifies the visibility of the CastBar text.
     
* function CastBarPause takes CastBar cb, boolean flag returns boolean
    - Pause/Unpause the timer of the CastBar.

* function SetCastBarTime takes CastBar cb, real newTime returns nothing
    - Set the time remaining in a CastBar
    
* function SetCastBarPercent takes CastBar cb, real percentage returns nothing
    - Set the percentage completion in a CastBar. Setting it to 0 resets the CastBar.
      Setting it to 1 completes the CastBar.

* function SetCastBarHeight takes CastBar cb, real newHeight returns nothing
    - Set the height of a CastBar relative from the ground.
    
* function SetCastBarDisplayPercent takes CastBar cb, boolean flag returns nothing
    - Determines whether the text in the CastBar is displayed as percentage
      or actual value.
    
* function SetCastBarTextSize takes CastBar cb, real newSize returns nothing
    - Set the texttag size of the name and value of the CastBar.
    
* function SetCastBarColor takes CastBar cb, real red, real green, real blue, real alpha returns nothing
    - Set the filled-CastBar color

* function SetCastBarColorChange takes CastBar cb, integer red1, integer green1, integer blue1, 
  integer red2, integer green2, integer blue2 returns nothing
    - Set the initial and final text color of the CastBar. The text color will change
      proportional to the percent completion.
    
* function SetCastBarInitialTime takes CastBar cb, real newInitTime returns nothing
    - Change the initial time of a CastBar.
    
* function GetCastBarName takes CastBar cb returns string
    - Returns the name of a CastBar.

* function GetCastBarUnit takes CastBar cb returns unit
    - Returns the unit where the CastBar is attached.

* function GetCastBarX takes CastBar cb returns real
    - Returns the x-coordinate of a CastBar.

* function GetCastBarY takes CastBar cb returns real
    - Returns the y-coordinate of a CastBar.

* function GetExpiringCastBar takes nothing returns CastBar
    - Returns the expiring CastBar in the Event: Game - CastBar_Expires becomes Equal to 1.00

*/    
    globals
        //SYSTEM VARIABLES
        private constant real TIMEOUT = 0.03125000  
        private timer periodic = CreateTimer()
        private CastBar expire
        private CastBar lastCreated
        private location l = Location(0, 0)
    endglobals
    
    struct CastBar
        
        unit u              //The unit the CastBar is attached if any
        boolean paused      //Determines whether a CastBar is paused or not
        real t              //The current time left in the CastBar
        real t0             //The initial time
        real height         //CastBar Height
        player p            //The player whose camera the CastBar is attached
        real yOffset        //How much below the CastBar from the center of camera
        real textSize       //Size of the texttag in the CastBar
        texttag text
        //--- CAST BAR COLOR
        real er
        real eg
        real eb
        real ea
        real fr
        real fg
        real fb
        real fa
        //--- TEXT COLOR CHANGE ---
        integer tr1
        integer tg1
        integer tb1
        integer tr2
        integer tg2
        integer tb2
        //--------------------
        real nameOffset     //x-offset of the string name, to make it appear in the middle
        boolean textInValue //If true, the texttag in the CastBar dispays the actual value
                            //If false, the texttag in the CastBar dispays the percentage
        
        readonly real x              //CastBar X Location
        readonly real y              //CastBar Y Location
        readonly string name         //The name of the castbar
        readonly boolean startEmpty  //If true, the cast bar will start empty and fills as time goes
        readonly lightning fullBar
        readonly lightning emptyBar
        
        private real length             //The length of the CastBar
        private boolean checkVisibility 
        
        private static integer array next
        private static integer array prev
        
        
        method destroy takes nothing returns nothing
            //Remove from the List
            set next[prev[this]] = next[this]
            set prev[next[this]] = prev[this]
            //Timer
            if next[0] == 0 then
                call PauseTimer(periodic)
            endif
            //Clean Handles
            call DestroyLightning(.fullBar)
            call DestroyLightning(.emptyBar)
            if .text != null then
                call DestroyTextTag(.text)
                 set .text = null
            endif
            //Clean References
            set .u = null
            set .p = null
            set .fullBar = null
            set .emptyBar = null
            call deallocate()
        endmethod
        
        method move takes real xPos, real yPos returns real
            local real xOffset = 0.5*.length
            local real xMin = xPos - xOffset
            local real xMax = xPos + xOffset
            local real percent = .t/.t0
            local real xMid
            local real zBar = .height
            local real zText = .height - 5

            if .startEmpty then
                set xMid = xMax - (xMax - xMin)*percent
            else
                set xMid = xMin + (xMax - xMin)*percent
            endif
            if .u != null then
                call MoveLocation(l, xPos, yPos)
                set zBar = zBar + GetLocationZ(l)
            elseif .p != null then
                call MoveLocation(l, xPos, yPos)
                set zText = zText - GetLocationZ(l)
            endif
            if .checkVisibility then
                if IsVisibleToPlayer(xPos, yPos, GetLocalPlayer()) then
                    call SetLightningColor(.emptyBar, .er, .eg, .eb, .ea)
                    call SetLightningColor(.fullBar, .fr, .fg, .fb, .fa)
                else
                    call SetLightningColor(.fullBar, 0, 0, 0, 0)
                    call SetLightningColor(.emptyBar, 0, 0, 0, 0)
                endif
            endif
            call MoveLightningEx(.emptyBar, .checkVisibility, xMin, yPos, zBar, xMax, yPos, zBar)
            call MoveLightningEx(.fullBar, .checkVisibility, xMin, yPos, zBar, xMid, yPos, zBar)
            call SetTextTagPos(.text, xPos - .nameOffset, yPos, zText)
            set .x = xPos
            set .y = yPos
            return percent
        endmethod
        
        private method update takes nothing returns nothing
            local real percent
            //If CastBar is paused and attached,
            //still update position
            if .paused then
                if .u != null then
                    call move(GetUnitX(.u), GetUnitY(.u))
                elseif .p != null then
                    call move(GetCameraTargetPositionX(), GetCameraTargetPositionY() + .yOffset)
                endif
            else
                set .t = .t - TIMEOUT
                if .t > 0 then
                    if .u != null then
                        set percent = move(GetUnitX(.u), GetUnitY(.u))
                    elseif .p != null then
                        set percent = move(GetCameraTargetPositionX(), GetCameraTargetPositionY() + .yOffset)
                    else
                        set percent = move(.x, .y)
                    endif
                    if .textInValue then
                        call SetTextTagText(.text, .name + ": " + R2S(.t), .textSize)
                    else
                        call SetTextTagText(.text, .name + ": " + I2S(R2I(percent*100)), .textSize)
                    endif
                    set percent = 1 - percent
                    call SetTextTagColor(.text, R2I((.tr2 - .tr1)*percent + .tr1), R2I((.tg2 - .tg1)*percent + .tg1), R2I((.tb2 - .tb1)*percent + .tb1), 255)
                else
                    set expire = this
                    set udg_CastBar_Expires = 1.00
                    set udg_CastBar_Expires = 0.00
                    call destroy()
                endif
            endif
        endmethod
        
        private static method pickAll takes nothing returns nothing
            local thistype this = next[0]
            loop
                exitwhen this == 0
                call update()
                set this = next[this]
            endloop
        endmethod
        
        static method create takes real time, real barLength, string whichName, boolean emptyToFull, boolean visibileInFog returns thistype
            local thistype this = allocate()
            
            set .t0 = time
            set .t = time
            set .length = barLength
            set .name = whichName
            set .startEmpty = emptyToFull
            set .checkVisibility = not visibileInFog
            set .paused = false
            set .height = DEFAULT_HEIGHT
            set .textSize = DEFAULT_TEXT_SIZE
            set .textInValue = true
            set .nameOffset = I2R(StringLength(whichName) + 5)/(8*DEFAULT_TEXT_SIZE)
            set .emptyBar = AddLightning(BAR_ID, .checkVisibility, 0, 0, 0, 0)
            set .fullBar = AddLightning(BAR_ID, .checkVisibility, 0, 0, 0, 0)
            set .text = CreateTextTag()
            
            //CastBar Color
            set .er = EMPTY_RED
            set .eg = EMPTY_GREEN
            set .eb = EMPTY_BLUE
            set .ea = 1
            set .fr = FULL_RED
            set .fg = FULL_GREEN
            set .fb = FULL_BLUE
            set .fa = 1
            
            call SetLightningColor(.emptyBar, .er, .eg, .eb, .ea)
            call SetLightningColor(.fullBar, .fr, .fg, .fb, .fa)
            
            //Text Color Change
            set tr1 = TEXT_RED1
            set tg1 = TEXT_GREEN1
            set tb1 = TEXT_BLUE1
            set tr2 = TEXT_RED2
            set tg2 = TEXT_GREEN2
            set tb2 = TEXT_BLUE2
            
            call SetTextTagText(.text, .name + ": " + R2S(.t), DEFAULT_TEXT_SIZE)
            call SetTextTagColor(.text, .tr1, .tg1, .tb1, 255)
            
            //Insert in the list
            set next[this] = 0
            set prev[this] = prev[0]
            set next[prev[this]] = this
            set prev[0] = this
            
            if prev[this] == 0 then
                call TimerStart(periodic, TIMEOUT, true, function thistype.pickAll)
            endif
            
            return this
        endmethod
        
    endstruct
    
    //-------------------  WRAPPER FUNCTIONS  ----------------------------
    // You may end up not using these if you know how to use structs
    
    function CreateCastBarAtPos takes real x, real y, real time, real barLength, string whichName, boolean emptyToFull, boolean visibileInFog returns CastBar
        local CastBar cb = CastBar.create(time, barLength, whichName, emptyToFull, visibileInFog)
        call cb.move(x, y)
        set lastCreated = cb
        return cb
    endfunction
    
    function CreateCastBarAtLoc takes location l, real time, real barLength, string whichName, boolean emptyToFull, boolean visibileInFog returns CastBar
        local CastBar cb = CastBar.create(time, barLength, whichName, emptyToFull, visibileInFog)
        call cb.move(GetLocationX(l), GetLocationY(l))
        set lastCreated = cb
        return cb
    endfunction
    
    function CreateCastBarAtUnit takes unit whichUnit, real time, real barLength, string whichName, boolean emptyToFull, boolean visibileInFog returns CastBar
        local CastBar cb = CastBar.create(time, barLength, whichName, emptyToFull, visibileInFog)
        set cb.u = whichUnit
        set cb.height = DEFAULT_HEIGHT_IN_UNIT
        set lastCreated = cb
        return cb
    endfunction
    
    function CreateCastBarAtPlayer takes player whichPlayer, real cameraOffset, real time, real barLength, string whichName, boolean emptyToFull, boolean visibileInFog returns CastBar
        local CastBar cb = CastBar.create(time, barLength, whichName, emptyToFull, visibileInFog)
        set cb.p = whichPlayer
        set cb.yOffset = cameraOffset
        if GetLocalPlayer() != whichPlayer then
            call DestroyTextTag(cb.text)
            set cb.text = null
        endif
        set lastCreated = cb
        return cb
    endfunction

    function DestroyCastBar takes CastBar cb returns nothing
        call cb.destroy()
    endfunction
    
    function CastBarDetach takes CastBar cb returns nothing
        set cb.u = null
    endfunction
    
    function CastBarMove takes CastBar cb, real x, real y returns nothing
        call cb.move(x, y)
    endfunction
    
    function CastBarReset takes CastBar cb returns nothing
        set cb.t = cb.t0
        set cb.paused = false
    endfunction
    
    function CastBarShowText takes CastBar cb, boolean flag returns nothing
        call SetTextTagVisibility(cb.text, flag)
    endfunction
    
    function CastBarShow takes CastBar cb, boolean flag returns nothing
        if flag then
            call SetLightningColor(cb.emptyBar, cb.er, cb.eg, cb.eb, cb.ea)
            call SetLightningColor(cb.fullBar, cb.fr, cb.fg, cb.fb, cb.fa)
        else
            call SetLightningColor(cb.fullBar, 0, 0, 0, 0)
            call SetLightningColor(cb.emptyBar, 0, 0, 0, 0)
        endif
        call SetTextTagVisibility(cb.text, flag)
    endfunction
    
    function CastBarPause takes CastBar cb, boolean flag returns nothing
        set cb.paused = flag
    endfunction
    
    function SetCastBarTime takes CastBar cb, real newTime returns nothing
        local real percent
        if newTime > cb.t0 then
            set cb.t = cb.t0
        else
            set cb.t = newTime
        endif
        set percent = cb.t/cb.t0
        if cb.textInValue then
            call SetTextTagText(cb.text, cb.name + ": " + R2S(cb.t), cb.textSize)
        else
            call SetTextTagText(cb.text, cb.name + ": " + I2S(R2I(percent*100)), cb.textSize)
        endif
        set percent = 1 - percent
        call SetTextTagColor(cb.text, R2I((cb.tr2 - cb.tr1)*percent + cb.tr1), R2I((cb.tg2 - cb.tg1)*percent + cb.tg1), R2I((cb.tb2 - cb.tb1)*percent + cb.tb1), 255)
    endfunction
    
    function SetCastBarPercent takes CastBar cb, real percent returns nothing
        if percent > 1 then
            set cb.t = cb.t0
            call SetTextTagColor(cb.text, cb.tr2, cb.tg2, cb.tb2, 255)
        else
            set percent = 1 - percent
            set cb.t = cb.t0*percent
            call SetTextTagColor(cb.text, R2I((cb.tr2 - cb.tr1)*percent + cb.tr1), R2I((cb.tg2 - cb.tg1)*percent + cb.tg1), R2I((cb.tb2 - cb.tb1)*percent + cb.tb1), 255)
            set percent = 1 - percent
        endif
        if cb.textInValue then
            call SetTextTagText(cb.text, cb.name + ": " + R2S(cb.t), cb.textSize)
        else
            call SetTextTagText(cb.text, cb.name + ": " + I2S(R2I(percent*100)), cb.textSize)
        endif
    endfunction
    
    function SetCastBarHeight takes CastBar cb, real newHeight returns nothing
        set cb.height = newHeight
    endfunction
    
    function SetCastBarTextSize takes CastBar cb, real newSize returns nothing
        local real percent = cb.t/cb.t0
        set cb.textSize = newSize
        set cb.nameOffset = I2R(StringLength(cb.name) + 5)/(8*newSize)
        call cb.move(cb.x, cb.y)
        if cb.textInValue then
            call SetTextTagText(cb.text, cb.name + ": " + R2S(cb.t), cb.textSize)
        else
            call SetTextTagText(cb.text, cb.name + ": " + I2S(R2I(percent*100)), cb.textSize)
        endif
        set percent = 1 - percent
        call SetTextTagColor(cb.text, R2I((cb.tr2 - cb.tr1)*percent + cb.tr1), R2I((cb.tg2 - cb.tg1)*percent + cb.tg1), R2I((cb.tb2 - cb.tb1)*percent + cb.tb1), 255)
    endfunction
    
    function SetCastBarDisplayPercent takes CastBar cb, boolean flag returns nothing
        set cb.textInValue = not flag
    endfunction
    
    function SetCastBarColor takes CastBar cb, real red, real green, real blue, real alpha returns nothing
        set cb.fr = red
        set cb.fg = green
        set cb.fb = blue
        set cb.fa = alpha
        call SetLightningColor(cb.emptyBar, cb.er, cb.eg, cb.eb, cb.ea)
        call SetLightningColor(cb.fullBar, cb.fr, cb.fg, cb.fb, cb.fa)
    endfunction
    
    function SetCastBarColorChange takes CastBar cb, integer red1, integer green1, integer blue1, integer red2, integer green2, integer blue2 returns nothing
        set cb.tr1 = red1
        set cb.tg1 = green1
        set cb.tb1 = blue1
        set cb.tr2 = red2
        set cb.tg2 = green2
        set cb.tb2 = blue2
    endfunction
    
    function SetCastBarInitialTime takes CastBar cb, real newInitTime returns nothing
        set cb.t0 = newInitTime
    endfunction
    
    function GetCastBarName takes CastBar cb returns string
        return cb.name
    endfunction
    
    function GetCastBarUnit takes CastBar cb returns unit
        return cb.u
    endfunction
    
    function GetCastBarX takes CastBar cb returns real
        return cb.x
    endfunction
    
    function GetCastBarY takes CastBar cb returns real
        return cb.y
    endfunction
    
    function GetExpiringCastBar takes nothing returns CastBar
        return expire
    endfunction
    
    function GetLastCreatedCastBar takes nothing returns CastBar
        return lastCreated
    endfunction

endlibrary

For Demo triggers and how it was used, click here to see the whole triggers without downloading.


Changelog:
v1.00 (15 November 2015)
- Initial Release.

v1.10 (17 Novermber 2015)
- Fixed a bug in SetCastBarTime.
- Fixed the inconsistent position of CastBar on different terrain height.
- Fixed CastBar fog visibility issue.
- Added a function that display the texttag whether in value or percent.
- Added a function that change the texttag size of a CastBar.
- Added a function thato control the initial and final color of the CastBar text.
- Added a function that returns the unit where the CastBar is attached.
- Added a function that show/hide the texttag of a CastBar.
- Added a function that changes the initial time of a CastBar.
- Added a Demo where the CastBars are used as Manabars.
- Wrapper functions moved so that it compiles into function calls instead of trigger evaluations.
- Removed unused local variables and input arguments in the scripting.
- Locally destroy texttags in other players when the CastBar is attached to a Player Camera.
- Changed the linked list structure.
- CastBarPause no longer returns a value.

v1.11 (3 December 2015)
- Optimized the scripting
- Fullbar now overlaps the Emptybar to make it more appealing.
- Fixed a mistake in the manabar demo.

v1.12 (6 December 2015)
- Added a function that allows you to edit the color of the CastBar.
- The system now only uses 1 texture and relies on color change to distinguish empty bar and full bar.

Keywords:
CastBar, Cast, Bar, Time, Text
Contents

CastBarSystem (Map)

Reviews
16:22, 8th Dec 2015 IcemanBo: Good system. http://www.hiveworkshop.com/forums/spells-569/castbarsystem-v1-12-a-272512/index2.html#post2764646
Level 22
Joined
Feb 6, 2014
Messages
2,466
I forgot to test desync issues. Sorry moderators.

Known Issue:
- When the CastBar is attached to the Player's Camera, it can get left behind when the Player pans the camera too fast.
 

Attachments

  • CastBar System.gif
    CastBar System.gif
    1.3 MB · Views: 298
  • CastBarSystem.gif
    CastBarSystem.gif
    5.7 MB · Views: 314
Last edited:
Level 19
Joined
Mar 18, 2012
Messages
1,716
We have tons of bar Systems. ( over 7 ) I have to compare them with to this one.

Anyway thx for the submission. :)

Edit: The demo is interesting. Please add a message at map init that the tests can be run via num 1-9.
I had to check the code, to see how to test the system.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
This one uses lightning effects so it can be visible in fog/black mask. And also allows users to easily create their own design for the castbar because it uses lightning effects.

EDIT:
Edit: The demo is interesting. Please add a message at map init that the tests can be run via num 1-9.
I had to check the code, to see how to test the system.

Will do in the next update. I have a feeling I missed something so there is a high chance that I will update it.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Please move the struct to above the wrapper functions. That may look good for the user to see the API, but it compiles into duplicate code and trigger evaluations instead of function calls.

Do normal structs allow you to override the .destroy() method? I recall a point in the past where that was a syntax error and you had to use onDestroy. If it only works with Cohadar's JH, for example, it needs to be stated in the description.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Source: Jasshelper
Since 0.9.Z.1 you may also override the destroy method by declaring your own one. Then use deallocate to call the normal destroy method.

I took a quick look into your code:

1. In method move, local real x/y can be replaced by xPos/yPos. You allocate two useless locals here.

2. My personal opinion about wrapper functions: they are often useless. I only implement them,
if I wish to add a 100% fail safe API. Like Blizzard tried to do with their BJs.
Other moderators may disagree with me. Rate it as my personal opinion.
I think those who use .move within are useful ( does more then just calling the respective the struct method ).
The rest ( like DestroyCastBar(cb) ) can be removed.

3. Texttag handle count is limited to 100, but can increase to 100*player count if created locally.
Create them locally if they are meant to be shown for a local client. Maybe your create method should
take a player argument. player == null means for everyone, else create a local texttag.

4. A linked list is the correct data structure, because you fire events, hence the allocation order shouldn't shuffle on destroy ( a stack would do that ).
But I would do it like presented here ( link ), because then you don't need to create a head node.
Also you don't run into issues with module initializer and compile order.

5. Some of your struct members can be set. Their names should be more generic
- unit u --> unit target
- real t --> real time
- player p --> player user ( I'm also ok with player p )

6. Why does function Detach take a unit argument?

7. I don't get the purpose of returned boolean in CastBarPause. It's also incorrect.

8. I didn't test it, but I guess you have to take the terrain z into account, when updating your lightnings.
 
Last edited:
Level 22
Joined
Feb 6, 2014
Messages
2,466
Please move the struct to above the wrapper functions. That may look good for the user to see the API, but it compiles into duplicate code and trigger evaluations instead of function calls.

Got it.

1. In method move, local real x/y can be replaced by xPos/yPos. You allocate two useless locals here.
1. Right, totally missed that one.

2. My personal opinion about wrapper functions: they are often useless. I only implement them,
if I wish to add a 100% fail safe API. Like Blizzard tried to do with their BJs.
Other moderators may disagree with me. Rate it as my personal opinion.
I think those who use .move within are useful ( does more then just calling the respective the struct method ).
The rest ( like DestroyCastBar(cb) ) can be removed.
2. Some people only know JASS not vJASS, that's why I made the wrapper function. It's to make it user-friendly and the skill required to use this the same level as a user who know how to remove leaks.

3. Texttag handle count is limited to 100, but can increase to 100*player count if created locally.
Create them locally if they are meant to be shown for a local client. Maybe your create method should
take a player argument. player == null means for everyone, else create a local texttag.
3. Ok, I will only create the texttag locally if the castbar is attached to a player camera.

4. A linked list is the correct data structure, because you fire events, hence the allocation order shouldn't shuffle on destroy ( a stack would do that ).
But I would do it like presented here ( link ), because then you don't need to create a head node.
Also you don't run into issues with module initializer and compile order.
4. Ok, I will learn the better way in creating linked list.

5. Some of your struct members can be set. Their names should be more generic
- unit u --> unit target
- real t --> real time
- player p --> player user ( I'm also ok with player p )
5. It seems fine to me in my opinion.

6. Why does function Detach take a unit argument?
6. Fair enough, I will remove the unit argument.

7. I don't get the purpose of returned boolean in CastBarPause. It's also incorrect.
7. It returns whether a castbar is paused or not before applying the effect. But I realize it is useless so I will remove that.

8. I didn't test it, but I guess you have to take the terrain z into account, when updating your lightnings.
8. Ok, I forgot that the z in lightning refers to absolute z, not relative z from the ground.

Sorry for having a lot of issues, I was in a rushed when I submitted it.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
I kind of dislike the lightning method because of that there are limited lightning models in one map... afaik.

This is also much easier done with a model and animation speed so you can do it without a loop at all.

However, it looks nice.
It is not bad to use.
Well done SF.

We have tons of bar Systems. ( over 7 ) I have to compare them with to this one.
Yet no lightweight working health bar system.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
I kind of dislike the lightning method because of that there are limited lightning models in one map... afaik.

This is also much easier done with a model and animation speed so you can do it without a loop all.

I didn't know there is a limit. But this just add 2 additional lightning which I think isn't much. How much is the limit?

I agree that using a model CastBar, you don't have to loop. But if you would attach that CastBar to a unit, you'll eventually loop. Plus, unit CastBar is not visible in fog and you can't set the current percent completion of a unit CastBar instantly. You also can't reverse it. And by using lightning, users can actually make their own design for the CastBar. Anyway, thanks for the feedback.

The update is coming soon, I was just a little busy yesterday.
 

Zwiebelchen

Hosted Project GR
Level 35
Joined
Sep 17, 2009
Messages
7,236
Even if this doesn't desync: there is the problem that GetCameraTarget updates much slower in multiplayer than it does in singleplayer.
Your bar will probably "lag" quite a bit when the player is moving the camera.

However, you can probably fix that by interpolating x and y values between two GetCameraTargetPosition() updates.

To do that, simply store the last X and Y value retrieved and compare it with the result of GetCameraTargetPosition(). If the value changed (and is within a certain sanity treshold in case a player clicks the minimap or a camera is applied instantly), then you can calculate the time between the two values changes and use that to calculate an X and Y velocity to offset your "virtual" GetCameraTarget inbetween two actual return values.

I highly recommend doing that. It will "smooth out" the movement of your bar when the camera is swayed by the player.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Even if this doesn't desync: there is the problem that GetCameraTarget updates much slower in multiplayer than it does in singleplayer.
Your bar will probably "lag" quite a bit when the player is moving the camera.

However, you can probably fix that by interpolating x and y values between two GetCameraTargetPosition() updates.

To do that, simply store the last X and Y value retrieved and compare it with the result of GetCameraTargetPosition(). If the value changed (and is within a certain sanity treshold in case a player clicks the minimap or a camera is applied instantly), then you can calculate the time between the two values changes and use that to calculate an X and Y velocity to offset your "virtual" GetCameraTarget inbetween two actual return values.

I highly recommend doing that. It will "smooth out" the movement of your bar when the camera is swayed by the player.

Good suggestion, I like it and I will get right on it. Something interesting to do here.
That was actually the issue of this resource (as seen in the first post) but I thought it doesn't matter much since moderators didn't suggest it.
 
Do you need all these members public if there is an API for them?
On destroy the unit is not nulled, which should be, even it might not be set.

I can imagine CastBars are mostly used attched on units.
Currently there is need of a loop to find maching Bar for a unit.
Directly attaching a Bar to a unit might make sense here. (hashtable, Indexer)

The demo is really very good. I like the system much.
The new visuals of the empty mana bar looks like 5x better than before.

Why method move is public? It should be private as there exists a wrapper.

If I attach a Bar:
1) To a unit
and later
2) To a player
it won't wotk

because user has manualy to detach the bar from unit first so it can be used.
Maybe when setting to player, the bar.targetUnit can just be set to "null" because of comfort.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Do you need all these members public if there is an API for them?
So the wrapper functions can access them.

On destroy the unit is not nulled, which should be, even it might not be set.
It is nulled.
JASS:
//Clean References
set .u = null
set .p = null
set .fullBar = null
set .emptyBar = null
call deallocate()

I can imagine CastBars are mostly used attched on units.
Currently there is need of a loop to find maching Bar for a unit.
Directly attaching a Bar to a unit might make sense here. (hashtable, Indexer)
I thought about that also, but in this system, you can actually attach more than one CastBar on a unit, so I can't really have something like GetAttachedCastBar(unit).

Why method move is public? It should be private as there exists a wrapper.
Again, because it is used in the wrapper functions. When I made them private, the wrapper functions won't have access to them anymore.

If I attach a Bar:
1) To a unit
and later
2) To a player
it won't wotk

because user has manualy to detach the bar from unit first so it can be used.
Maybe when setting to player, the bar.targetUnit can just be set to "null" because of comfort.
Uhmm, there is no function that will attach a CastBar to a player, only create a CastBar to a player.
 
I missed the fact that API is outside the struct,
and seems also I didn't recognize the reference clean ups.
It is totaly fine for me, too, if you prefer outside functions.
I personaly also sometimes prefer it.

Uhmm, there is no function that will attach a CastBar to a player, only create a CastBar to a player.
Where is the difference here for you? You create and attach it to the player.
I don't know if only don't like the word I used or I am wrong,
but I thought my question was understandable.

Anyway user has possiblity to do it manualy so I it remains only as suggestion.

Btw, texttags don't necessarily need to be nulled.

you can actually attach more than one CastBar on a unit
I am aware of that, but I people will mostly use it for units.

From my personal taste I would enjoy to have it more (v-)JASS friedlier than GUI friendly but all works fine.
And I love the result of the system.

Approved
 
Level 3
Joined
Dec 8, 2013
Messages
51
Create a CastBar and change the color locally (using GetLocalPlayer())
Example:
JASS:
local CastBar cb = CreateCastBarAtPos(...)
if GetLocalPlayer() != yourPlayer then
    //Make the CastBar transparent
    call SetCastBarColor(cb, 0, 0, 0, 0)
endif
Much thanks!
 
Level 3
Joined
Dec 8, 2013
Messages
51
Create a CastBar and change the color locally (using GetLocalPlayer())
Example:
JASS:
local CastBar cb = CreateCastBarAtPos(...)
if GetLocalPlayer() != yourPlayer then
    //Make the CastBar transparent
    call SetCastBarColor(cb, 0, 0, 0, 0)
endif
I finally tested it, and it only hides the empty-to-full bar effect, not the whole bar.
I also tried CastBarShow, but it doesnt work at all.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
I finally tested it, and it only hides the empty-to-full bar effect, not the whole bar.
I also tried CastBarShow, but it doesnt work at all.
Ignore my last suggestion, I forgot I created an API for the actual visibility. You should use CastBarShow, I just tested it and it works.
JASS:
local CastBar cb = CreateCastBarAtPos(...)
if GetLocalPlayer() != yourPlayer then
    //Hide the CastBar if local is not your player
    call CastBarShow(cb, false)
endif
 
Level 3
Joined
Dec 8, 2013
Messages
51
Ignore my last suggestion, I forgot I created an API for the actual visibility. You should use CastBarShow, I just tested it and it works.
JASS:
local CastBar cb = CreateCastBarAtPos(...)
if GetLocalPlayer() != yourPlayer then
    //Hide the CastBar if local is not your player
    call CastBarShow(cb, false)
endif
Hm, man but why do I still see the bar? I go GetLocalPlayer() != Player(1) ( I am playing player 0 so the bar should not work for me ), but the bar is still visible.
 
Level 3
Joined
Dec 8, 2013
Messages
51
Perhaps you're referencing the wrong CastBar?

I attached the map I tested on, look at CastBar at Pos trigger (when "1" is typed in chat).
I can't see the CastBar but when I changed it to Player(0), it is now visible.
Well, I ve got one assumption. Seems like visibileInFog condition might conflict with local player vision.
But I probably resolved the main problem, so thx mate ;)
 
Level 8
Joined
May 24, 2016
Messages
296
I implemented this system into my map, thx and credit to u Flux. But during my singleplayer test it once bugged, giving me an error and lowering fps to 10-15. So bad I didnt screen, but this definitely need to be screened next time.
 
Level 7
Joined
Sep 27, 2016
Messages
68
sir.. as i know, in warcraft 1.32 ,, the imported textures/materials/skins with original path are cannot be read in the game, the game is always use in-game textures instead the imported ones.. can you uses a new different path instead the original path?
 
Top