Snippet Text Tag

Discussion in 'Tutorials and Resources' started by MyPad, Jul 18, 2017.

Tags:
  1. MyPad

    MyPad Member

    Ratings:
    +0 / 0 / -0
    A text tag snippet that allows you to create local text tags worry-free.

    If you have any suggestions for any features, feel free to add them:

    JASS:
    library TextTag uses/*
    
        */ optional OneTimer,/*   - A truly optional resource. If not found, the system attempts to generate a hashtable
                                in order to store the timers to be generated, which will handle the checking of instances.
        */
    
        //==========================//
        //  TextTag                 //
        //      -   By  MyPad       //
        //                          //
        //  Version:                //
        //      v.1.3.01            //
        //==========================//
     
        //  Description:    //
    
        //======================================================================================//
        //  TextTag is a snippet that provides convenience for the creation of local text tags. //
        //  Thus, it is lightweight in usage and grants the user a bit of ease in coding.       //
        //======================================================================================//
     
        //  API (Application Programming Interface) //
        //      Note: Section is in vJASS...        //
     
        //! novjass
            struct TextTag
         
                Creation and destruction:
             
                call TextTag.create(playerId)
                    //  Creates a local texttag for a certain player.
                 
                    //  Note that the playerId parameter takes the actual number of the player,
                    //  not the player itself
               
                    //  To create a global instance, request 17 or higher (Must be bigger than bj_MAX_PLAYER_SLOTS)
                local TextTag tag = TextTag.create(playerId)
             
                ..
             
                call tag.destroy()
                    //  This destroys a TextTag instance. How it manages to destroy an instance
                    //  for a player is determined mathematically.
             
                method operator:
             
                    set tag.permanent = bool
                        //  Sets the permanence of a TextTag
                     
                    set tag.duration = r
                        //  If it is not permanent, a TextTag's duration is reset to the requested (r).
                     
                    set tag.msg = somevar
                        //  Sets the message of a texttag
                     
                    set tag.Red = int
                    set tag.Blue = int
                    set tag.Green = int
                    set tag.Alpha = int
                        //  These are self-explanatory
                     
                    set tag.widget = wid
                    set tag.unit = uni
                        //  Attaches a text tag to a widget or a unit.
                     
                method /(s):
                    call tag.setPos(x, y, heightOffset)
                        //  Sets the position of a TextTag instance to the requested coordinates
                        //  with a z-offset of heightOffset
                 
                    call tag.setVeloc(xvel, yvel)
                        //  Sets the pace at which the tag moves at a certain direction.
                 
                    call tag.setVelocEx(speed, angle)
                        //  Wrapper function for setVeloc
                     
            endstruct
         
            function CreateTextTagBJ takes player p, real x, real y, real offset, integer red, integer green, integer blue, string msg returns TextTag
                //  Creates a TextTag instance with the default settings.
        //! endnovjass
     
        globals
            //  This determines the check rate of the timers..
            private constant real INTERVAL = 1/32.
        endglobals
     
        //  A minor rewrite of a double-linked list module.
        private module DoubleLink_Mod
            thistype next
            thistype prev
         
            method pop takes nothing returns nothing
                set next.prev = prev
                set prev.next = next
            endmethod
         
            method push takes integer head returns nothing
                set next = head
                set prev = next.prev
                set next.prev = this
                set prev.next = this
            endmethod
        endmodule
     
        private module TextTag_Mod
            //  How many texttags are possible (+1)
            readonly static constant integer ALLOC_MULTIPLIER = 101
         
            //  These are the default settings for heights
            readonly static constant real DEFAULT_HEIGHT = 10.
            readonly static constant real HEIGHT_OFFSET = 0.023 / 10.
         
            //  Default offset value for velocity
            readonly static constant real VELOCITY_OFFSET = 0.071 / 128.
         
            //  Default duration of a texttag instance
            readonly static constant real DEFAULT_DURATION = 2.
         
            //  Default speed and angle of a texttag
            readonly static constant real DEFAULT_VELOC_SPEED = 80.
            readonly static constant real DEFAULT_VELOC_ANGLE = 90.
         
            //  The list of deallocated instances.
            readonly thistype recCount
         
            //  When the text tag is a global text tag...
            readonly thistype local_next
            readonly thistype local_prev
         
            method local_pop takes nothing returns nothing
                set local_prev.local_next = local_next
                set local_next.local_prev = local_prev
                set local_prev = 0
                set local_next = 0
            endmethod
         
            method local_push takes integer head returns nothing
                set local_prev = head
                set local_next = local_prev.local_next
                set local_prev.local_next = this
                set local_next.local_prev = this
            endmethod
         
            static if LIBRARY_OneTimer then
                readonly Timer instanceCheck
            else
                //  Too lazy to do an array search...
                readonly static constant hashtable DATA_HASH = InitHashtable()
             
                readonly timer instanceCheck
                readonly integer instanceData
            endif
         
            method deallocate takes nothing returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                set recCount = thistype(pIndex*ALLOC_MULTIPLIER).recCount
                set thistype(pIndex*ALLOC_MULTIPLIER).recCount = this
            endmethod
         
            static method allocate takes integer pIndex returns thistype
                local thistype this = thistype(pIndex*ALLOC_MULTIPLIER).recCount
                if this.recCount == pIndex*ALLOC_MULTIPLIER then
                    if integer(this) < (pIndex+1)*ALLOC_MULTIPLIER then
                        //  From indices pIndex*ALLOC_MULTIPLIER to (pIndex+1)*ALLOC_MULTIPLIER - 1
                        set this = this + 1
                        set thistype(pIndex*ALLOC_MULTIPLIER).recCount = this
                        set this.recCount = pIndex*ALLOC_MULTIPLIER
                    else
                        //  Error, text tag count exceeded...
                        set this = -1
                    endif
                else
                    //  Recycling; it is impossible for the allocate method to go over the max.
                    set thistype(pIndex*ALLOC_MULTIPLIER).recCount = this.recCount
                    set this.recCount = pIndex*ALLOC_MULTIPLIER
                endif
                return this
            endmethod
         
            private static method onSecInit takes nothing returns nothing
                local thistype this = 0
             
                static if LIBRARY_OneTimer then
                    //  This recycles the expired timer instead.
                    call Timer.getExpired().destroy()
                else
                    //  This actually destroys the initialization timer.
                    call DestroyTimer(GetExpiredTimer())
                endif
             
                loop
                    exitwhen integer(this) > bj_MAX_PLAYER_SLOTS + 1
                 
                    call thistype(this*ALLOC_MULTIPLIER).push(this*ALLOC_MULTIPLIER)
                    set thistype(this*ALLOC_MULTIPLIER).recCount = this*ALLOC_MULTIPLIER
                   
                    static if LIBRARY_OneTimer then
                        set thistype(this*ALLOC_MULTIPLIER).instanceCheck = Timer.create()
                        set thistype(this*ALLOC_MULTIPLIER).instanceCheck.data = this*ALLOC_MULTIPLIER
                    else
                        set thistype(this*ALLOC_MULTIPLIER).instanceCheck = CreateTimer()
                        call SaveInteger(DATA_HASH, 0, GetHandleId(thistype(this*ALLOC_MULTIPLIER).instanceCheck), this*ALLOC_MULTIPLIER)
                        call SaveBoolean(DATA_HASH, 1, GetHandleId(thistype(this*ALLOC_MULTIPLIER).instanceCheck), true)
                    endif
                 
                    set this = this + 1
                endloop
            endmethod
         
            private static method onInit takes nothing returns nothing
                static if LIBRARY_OneTimer then
                    call Timer.create().start(0., false, function thistype.onSecInit)
                else
                    call TimerStart(CreateTimer(), 0., false, function thistype.onSecInit)
                endif
            endmethod
        endmodule
     
        struct TextTag extends array
            private texttag texttag
         
            private widget wid_targ
            private unit uni_targ
         
            private boolean isPermanent
            private real dur
         
            private string s
            private real size
         
            private real fadepoint
         
            private integer red
            private integer green
            private integer blue
            private integer alpha
         
            implement DoubleLink_Mod
           
            implement TextTag_Mod
           
            method destroy takes nothing returns nothing
                local thistype that = this.local_next
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call DestroyTextTag(texttag)
                    set texttag = null
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call DestroyTextTag(texttag)
                        set texttag = null
                    endif
                endif
             
                if that != 0 then
                    loop
                        exitwhen that == this
                        call that.local_pop()
                        call that.deallocate()
                        set that = this.local_next
                    endloop
                endif
             
                set wid_targ = null
                set uni_targ = null
             
                set isPermanent = false
                set dur = 0.
             
                set red = 0
                set green = 0
                set blue = 0
                set alpha = 0
             
                set s = ""
             
                call pop()
                call deallocate()
            endmethod
         
            //============================================================//
            //          Methods                                           //
            //============================================================//
            method setPos takes real x, real y, real heightOffset returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call SetTextTagPos(texttag, x, y, heightOffset)
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call SetTextTagPos(texttag, x, y, heightOffset)
                    endif
                endif
            endmethod
         
            method setVeloc takes real xvel, real yvel returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call SetTextTagVelocity(texttag, xvel * VELOCITY_OFFSET, yvel * VELOCITY_OFFSET)
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call SetTextTagVelocity(texttag, xvel * VELOCITY_OFFSET, yvel * VELOCITY_OFFSET)
                    endif
                endif
            endmethod
         
            method setVelocEx takes real speed, real angle returns nothing
                call setVeloc(Cos(angle * bj_DEGTORAD) * speed, Sin(angle * bj_DEGTORAD) * speed)
            endmethod
         
            //============================================================//
            //          Method operators                                  //
            //============================================================//
         
            method operator permanent takes nothing returns boolean
                return isPermanent
            endmethod
            method operator permanent= takes boolean b returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                set isPermanent = b
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call SetTextTagPermanent(texttag, isPermanent)
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call SetTextTagPermanent(texttag, isPermanent)
                    endif
                endif
            endmethod
         
            method operator duration takes nothing returns real
                if not isPermanent then
                    return dur
                endif
             
                //  If permanent, the text tag will always endure. Thus, its' duration is -1
                return -1.
            endmethod
            method operator duration= takes real r returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                if isPermanent then
                    return
                endif
             
                set dur = r
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call SetTextTagLifespan(texttag, dur)
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call SetTextTagLifespan(texttag, dur)
                    endif
                endif
            endmethod
         
            method operator msg takes nothing returns string
                return s
            endmethod
            method operator msg= takes string str returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                set s = str
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call SetTextTagText(texttag, s, size * HEIGHT_OFFSET)
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call SetTextTagText(texttag, s, size * HEIGHT_OFFSET)
                    endif
                endif
            endmethod
         
            method operator height takes nothing returns real
                return size
            endmethod
            method operator height= takes real h returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                set size = h
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call SetTextTagText(texttag, s, size * HEIGHT_OFFSET)
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call SetTextTagText(texttag, s, size * HEIGHT_OFFSET)
                    endif
                endif
            endmethod
         
            method operator fade takes nothing returns real
                return fadepoint
            endmethod
            method operator fade= takes real fader returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                if not isPermanent then
                    set fadepoint = RMinBJ(RAbsBJ(fader), dur)
                else
                    return
                endif
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call SetTextTagFadepoint(texttag, fadepoint)
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call SetTextTagFadepoint(texttag, fadepoint)
                    endif
                endif
            endmethod
         
            method operator Red takes nothing returns integer
                return red
            endmethod
            method operator Red= takes integer r returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                set red = r
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call SetTextTagColor(texttag, red, green, blue, 255 - alpha)
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call SetTextTagColor(texttag, red, green, blue, 255 - alpha)
                    endif
                endif
            endmethod
         
            method operator Green takes nothing returns integer
                return green
            endmethod
            method operator Green= takes integer r returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                set green = r
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call SetTextTagColor(texttag, red, green, blue, 255 - alpha)
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call SetTextTagColor(texttag, red, green, blue, 255 - alpha)
                    endif
                endif
            endmethod
         
            method operator Blue takes nothing returns integer
                return blue
            endmethod
            method operator Blue= takes integer r returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                set blue = r
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call SetTextTagColor(texttag, red, green, blue, 255 - alpha)
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call SetTextTagColor(texttag, red, green, blue, 255 - alpha)
                    endif
                endif
            endmethod
         
            method operator Alpha takes nothing returns integer
                return alpha
            endmethod
            method operator Alpha= takes integer r returns nothing
                local integer pIndex = this/ALLOC_MULTIPLIER
             
                set alpha = r
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    call SetTextTagColor(texttag, red, green, blue, 255 - alpha)
                else
                    if GetLocalPlayer() == Player(pIndex) then
                        call SetTextTagColor(texttag, red, green, blue, 255 - alpha)
                    endif
                endif
            endmethod
         
            method operator widget takes nothing returns widget
                return wid_targ
            endmethod
            method operator widget= takes widget wid returns nothing
                if wid == null then
                    //  Must not attach to null instance...
                    return
                endif
             
                set uni_targ = null
                set wid_targ = wid
             
                call setPos(GetWidgetX(wid_targ), GetWidgetY(wid_targ), 0)
                call setVeloc(0,0)
            endmethod
         
            method operator unit takes nothing returns unit
                return uni_targ
            endmethod
            method operator unit= takes unit uni returns nothing
                if unit == null then
                    //  Must not attach to null instance...
                    return
                endif
             
                set wid_targ = null
                set uni_targ = uni
             
                call setPos(GetWidgetX(uni_targ), GetWidgetY(uni_targ), GetUnitFlyHeight(uni_targ))
                call setVeloc(0,0)
            endmethod
         
            //  =================================   //
            //  Create and onTick methods           //
            //  =================================   //
         
            private static method onTick takes nothing returns nothing
                static if LIBRARY_OneTimer then
                    local Timer tick
                else
                    local timer tick
                endif
                local integer pIndex
                local thistype head
                local thistype this
             
                static if LIBRARY_OneTimer then
                    set tick = Timer.getExpired()
                    set pIndex = tick.data
                else
                    set tick = GetExpiredTimer()
                    set pIndex = LoadInteger(DATA_HASH, 0, GetHandleId(tick))
                endif
             
                set head = pIndex
                set this = head.next
             
                set pIndex = pIndex/ALLOC_MULTIPLIER
             
                if this == head then
                 
                    static if LIBRARY_OneTimer then
                        set tick.pause = true
                    else
                        call SaveBoolean(DATA_HASH, 1, GetHandleId(this.instanceCheck), true)
                        call PauseTimer(tick)
                    endif
                endif
             
                loop
                    exitwhen this == head
                    if this.uni_targ != null or this.wid_targ != null then
                        if this.wid_targ != null then
                            set this.widget = wid_targ
                        else
                            set this.unit = uni_targ
                        endif
                    endif
                    if not this.isPermanent then
                        set this.dur = this.dur - INTERVAL
                     
                        if this.dur <= 0. then
                            call this.destroy()
                        endif
                    endif
                    set this = this.next
                endloop
            endmethod
         
            static method create takes integer pIndex returns thistype
                local thistype this = 0
                local integer i = 0
                local thistype array that
               
                if pIndex > bj_MAX_PLAYER_SLOTS + 1 then
                    set pIndex = bj_MAX_PLAYER_SLOTS + 1
                elseif pIndex < 0 then
                    //  Apply modulo...
                    set pIndex = pIndex - pIndex/(bj_MAX_PLAYER_SLOTS + 1)*(bj_MAX_PLAYER_SLOTS + 1) + (bj_MAX_PLAYER_SLOTS + 1)
                endif
             
                if pIndex > bj_MAX_PLAYER_SLOTS then
                    loop
                        exitwhen i > bj_MAX_PLAYER_SLOTS
                        set that[i] = allocate(i)
                     
                        if that[i] == -1 then
                            exitwhen true
                        endif
                        set i = i + 1
                    endloop
                 
                    if i <= bj_MAX_PLAYER_SLOTS then
                        //  Creation failed, sadly...
                        loop
                            exitwhen i <= 0
                            call that[i].deallocate()
                            set i = i - 1
                        endloop
                    else
                        //  Creation success..
                        set this = allocate(pIndex)
                     
                        call this.push(pIndex*ALLOC_MULTIPLIER)
                     
                        set this.texttag = CreateTextTag()
                     
                        set i = 0
                        loop
                            exitwhen i > bj_MAX_PLAYER_SLOTS
                            call that[i].local_push(this)
                            set i = i + 1
                        endloop
                     
                        static if LIBRARY_OneTimer then
                            if thistype(pIndex*ALLOC_MULTIPLIER).instanceCheck.paused then
                                call thistype(pIndex*ALLOC_MULTIPLIER).instanceCheck.start(INTERVAL, true, function thistype.onTick)
                            endif
                        else
                            if LoadBoolean(DATA_HASH, 1, GetHandleId(thistype(pIndex*ALLOC_MULTIPLIER).instanceCheck)) then
                                call RemoveSavedBoolean(DATA_HASH, 1, GetHandleId(thistype(pIndex*ALLOC_MULTIPLIER).instanceCheck))
                                call TimerStart(thistype(pIndex*ALLOC_MULTIPLIER).instanceCheck, INTERVAL, true, function thistype.onTick)
                            endif
                        endif
                    endif
                else
                    set this = allocate(pIndex)
                    if this != -1 then
                        call BJDebugMsg("Allocated! \n" + I2S(this))
                        //  Allocation Successful..
                        call this.push(pIndex*ALLOC_MULTIPLIER)
                     
                        if GetLocalPlayer() == Player(pIndex) then
                            set this.texttag = CreateTextTag()
                        endif
                     
                        static if LIBRARY_OneTimer then
                            if thistype(pIndex*ALLOC_MULTIPLIER).instanceCheck.paused then
                                call thistype(pIndex*ALLOC_MULTIPLIER).instanceCheck.start(INTERVAL, true, function thistype.onTick)
                            endif
                        else
                            if LoadBoolean(DATA_HASH, 1, GetHandleId(thistype(pIndex*ALLOC_MULTIPLIER).instanceCheck)) then
                                call RemoveSavedBoolean(DATA_HASH, 1, GetHandleId(thistype(pIndex*ALLOC_MULTIPLIER).instanceCheck))
                                call TimerStart(thistype(pIndex*ALLOC_MULTIPLIER).instanceCheck, INTERVAL, true, function thistype.onTick)
                            endif
                        endif
                    endif
                endif
                return this
            endmethod
         
        endstruct
     
        globals
            TextTag vj_lastCreatedTextTag = 0
        endglobals
       
        function CreateTextTagBJ takes player p, real x, real y, real offset, integer red, integer green, integer blue, string msg returns TextTag
            local TextTag this
         
            if p == null then
                set this = TextTag.create(bj_MAX_PLAYER_SLOTS + 1)
            else
                set this = TextTag.create(GetPlayerId(p))
            endif
         
            if this == -1 then
                return this
            endif
         
            call this.setPos(x, y, offset)
            call this.setVelocEx(TextTag.DEFAULT_VELOC_SPEED, TextTag.DEFAULT_VELOC_ANGLE)
         
            set this.permanent = false
         
            set this.height = TextTag.DEFAULT_HEIGHT
            set this.duration = TextTag.DEFAULT_DURATION
            set this.fade = TextTag.DEFAULT_DURATION - 0.5
         
            set this.Red = red
            set this.Green = green
            set this.Blue = blue
            set this.Alpha = 0
         
            set this.msg = msg
         
            set vj_lastCreatedTextTag = this
            return vj_lastCreatedTextTag
        endfunction
    endlibrary


    Parallel Link:
    HIVE
     

Share This Page