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

New Bar System by xD.Schurke

Level 16
Joined
Feb 22, 2006
Messages
960
So I created my own bar system (it's more like a casting bar or timed bar).
This creates a bar over an unit and runs out in a time, selected by the user (also the user has some other options to select.)
Of course it's MUI

Requires:
JNGP

attachment.php


Main Script:

JASS:
//! textmacro CostumInterface takes Loop,End,path,periodic
library CostumInterface$path$ initializer init
      interface $path$Loop
        boolean active=false
        boolean paused=false

        method $Loop$ takes nothing returns nothing
        method $End$ takes nothing returns nothing
      endinterface
         
      globals
        private $path$Loop array $path$_loopObject
        private integer $path$_size=0
        
        private trigger $path$_loop
        constant real $path$_periodic=$periodic$
      endglobals
         
      function AddObjectTo$path$ takes $path$Loop loopObject returns integer
           set $path$_loopObject[$path$_size]=loopObject
           set $path$_loopObject[$path$_size].active=true
     set $path$_size=$path$_size+1
        
     if not IsTriggerEnabled($path$_loop) then
       call EnableTrigger($path$_loop)
     endif

        return $path$_size
      endfunction
         
      private function Loop$path$ takes nothing returns nothing
         local integer index=0
         
      loop
        exitwhen index==$path$_size
        if $path$_loopObject[index].active and not $path$_loopObject[index].paused then
      call $path$_loopObject[index].$Loop$.execute()
      set index=index+1
        elseif $path$_loopObject[index].paused then
                    set index=index+1
               else
      call $path$_loopObject[index].$End$()
      set $path$_size=$path$_size-1
      set $path$_loopObject[index]=$path$_loopObject[$path$_size]
               endif
      endloop
         
      if $path$_size<=0 then
        call DisableTrigger($path$_loop)
      endif
      endfunction
         
      private function init takes nothing returns nothing
        set $path$_loop=CreateTrigger()
        call TriggerRegisterTimerEvent($path$_loop,$path$_periodic,true)
        call TriggerAddAction($path$_loop,function Loop$path$)
        call DisableTrigger($path$_loop)
      endfunction
endlibrary
//! endtextmacro

//! runtextmacro CostumInterface("update","endupdate","Update","0.03")

NewBarSystem:

JASS:
//===========================================================================
//===========================================================================
//===========================New=Bar=System=v1.3=============================
//===========================================================================
//==============================By xD.Schurke================================
//===========================================================================
//===========================================================================

library NewBarSystem
globals
    private constant string ONE_BAR = "|" //For Bar Update (The style of the bar, also can use other chars, but would look ugly)
    
    private constant integer LOOP_NUMBER = 101 //for loop reasons ;)
    private constant integer STANDARD_LENGTH = 1 //standard: how many new single bars in a bar are added
    private constant integer BAR_LENGTH = 100 //the bar length
    
    //the following three integers are for color reasons. The color of the background bar (grey)
    private constant integer BACKGROUND_BAR_RED = 150 
    private constant integer BACKGROUND_BAR_GREEN = 150
    private constant integer BACKGROUND_BAR_BLUE = 150
    
    private constant real OFFSET = 150. //the offset of the texttags
    private constant real STATE_LIFE_OFFSET = 80. //the offset of the State_Life_Texttag
    private constant real STATE_MANA_OFFSET = 30. //the offset of the State_Mana_Texttag
    private constant real BAR_SIZE = 0.023 //the size of the texttags
    private constant real STATE_BAR_SIZE = 0.020 //DO NOT CHANGE
    private constant real RBSIZE = 7//Change for barsize (Bigger then 7 will make the bars look ugly)
    private constant real REAL_SIZE = (RBSIZE * BAR_SIZE / 10)//DO NOT CHANGE
    private constant real REAL_SIZE_STATE = (RBSIZE * STATE_BAR_SIZE / 10)//DO NOT CHANGE

    
    private constant real X_CORRECTION = -30. //for the bar position: change if you want the bar to be slide along the x-axis
    private constant real Y_CORRECTION = 0. //change if you want the bar to be slide along the y-axis
    private constant real STATE_X_CORRECTION = -100. //for the bar position: change if you want the bar to be slide along the x-axis
    private constant real STATE_Y_CORRECTION = 0. //change if you want the bar to be slide along the y-axis
    
    private constant real CORRECTION = 0.01 //for correction reasons in method update (the bar should update each 0.03 seconds, but there are numbers which are not a divisor of 0.03 so i have to correct those by 0.01)
    private constant real TIME = 3. //the standard time. the system functions in another way if the user explicide time is over 3 seconds
    private constant real TIME_UPDATE = .03 //the method update is called each 0.03 seconds (Always has to be TIME/100) if you change go into Main Script and change this line: //! runtextmacro CostumInterface("update","endupdate","Update","NEW TIME"), where NEW TIME is written, you have to enter the new number which has to be TIME/100

    //The following part is only for the call of the StateBar.create()
    constant integer BAR_UNIT_STATE_LIFE = 0
    constant integer BAR_UNIT_STATE_MANA = 1
endglobals
//====================DO NOT CHANGE THE FOLLOWING PART===============================

//the following two functions are another little system (credits to WaterKnight) it rounds a number, needed if the user enters a decimal number as the time)
private function RoundTo_GetDifference takes real dividend, real divisor returns real
    return RAbsBJ( dividend - R2I( dividend / divisor ) * divisor )
endfunction

private function RoundTo takes real base, real interval returns real
    local real difference1
    local real difference2
    if ( interval == 0 ) then
        return 0.
    endif
    set difference1 = RoundTo_GetDifference( base, interval )
    set difference2 = RAbsBJ( interval ) - difference1
    if ( difference2 < difference1 ) then
        return ( base + RSignBJ( interval ) * difference2 )
    endif
    return ( base - RSignBJ( interval ) * difference1 )
endfunction

struct TimedBar extends UpdateLoop
    unit tar //the target where the bar should appear
    texttag te = CreateTextTag() //background texttag
    texttag tt = CreateTextTag() //the counting texttag
    string tttext = "" //the text of tt
    real time = 0 //only important if the time selected by the user is bigger then TIME
    real timeup = 0 // also only important if the time selected by the user is bigger then TIME
    integer barup //only important if the time selected by the user is less then TIME
    boolean b = false //is for checking if the bar should update from left to right, or downgrade from right to left (true = downgrade)
    boolean a = false //true if the time selected by the player is bigger then TIME
    integer barlength = 0 //barlength if b == true then 0 else 100
        method update takes nothing returns nothing
            local integer i = 0
            local integer int = 1
            local boolean b = false
            call SetTextTagPos(.te,GetUnitX(.tar)+X_CORRECTION,GetUnitY(.tar)+Y_CORRECTION,OFFSET)
            call SetTextTagPos(.tt,GetUnitX(.tar)+X_CORRECTION,GetUnitY(.tar)+Y_CORRECTION,OFFSET)
            if .a then
                set .timeup = .timeup + TIME_UPDATE
                loop
                    exitwhen b == true or int >= LOOP_NUMBER
                    if .timeup == .time * int or .timeup == (.time * int) + CORRECTION or .timeup == (.time * int) - CORRECTION then
                        if .b then
                            set .tttext = SubString(.tttext,0,StringLength(.tttext)- STANDARD_LENGTH)
                            call SetTextTagText(.tt,.tttext,REAL_SIZE)
                            if StringLength(.tttext) <= .barlength or GetUnitState(.tar,UNIT_STATE_LIFE) <= 0 then
                                set .active = false
                            endif
                            set b = true
                        else
                            set .tttext = .tttext + ONE_BAR
                            call SetTextTagText(.tt,.tttext,REAL_SIZE)   
                            if StringLength(.tttext) >= .barlength or GetUnitState(.tar,UNIT_STATE_LIFE) <= 0 then
                                set .active = false
                            endif
                            set b = true
                        endif                        
                    endif
                    set int = int + 1
                endloop
                set int = 0                
            else
                if .b then
                    set .tttext = SubString(.tttext,0,StringLength(.tttext)-.barup)
                    call SetTextTagText(.tt,.tttext,REAL_SIZE)
                    if StringLength(.tttext) <= .barlength+1 or GetUnitState(.tar,UNIT_STATE_LIFE) <= 0 then
                        set .active = false
                    endif                
                else
                    loop
                        exitwhen i >= .barup
                        set .tttext = .tttext + ONE_BAR
                        set i = i + 1
                    endloop
                    call SetTextTagText(.tt,.tttext,REAL_SIZE)   
                    if StringLength(.tttext) >= .barlength or GetUnitState(.tar,UNIT_STATE_LIFE) <= 0 then
                        set .active = false
                    endif
                endif
            endif

        endmethod
        
        method endupdate takes nothing returns nothing
            call DestroyTextTag(.te)
            call DestroyTextTag(.tt)
            set .te = null
            set .tt = null
            set .tar = null
            call .destroy()
        endmethod
        
        static method create takes unit u, real t,integer red, integer green, integer blue, boolean b returns TimedBar
            local TimedBar Dat = TimedBar.allocate()
            local string text = ""
            local integer i = 0
                if t > TIME then
                    set Dat.time = RoundTo(t/BAR_LENGTH,TIME_UPDATE)
                    set Dat.a = true
                else
                    set Dat.barup = R2I(((TIME_UPDATE*BAR_LENGTH)/t)+.5)              
                endif

                set Dat.barlength = BAR_LENGTH
                loop
                    exitwhen i >= BAR_LENGTH
                    set text = text + ONE_BAR
                    set i = i + 1
                endloop
                set i = 0
                if b then
                    set Dat.b = true
                    set Dat.barlength = 0
                    loop
                        exitwhen i >= BAR_LENGTH
                        set Dat.tttext = Dat.tttext + ONE_BAR
                        set i = i + 1
                    endloop                    
                endif
                set Dat.tar = u
                call SetTextTagText(Dat.te,text, REAL_SIZE)
                call SetTextTagPos(Dat.te, GetUnitX(u)+X_CORRECTION, GetUnitY(u)+Y_CORRECTION, OFFSET)
                call SetTextTagColor(Dat.te, BACKGROUND_BAR_RED, BACKGROUND_BAR_GREEN, BACKGROUND_BAR_BLUE, 255)
                call SetTextTagVisibility(Dat.te, true)
                call SetTextTagPermanent(Dat.te, true)
                call SetTextTagText(Dat.tt,Dat.tttext, REAL_SIZE)
                call SetTextTagPos(Dat.tt, GetUnitX(u)+X_CORRECTION, GetUnitY(u)+Y_CORRECTION, OFFSET)
                call SetTextTagColor(Dat.tt, red, green, blue, 255)
                call SetTextTagVisibility(Dat.tt, true)
                call SetTextTagPermanent(Dat.tt, true)
                call AddObjectToUpdate(Dat)
            return Dat
        endmethod
endstruct
struct StateBar extends UpdateLoop
    unit tar
    texttag te = CreateTextTag()
    texttag tt = CreateTextTag()
    string tttext = ""
    real maxstate = 0
    real stateper = 0
    integer curper = 0
    boolean statebol = false
    integer state = 0
    integer maxstateint = 0
    integer red = 0
    integer green = 0
    integer blue = 0
        method update takes nothing returns nothing
            local integer i = 0
            local integer per = 0
            local integer dif = 0
            local boolean b = false
            local real offset            
            set .maxstate = GetUnitState(.tar,ConvertUnitState(.maxstateint))
            set .stateper = .maxstate/100
            set per = R2I(GetUnitState(.tar,ConvertUnitState(.state))/.stateper+.5)
            if .statebol then
                set offset = STATE_MANA_OFFSET
            else
                set offset = STATE_LIFE_OFFSET
            endif
            call SetTextTagPos(.te,GetUnitX(.tar)+STATE_X_CORRECTION,GetUnitY(.tar)+STATE_Y_CORRECTION,offset)
            call SetTextTagPos(.tt,GetUnitX(.tar)+STATE_X_CORRECTION,GetUnitY(.tar)+STATE_Y_CORRECTION,offset)
            if per > .curper then
                set dif = per-.curper
                set b = true
            elseif per < .curper then
                set dif = .curper - per
            elseif per == .curper then
                set dif = 0
            endif
            if b then
                loop
                    exitwhen i >= dif
                    set .tttext = .tttext + ONE_BAR
                    set i = i + 1
                endloop
            else
                loop
                    exitwhen i >= dif
                    set .tttext = SubString(.tttext,0,StringLength(.tttext)-STANDARD_LENGTH)
                    set i = i + 1
                endloop
            endif
            call SetTextTagText(.tt,.tttext, REAL_SIZE_STATE)
            if .statebol != true then
                if per >= 81 then
                    set .green = 255
                    set .red = 0
                    set .blue = 0
                elseif per <=80 and per >= 51 then
                    set .green = 249
                    set .red = 242
                    set .blue = 0
                elseif per <= 50 and per >= 21 then
                    set .green = 128
                    set .red = 255
                    set .blue = 0
                elseif per <= 20 and per >= 0 then
                    set .green = 0
                    set .red = 255
                    set .blue = 0
                endif
            endif
            call SetTextTagColor(.tt,.red,.green,.blue, 255)
            if GetUnitState(.tar,UNIT_STATE_LIFE) <= 0 then
                set .active = false
            endif
            set .curper = per
        endmethod
        
        method endupdate takes nothing returns nothing
            call DestroyTextTag(.te)
            call DestroyTextTag(.tt)
            set .te = null
            set .tt = null
            set .tar = null
            call .destroy()
        endmethod
        
        static method create takes unit u, integer state returns StateBar
            local StateBar Dat = StateBar.allocate()
            local string text = ""
            local integer i = 0
            local real offset
            if state == BAR_UNIT_STATE_LIFE then
                set Dat.green = 255
                set Dat.maxstate = GetUnitState(u,UNIT_STATE_MAX_LIFE)
                set Dat.stateper = Dat.maxstate/100
                set Dat.curper = R2I(GetUnitState(u,UNIT_STATE_LIFE)/Dat.stateper+.5) 
                set offset = STATE_LIFE_OFFSET
                set Dat.state = 0
                set Dat.maxstateint = 1
            elseif state == BAR_UNIT_STATE_MANA then
                set Dat.blue = 255
                set Dat.maxstate = GetUnitState(u,UNIT_STATE_MAX_MANA)
                set Dat.stateper = Dat.maxstate/100
                set Dat.curper = R2I(GetUnitState(u,UNIT_STATE_MANA)/Dat.stateper+.5)
                set offset = STATE_MANA_OFFSET
                set Dat.statebol = true
                set Dat.state = 2
                set Dat.maxstateint = 3
            elseif state > 1 then
                call StateBar.destroy(Dat)
                debug call BJDebugMsg("Incorrect Value!")
                return 0
            endif
            loop
                exitwhen i >= BAR_LENGTH
                set text = text + ONE_BAR
                set i = i + 1
            endloop
            set i = 0
            loop
                exitwhen i >= Dat.curper
                set Dat.tttext = Dat.tttext + ONE_BAR
                set i = i + 1
            endloop
            call SetTextTagText(Dat.te,text,REAL_SIZE_STATE)
            call SetTextTagPos(Dat.te, GetUnitX(u)+STATE_X_CORRECTION, GetUnitY(u)+STATE_Y_CORRECTION, offset)
            call SetTextTagColor(Dat.te, BACKGROUND_BAR_RED, BACKGROUND_BAR_GREEN, BACKGROUND_BAR_BLUE, 255)
            call SetTextTagVisibility(Dat.te, true)
            call SetTextTagPermanent(Dat.te, true)
            call SetTextTagText(Dat.tt,Dat.tttext, REAL_SIZE_STATE)
            call SetTextTagPos(Dat.tt, GetUnitX(u)+STATE_X_CORRECTION, GetUnitY(u)+STATE_Y_CORRECTION, offset)
            call SetTextTagColor(Dat.tt, Dat.red, Dat.green, Dat.blue, 255)
            call SetTextTagVisibility(Dat.tt, true)
            call SetTextTagPermanent(Dat.tt, true)  
            set Dat.tar = u
            call AddObjectToUpdate(Dat)
            return Dat
        endmethod
        
        method onDestroy takes nothing returns nothing
        
        endmethod
endstruct
endlibrary

here an example usage:

For the TimedBar:

call TimedBar.create(udg_t,9.643,255,255,0,true)

call TimedBar.create(<unit>,<time>,<redcolor>,<greencolor>,<bluecolor>,<false/true>)

For the StateBar:

call StateBar.create(udg_t,BAR_UNIT_STATE_LIFE)

call StateBar.create(<unit>,<BAR_UNIT_STATE_LIFE/BAR_UNIT_STATE_MANA>)

if the last part is true the bar will update from right to left, else from left to right

credits to Hanky for Interface System :)
please give credits to me and hanky if you use this one ;)

Test Map Attatched

And also give commands pls :p


version 1.1
  • Added StateBar
  • Reworked some constants

version 1.2
  • Fixed a bug with the downcounting bar

version 1.3
  • Reworked some values for a better look
 

Attachments

  • NewBarSystem.w3x
    26.6 KB · Views: 132
  • bla.jpg
    bla.jpg
    145.8 KB · Views: 481
Last edited:
Level 14
Joined
Nov 18, 2007
Messages
816
what does that boolean parameter do?
Oh, and i dont like that looping textmacro, i prefer either using one timer per instance, or i write my own loop (without stupid triggers).

And your indentation is ... weird (Indentation of that loop macro is fail).
 
Level 14
Joined
Nov 18, 2007
Messages
816
Sorry didnt read the OP carefully enough.

JASS:
//! textmacro CostumInterface takes Loop,End,path,periodic
library CostumInterface$path$ initializer init
    interface $path$Loop
        boolean active=false
        boolean paused=false

        method $Loop$ takes nothing returns nothing
        method $End$ takes nothing returns nothing
    endinterface

    globals
        private $path$Loop array $path$_loopObject
        private integer $path$_size=0

        private trigger $path$_loop
        constant real $path$_periodic=$periodic$
    endglobals

    function AddObjectTo$path$ takes $path$Loop loopObject returns integer
        set $path$_loopObject[$path$_size]=loopObject
        set $path$_loopObject[$path$_size].active=true
        set $path$_size=$path$_size+1

        if not IsTriggerEnabled($path$_loop) then
            call EnableTrigger($path$_loop)
        endif

        return $path$_size
    endfunction

    private function Loop$path$ takes nothing returns nothing
        local integer index=0

        loop
            exitwhen index==$path$_size
            if $path$_loopObject[index].active and not $path$_loopObject[index].paused then
                call $path$_loopObject[index].$Loop$.execute()
                set index=index+1
            elseif $path$_loopObject[index].paused then
                set index=index+1
            else
                call $path$_loopObject[index].$End$()
                set $path$_size=$path$_size-1
                set $path$_loopObject[index]=$path$_loopObject[$path$_size]
            endif
        endloop

        if $path$_size<=0 then
            call DisableTrigger($path$_loop)
        endif
    endfunction

    private function init takes nothing returns nothing
        set $path$_loop=CreateTrigger()
        call TriggerRegisterTimerEvent($path$_loop,$path$_periodic,true)
        call TriggerAddAction($path$_loop,function Loop$path$)
        call DisableTrigger($path$_loop)
    endfunction
    
endlibrary
//! endtextmacro
Done.
 
Level 7
Joined
Dec 3, 2006
Messages
339
I like this system, not exactly very much for the life/mana bars but more for the casting bars. Although i'm sure some people might find some use for the life/mana bars.

As for the problem; maybe you can apply a small trigger that detects new orders given as soon as the bar is created, or you could perhaps check if the unit is playing the "channel" animation sequence.

Heck, simply adding a stop/cancel bar method would be fine. Than you can make your own simple trigger that is enabled when the channel bar is created that cancels the bar on the order and disables that trigger again.
 
Level 16
Joined
Feb 22, 2006
Messages
960
I like this system, not exactly very much for the life/mana bars but more for the casting bars. Although i'm sure some people might find some use for the life/mana bars.

As for the problem; maybe you can apply a small trigger that detects new orders given as soon as the bar is created, or you could perhaps check if the unit is playing the "channel" animation sequence.

Heck, simply adding a stop/cancel bar method would be fine. Than you can make your own simple trigger that is enabled when the channel bar is created that cancels the bar on the order and disables that trigger again.

the thing is, it's not a simple trigger ;)
 
Level 9
Joined
Mar 25, 2005
Messages
252
I think the following is equivalent to the one you have in your script.

Code:
[COLOr=White][B][COLOr=Wheat]function[/COLOr][/B] [COLOr=PaleGreen]RoundTo[/COLOr] [COLOr=DarkOliveGreen]takes[/COLOr] [B][COLOr=YellowGreen]real[/COLOr][/B] x[B][COLOr=PaleGreen],[/COLOr][/B] [B][COLOr=YellowGreen]real[/COLOr][/B] a [B][COLOr=Wheat]returns[/COLOr][/B] [B][COLOr=YellowGreen]real[/COLOr][/B]
    [B][COLOr=Wheat]return[/COLOr][/B] [COLOr=SandyBrown]R2I[/COLOr][B][COLOr=PaleGreen]([/COLOr][/B][COLOr=Silver]0.5[/COLOr] [B][COLOr=PaleGreen]+[/COLOr][/B] x [B][COLOr=PaleGreen]/[/COLOr][/B] a[B][COLOr=PaleGreen])[/COLOr][/B] [B][COLOr=PaleGreen]*[/COLOr][/B] a
[B][COLOr=Wheat]endfunction[/COLOr][/B][/COLOr]
 
Level 16
Joined
Feb 22, 2006
Messages
960
I think the following is equivalent to the one you have in your script.

Code:
[COLOr=White][B][COLOr=Wheat]function[/COLOr][/B] [COLOr=PaleGreen]RoundTo[/COLOr] [COLOr=DarkOliveGreen]takes[/COLOr] [B][COLOr=YellowGreen]real[/COLOr][/B] x[B][COLOr=PaleGreen],[/COLOr][/B] [B][COLOr=YellowGreen]real[/COLOr][/B] a [B][COLOr=Wheat]returns[/COLOr][/B] [B][COLOr=YellowGreen]real[/COLOr][/B]
    [B][COLOr=Wheat]return[/COLOr][/B] [COLOr=SandyBrown]R2I[/COLOr][B][COLOr=PaleGreen]([/COLOr][/B][COLOr=Silver]0.5[/COLOr] [B][COLOr=PaleGreen]+[/COLOr][/B] x [B][COLOr=PaleGreen]/[/COLOr][/B] a[B][COLOr=PaleGreen])[/COLOr][/B] [B][COLOr=PaleGreen]*[/COLOr][/B] a
[B][COLOr=Wheat]endfunction[/COLOr][/B][/COLOr]

no it's not because, with my roundto functions you can round to numbers like 0.xx and not only integers
 
Level 9
Joined
Mar 25, 2005
Messages
252
no it's not because, with my roundto functions you can round to numbers like 0.xx and not only integers

RoundTo(2.99, 2.0) == 2.0
RoundTo(3.00, 2.0) == 4.0
RoundTo(1.10, 2.0) == 2.0
RoundTo(0.50, 2.0) == 0.0

RoundTo(1.30, 0.5) == 1.5
RoundTo(1.24, 0.5) == 1.0
RoundTo(0.50, 0.5) == 0.5

Thats how the one I posted works. Sorry if I misunderstood, but I thought thats what yours does also.
 
Level 7
Joined
Dec 3, 2006
Messages
339
A suggestion would be to add a string parameter to the caster bar function, which would be displayed above the bar.

Thing is... that can be a whole other system itself. Also its not very rpg-like to call out spells completely giving out all the info about your next plan of attack. Although chanting out the spell name in txt after the bar completes would definately be applicable i think. So... maybe a text messege after the bar completes for timed bars?
 
Level 9
Joined
Apr 5, 2008
Messages
529
Thing is... that can be a whole other system itself. Also its not very rpg-like to call out spells completely giving out all the info about your next plan of attack. Although chanting out the spell name in txt after the bar completes would definately be applicable i think. So... maybe a text messege after the bar completes for timed bars?

If you don't want the string to be displayed you can just call the function with "". =P
 
Top