System Floating Bars

Discussion in 'Systems and Snippets' started by Steel, Feb 21, 2008.

  1. Steel

    Steel Software Engineer

    Ratings:
    +109 / 0 / -0
    Version History:
    Version 2.4:
    -Greatly Simplified Code
    -Fixed a string concatenation issue causing the system to crash

    Version 2.3:
    -Better map cleanup
    -Better unit indexation
    -Added in function RemoveBarUnit
    -Modified existing functions for better leak / crash protection
    -Split Gradient functions and Floating Bars into separate libraries
    -Speed optimized

    Version 2.2:
    -Map properly cleans memory leaks.
    -Mana bar properly disappears.
    -Changed the syntax for AddBar, it takes in a boolean now. Example: call AddBar(u, true). The boolean of true or false tells the function if we want the mana bar added or not.
    -Combined the Config trigger with the globals with the main structure of the system
    Version 2.1:
    -Map now tracks mana.
    Version 2.0:
    -Initial Release



    FAQ
    Q: Can this work for heroes/specific units exclusively?
    A: Yes! You as the user determine which units have the bars above them. Please read the How to Use section below. It will be very useful.

    Q: What is use? The game can have health bars already!
    A: This was originally designed to show the HP bar without having to hold alt. The WC3 Engine now supports showing the health bar forever, but my system now also shows mana above the unit. You also are not required to have both the health and mana bar, you can have just the mana bar shown without the health. It's up to you.

    Q: How does it work?
    A: This system uses the ability of structs to house information. The older system used handles which made it very slow. This new system is much faster since it uses globals. The system doesn't use multiple timers to track each texttag, this is highly inefficient and extremely slow. The system uses 1 timer that traverses over every unit in the array and updates the texttags this way.


    Requirements
    -vJASS

    Implementation
    Step 1a - Copy the Category Floating Bars
    Step 1b - Paste what you just copied into your map
    Step 1c - Save your Map, any compile errors mean that you have pasted improperly or you do not use vJASS

    Advanced Users Only
    Step 2a - You can change the variables in the Configurables if you know how they will react


    Functions to Use:
    You should only ever use the following 2 functions
    Basic Users:
    AddBar(u, life, mana)
    RemoveBarUnit(u)


    Advanced Users:
    function Addbar takes unit u, boolean life, boolean mana returns nothing
    function RemoveBarUnit takes unit u returns boolean //If boolean returns false, unit is not found and it has no bars on it.

    AddBar will create a bar ontop of the unit you deem. The boolean life and mana tell the system what you want to track.
    For example say we just created a unit, you want to track the unit's life and mana you would do this DIRECTLY after you create the unit

    //Track the last created unit's life and mana
    call AddBar(bj_lastCreatedUnit, true, true)

    //Track the last created unit's mana only
    call AddBar(bj_lastCreatedUnit, false, true)

    //Track the last created unit's life only
    call AddBar(bj_lastCreatedUnit, true, false)

    Starting to see the picture?

    Now that you know how to add a bar, let me show you how to Add a bar....lets remove:
    call RemoveBarUnit(GetTriggerUnit())

    Very simple.

    Floating Bars v2.4
    JASS:
    library FloatingBars initializer FloatingInit requires Gradient
    
    globals
    
    //========================================================================
    //**********************    Configurable Settings!                     ********************
    //========================================================================
    
    string DisplayCharacter = "'"   //Character intended for display
    integer BarLength       = 30    //How many DisplayCharacters are used
    real BarSize            = 11.00 //Size of the text
    real XOffSet            = -35.00//Offset over the unit by X
    real YOffSet            = -40.00//Offset over the unit by Y
    real XOffSetM           = -35.  //Offset over the unit by X (Mana version)
    real YOffSetM           = -55.     //Offset over the unit by Y (Mana version)
    real Frequency          = .04   //Recurrence of the timer that tracks the system
    
    //========================================================================
    //**********************DO NOT MODIFY BELOW THIS LINE!********************
    //========================================================================
    
    integer FS_MAX_BARS    = 100
    integer FS_CURR_BARS   = 0
    FloatingStruct array structlink
    integer FS_COUNT = 0
    endglobals
    
    struct FloatingStruct
    unit u
    texttag t
    texttag tm
        static method create takes unit whichUnit, boolean life, boolean mana returns FloatingStruct
            local FloatingStruct fs = FloatingStruct.allocate()
            set fs.u = whichUnit
            if life then
                if FS_CURR_BARS<=100 then
                    set fs.t    = CreateTextTag()
                    set FS_CURR_BARS=FS_CURR_BARS+1
                    call SetTextTagText(fs.t, "|c0000FF00", BarSize * 0.023 / 10)
                    call SetTextTagPos(fs.t,GetUnitX(whichUnit)+XOffSet,GetUnitY(whichUnit)+YOffSet,200)
                    call SetTextTagPermanent(fs.t,true)
                    call SetTextTagColor(fs.t,255,255,255,255)
                    call SetTextTagVisibility(fs.t,IsUnitVisible(fs.u,GetLocalPlayer()))
                debug else
                debug call BJDebugMsg("Text tax limit reached")
                endif
            endif
    
            if ((GetUnitState(whichUnit, UNIT_STATE_MANA)>1) and mana) then
                if FS_CURR_BARS<=100 then           
                    set fs.tm    = CreateTextTag()
                    debug call BJDebugMsg("Text Tag Created")
                    set FS_CURR_BARS=FS_CURR_BARS+1
                    call SetTextTagText(fs.tm, "|c000000FF", BarSize * 0.023 / 10)
                    call SetTextTagPos(fs.tm,GetUnitX(whichUnit)+XOffSetM,GetUnitY(whichUnit)+YOffSetM,200)
                    call SetTextTagPermanent(fs.tm,true)
                    call SetTextTagColor(fs.tm,255,255,255,255)
                    call SetTextTagVisibility(fs.tm,IsUnitVisible(fs.u,GetLocalPlayer()))
                debug else
                debug call BJDebugMsg("Text tax limit reached")
                endif
            endif
            return fs
        endmethod
    
        private method onDestroy takes nothing returns nothing
        set this.u = null
        
        if (not(this.t==null)) then
            call DestroyTextTag(this.t)
            set FS_CURR_BARS=FS_CURR_BARS-1
            set this.t=null
        endif
        
        if (not(this.tm==null)) then
            call DestroyTextTag(this.tm)
            set FS_CURR_BARS=FS_CURR_BARS-1
            set this.tm=null
        endif    
        
        set FS_COUNT=FS_COUNT-1
        endmethod
    endstruct
    
    function RecycleIndex takes integer i returns nothing
    loop
        exitwhen i>FS_COUNT
        set structlink[i]=structlink[i+1]
        set i = i + 1
    endloop
    endfunction
    
    function RemoveBarInt takes integer i returns nothing
    call structlink[i].destroy()
    call RecycleIndex(i)
    endfunction
    
    function FindUnitIndex takes unit u returns integer
    local integer i = 1
    loop
        exitwhen ((i>FS_COUNT) or (structlink[i].u==null))
        if structlink[i].u==u then
            return i
        endif
        set i = i + 1
    endloop
    return -1
    endfunction
    
    function RemoveBarUnit takes unit u returns boolean
    local integer i = FindUnitIndex(u)
    if (i==-1) then
        debug call BJDebugMsg("Error unit not in index")
        return false
    else
        call RemoveBarInt(i)
    endif
    return true
    endfunction
    
    function UpdateBar takes integer in, string barstr, texttag t, unitstate curr, unitstate max returns nothing
        local integer   i       = 0
        local integer   j       = 0
        local boolean   update  = false   
    
            loop
                exitwhen i==BarLength
                if (not update) and (GetUnitState(structlink[in].u, curr) < (i * ((GetUnitState(structlink[in].u, max))/BarLength))+1) then
                    set update = true
                    set barstr = barstr+"|r|cFF000000"
                else
                    set barstr = barstr+DisplayCharacter
                endif
                set i = i + 1
            endloop
            set barstr = barstr+"|r"    
            call SetTextTagText(t, barstr, BarSize * 0.023 / 10)
            call SetTextTagVisibility(t,IsUnitVisible(structlink[in].u,GetLocalPlayer()))
    
    endfunction
    
    function BarTimer takes nothing returns nothing
        local integer i=0
    
        loop
            exitwhen (i>FS_COUNT or structlink[i].u==null)
            if (not(structlink[i].t==null)) then
                call UpdateBar(i,"|c00"+gradientchild(GetUnitState(structlink[i].u, UNIT_STATE_LIFE),GetUnitState(structlink[i].u, UNIT_STATE_MAX_LIFE)), structlink[i].t, UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE)
                call SetTextTagPos(structlink[i].t,GetUnitX(structlink[i].u)+XOffSet,GetUnitY(structlink[i].u)+YOffSet,180)            
                debug else
                debug call BJDebugMsg("structlink[i].t == null")
            endif
            
            
            //Mana        
            if (not(structlink[i].tm==null)) then
                call UpdateBar(i,"|c000000FF", structlink[i].tm, UNIT_STATE_MANA, UNIT_STATE_MAX_MANA)
                call SetTextTagPos(structlink[i].tm,GetUnitX(structlink[i].u)+XOffSetM,GetUnitY(structlink[i].u)+YOffSetM,180)       
                debug else
                debug call BJDebugMsg("structlink[i].tm == null")
            endif      
            
            if GetUnitState(structlink[i].u, UNIT_STATE_LIFE) <= 0 then
            call RemoveBarInt(i)
            endif             
            
            
            set i=i+1        
        endloop 
    endfunction
    
    function AddBar takes unit u, boolean life, boolean mana returns nothing
    if (not(FindUnitIndex(u)==-1)) then
    debug call BJDebugMsg("Error: Duplicate Floating Bar Creation Called")
    return
    endif
    set structlink[FS_COUNT] = FloatingStruct.create(u, life, mana)
    set FS_COUNT = FS_COUNT + 1
    endfunction
    
    function FloatingInit takes nothing returns nothing
    local timer t = CreateTimer()
    set FS_COUNT = 0
    call TimerStart(t,Frequency,true,function BarTimer)
    endfunction
    endlibrary


    Gradient v2.4
    JASS:
    library Gradient
    function s2hex takes string str returns integer
    if (str == "F") then
    return 15
    elseif (str=="E") then
    return 14
    elseif (str=="D") then
    return 13
    elseif (str=="C") then
    return 12
    elseif (str=="B") then
    return 11
    elseif (str=="A") then
    return 10
    endif
    return S2I(str)
    endfunction
    
    function hex2s takes integer i returns string
    if (i == 15) then
    return "F"
    elseif (i==14) then
    return "E"
    elseif (i==13) then
    return "D"
    elseif (i==12) then
    return "C"
    elseif (i==11) then
    return "B"
    elseif (i==10) then
    return "A"
    elseif (i>15) then
    return "F"
    elseif (i<0) then
    return "0"
    endif
    return I2S(i)
    endfunction
    
    function gradient takes string str returns string
    local integer i = 1
    local string r1 = SubString(str,0,1)
    local string r2 = SubString(str,1,2)
    local string g1 = SubString(str,2,3)
    local string g2= SubString(str,3,4)
    local string b1 = SubString(str,4,5)
    local string b2 = SubString(str,5,6)
    local integer x
        set x = s2hex(r1)+2
        set r1 = hex2s(x)
        
        set x = s2hex(r2)+2
        set r2 = hex2s(x)
        
        set x = s2hex(g1)-2
        set g1 = hex2s(x)
        
        set x=s2hex(g2)-2
        set g2 = hex2s(x)  
        set str = r1+r2+g1+g2+b1+b2
    
    return str
    endfunction
    
    function gradientchild takes real curr, real max returns string
    local integer i = 1
    local string str = "00FF00"
    local real percent = (curr/max)*100
    local integer x = R2I((100-percent)/12.5)
            loop
                exitwhen i>x
                set str = gradient(str)
                set i = i +1
            endloop
    return str
    endfunction
    endlibrary

    Screenshot:
    [​IMG]

    Download Me (v2.4)!
    Download Me (v2.3)!
    Download Me (v2.2)!
    Download Me (v2.1)!
    Download Me (v2.0)!
     

    Attached Files:

    • Like Like x 3
  2. Insane!

    Insane! Shh I didn't edit this, go away.

    Ratings:
    +121 / 0 / -0
    Ehh not too usefull, but cool :)
    could you make a version thake floats below there feet?

    and looks like its vjass is it?
     
  3. Steel

    Steel Software Engineer

    Ratings:
    +109 / 0 / -0
    It could float at there feet, configure it. There is an XOffSet and YOffSet that you can change to modify the location of the bar in respect to the unit.

    Yes it is in vJass
     
  4. ~GaLs~

    ~GaLs~ † Ғσſ ŧħə ѕαĸε Φƒ ~Ğ䣚~ †

    Ratings:
    +181 / 0 / -0
    Post the code of FloatingGlobals too?
     
  5. cr4xzZz

    cr4xzZz Also known as azwraith_ftL.

    Ratings:
    +51 / 0 / -0
    >Ehh not too usefull, but cool
    Excuse me? It is useful in my opinion. A lot useful. Many maps need something like this, like DotA for example. +rep for the sys
     
  6. Steel

    Steel Software Engineer

    Ratings:
    +109 / 0 / -0
    Done
     
  7. Vestras

    Vestras Retired

    Ratings:
    +249 / 0 / -0
    It doesn't work.
    It wont go into the map.
     
  8. cr4xzZz

    cr4xzZz Also known as azwraith_ftL.

    Ratings:
    +51 / 0 / -0
    > It wont go into the map.
    Requires NewGen editor. I think he didn't note that in the first post...
     
  9. AceHart

    AceHart Your Friendly Neighborhood Admin

    Ratings:
    +1,489 / 0 / -0
    Does it remove the bar when the unit dies?

    Also, there's a limit of 99 floating texts at once.
     
  10. 0zaru

    0zaru Learning vJASS ;)

    Ratings:
    +60 / 0 / -0
    Not usefull at all but It's nice... but if the limit is too low... :(
     
  11. Steel

    Steel Software Engineer

    Ratings:
    +109 / 0 / -0
    Yup, there is a simple check in there if the unit's current life is 0 it calls the remove function.

    As for 99 floating texts, I think that's actually plenty. Essentially with this system you could use AddBar to whatever unit you would like and not EVERY unit.
     
  12. xfirenzx

    xfirenzx New Member

    Ratings:
    +7 / 0 / -0
    Hey, I just tested this and the mana bar did not disappear. Hopefully you can fix that in future versions because i would really like to use this in my map (I will give credit).
     
  13. Steel

    Steel Software Engineer

    Ratings:
    +109 / 0 / -0
    Fixed in version 2.2

    Moderators: What does this system need to be approved?
     
  14. Cidzero

    Cidzero Imma firin mah lazer!!!1!1

    Ratings:
    +39 / 0 / -0
    They want perfection.

    And very nice, if only I didn't use so many units at the same time I could use :(
     
  15. ~GaLs~

    ~GaLs~ † Ғσſ ŧħə ѕαĸε Φƒ ~Ğ䣚~ †

    Ratings:
    +181 / 0 / -0
    You should really add some debug message as a warning and code to stop the system when the amount of bars is reaching about 80 , to prevent people from extreme usage.

    This system is quite useful for something like, coding a custom barrier, which is completely triggered barrier. It can act as the barrier's hp bar.
    (This might also require modification on system thought)
     
  16. Steel

    Steel Software Engineer

    Ratings:
    +109 / 0 / -0
    That is the exact reason I created this system for my own map.
     
    • Like Like x 1
  17. PurgeandFire

    PurgeandFire zxcvmkgdfg

    Ratings:
    +513 / 0 / -0
    Yes, it has extra features for JASS, but not for GUI. It helps the map though, with the DLLs mainly like War3err. You can go to the "Extensions" tab to enable/disable certain stuff. Then you can test the map by saving it and opening it in NewGen wc3.

    Great system, probably most useful for RPGs.
     
  18. Tinki3

    Tinki3 Special Member

    Ratings:
    +418 / 0 / -0
    Nice system, approved.
     
  19. PurgeandFire

    PurgeandFire zxcvmkgdfg

    Ratings:
    +513 / 0 / -0
    Haha, oddly the new patch can have you press ALT and keep it like that. :p

    But this is still useful for specifications and mana...
     
  20. Gripen2

    Gripen2 New Member

    Ratings:
    +1 / 0 / -0
    Is it possible to make the bars only on one unit instead of all.

    Like the bars display only on the ( Cant remember the word :banghead: ) "Speficied" unit.
     

Share This Page