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:
Parallel Link:
HIVE
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
</i></i></i></i>
Parallel Link:
HIVE