- Joined
- May 9, 2014
- Messages
- 1,819
A text tag library (formerly a snippet) that allows you to create local text tags worry-free.
[/hidden]
JASS:
library TextTag
/*------------------------------
| |
| TextTag |
| By MyPad |
| |
| Version: |
| v.1.4.10 |
|--------------------------------------------------------------------------------
|
| TextTag is a library that provides convenience for the creation of local
| text tags. Knowing that there is a limit to the number of text tag handles
| that can be created and used at any given time, this system optimizes
| the usage of these limited text tag handles, minimizing their actual amount.
|
| If you want to create localized text tags, then this library is definitely
| for you. If you want an object-oriented approach to handling text tags,
| this library should suit your needs.
|
|---------------------------------------------------------------------------------
| |
| API |
| |
--------------------------------------------------------------------------------
*/
//! novjass
struct TextTag
Creation and destruction:
TextTag.create(integer playerId) -> TextTag
// 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 bj_MAX_PLAYER_SLOTS or higher
local TextTag tag = TextTag.create(integer playerId) -> TextTag
// Creates a TextTag instance.
..
tag.destroy()
// This destroys a TextTag instance. How it destroys an instance
// for a player is determined either manually
// or automatically
method operator/s:
// Note: "==" operators indicate getters, while "=" operators indicate setters.
tag.z == real z
// Returns the member z
tag.height2 == real z
// Returns z as well for BC
tag.height2 = real height
// Internally calls method setPos()
tag.height == real size
// Returns the member size
tag.height = real size
// sets the size of a Text Tag
tag.permanent == boolean isPermanent
// Returns the member isPermanent
tag.permanent = boolean bool
// Sets the permanence of a TextTag
// If set to true, this will lock the transparency of
// the TextTag. Be careful when using.
// Documented in v.1.4.10
tag.fade == real fadepoint
// Returns the member fadepoint
tag.fade = real fadepoint
// Determines the amount of time before the TextTag
// starts fading. (Watch out for the permanence property!)
tag.duration == real dur
// Returns the member dur -> tells duration.
tag.duration = real newDur
// If it is not permanent, a TextTag's duration is reset to the requested (r).
tag.msg or tag.message == string s
// message is just an abstraction of msg, a method operator that returns a member s.
tag.msg = string sometext
tag.message = string sometext
// Sets the message of a texttag
tag.red = integer int(0 - 255)
tag.green = integer int(0 - 255)
tag.blue = integer int(0 - 255)
tag.alpha = integer int(0 - 255)
// Returns the red, green, blue, and alpha properties of the text tag.
// Alpha levels determine the visibility of the locally created text tag.
// 255 means the instance is fully visible while 0 means transparent.
tag.widget = widget wid
tag.unit = unit uni
// Attaches a text tag to a widget or a unit.
method-s:
//tag
tag.setPosPrime(real x, real y, real heightOffset, boolean break)
// Sets the position of a TextTag instance to the requested coordinates
// with a z-offset denoted as heightOffset
tag.setPos(real x, real y, real heightOffset)
// Calls setPosPrime with a false parameter for variable break.
tag.setVeloc(real xvel, real yvel)
// Sets the pace at which the tag moves at a certain direction.
tag.setVelocEx(real speed, real angle)
// Wrapper function for setVeloc
tag.generate(integer playerId) -> TextTag
// Generates the same text tag for another player
tag.transfer(integer playerId) -> TextTag
// Same as generate, but destroys the base instance.
tag.applyForceVisibility(force f, boolean visible)
tag.visible_to_force(force f, boolean b) // @deprecated
// Only works when the Text Tag instance is a global one.
// Sets the visibility of a global text tag to flag b,
// towards players belonging to a certain force f
endstruct
function CreateTextTagBJ(player p, real x, real y, real offset, integer red, integer green, integer blue, string msg) -> {TextTag}
function CreateTextTagVJ(player p, real x, real y, real offset, integer red, integer green, integer blue, string msg) -> {TextTag}
// Creates a TextTag instance with the default settings.
// If you're not planning on saving the instance immediately,
// you can still access it via vj_lastCreatedTextTag
{vj_lastCreatedTextTag} // or return vj_lastCreatedTextTag
//! endnovjass
//! novjass
Update History:
v.1.4.1.0 - Slightly changed the hashing algorithm used in GetHashID.
- Exchanged execution speed for guaranteed unique indices
for the internal timers.
- Revised the API to describe the machinations of the system
in more detail.
- The method visible_to_force has been marked for deprecation.
You are advised to use the method applyForceVisibility instead.
- Author's note: Turns out I forgot to include applyForceVisibility
as one of the publicly accessible methods.
v.1.4.0.0 - Removed all requirements
v.1.3.0.6 - Added some details on method operator getters. (Denoted by ==)
- Fixed setVeloc-s slightly buggy behavior. (It didn-t originally pause the texttag when set to 0)
- Exposed a new method setPosPrime (does what setPos did before, with a boolean parameter)
- setPos now calls setPosPrime with a false flag.
v.1.3.0.5 - Improved API documentation.
- Added a new method operator height2
- Backwards compatible!
v.1.3.0.4 - Update history created!
- method operator unit= fixed.
//! endnovjass
globals
// This determines the check rate of the timers.
private constant real INTERVAL = 1/16.
endglobals
private function print takes string msg returns nothing
call BJDebugMsg(msg)
endfunction
private module TextTagModule
private static constant integer HASH_DIVISOR = 37
readonly static constant integer ALLOC_SPACE = 101
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.
private static timer array decayWatcher
private static integer array decayWatchMap
private static thistype array activeList
private static integer array timerId
private thistype allocId
// Flag members
private boolean is_active
private boolean is_permanent
// Real members
private real fadepoint
private real size
private real dur
private real cx
private real cy
private real cz
private real dx
private real dy
// Message
private string str
// Color members
private integer r
private integer g
private integer b
private integer a
private static method GetHashID takes timer whichtimer returns integer
local integer id = GetHandleId(whichtimer)
local integer baseIndex = ModuloInteger(ModuloInteger(id, JASS_MAX_ARRAY_SIZE), HASH_DIVISOR)
local integer iterIndex = 0
if (decayWatchMap[baseIndex] == 0) or (decayWatchMap[baseIndex] == id) then
if (decayWatchMap[baseIndex] == 0) then
set decayWatchMap[baseIndex] = id
endif
return baseIndex
endif
set iterIndex = baseIndex
loop
set iterIndex = ModuloInteger(iterIndex + 1, HASH_DIVISOR)
if (decayWatchMap[iterIndex] == 0) or (decayWatchMap[iterIndex] == id) then
if (decayWatchMap[iterIndex] == 0) then
set decayWatchMap[iterIndex] = id
endif
return iterIndex
endif
exitwhen (iterIndex == baseIndex)
endloop
return -1
endmethod
private static method SetTimerID takes timer whichtimer, integer id returns nothing
set timerId[GetHashID(whichtimer)] = id
endmethod
private static method GetTimerID takes timer whichtimer returns integer
return timerId[GetHashID(whichtimer)]
endmethod
private static method ApplyPlayerCondition takes integer pIndex returns boolean
local player p = null
if pIndex < bj_MAX_PLAYER_SLOTS then
set p = Player(pIndex)
endif
return (p == null) or (GetLocalPlayer() == p)
endmethod
private static method allocate takes integer i returns thistype
local integer j = 0
local thistype head = thistype(0)
local thistype this = thistype(0)
set head = thistype(i*ALLOC_SPACE)
set this = head.allocId
if (this.allocId == head) or (this.allocId == thistype(0)) then
set j = integer(this) + 1
if j - integer(head) >= ALLOC_SPACE then
return thistype(-1)
endif
set this = thistype(j)
set head.allocId = this
else
// Obtaining a recycled instance
set head.allocId = this.allocId
set this.allocId = 0
endif
set this.is_active = true
return this
endmethod
private method deallocate takes nothing returns nothing
local integer mod = ModuloInteger(integer(this), ALLOC_SPACE)
local thistype head
if not this.is_active then
return
endif
if mod == 0 then
return
endif
if this.allocId != thistype(0) then
return
endif
set head = thistype(integer(this)/ALLOC_SPACE*ALLOC_SPACE)
set this.allocId = head.allocId
set head.allocId = this
endmethod
method destroy takes nothing returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
local thistype head = thistype(pIndex*ALLOC_SPACE)
local thistype that = thistype(0)
local integer i = activeList[integer(head)]
local integer max = i
if not this.is_active then
return
endif
if ApplyPlayerCondition(pIndex) then
call DestroyTextTag(this.tag)
set this.tag = null
endif
call this.deallocate()
set this.target = null
set this.widgetTarg = null
set this.is_permanent = false
set this.fadepoint = 0.
set this.size = 0.
set this.dur = 0.
set this.dx = 0.
set this.dy = 0.
set this.cx = 0.
set this.cy = 0.
set this.cz = 0.
set this.r = 0
set this.g = 0
set this.b = 0
set this.a = 0
set this.str = null
loop
exitwhen i < 1
set that = activeList[integer(head) + i]
if that == this then
set that = activeList[integer(head) + max]
set activeList[integer(head) + i] = that
set activeList[integer(head) + max] = 0
set activeList[integer(head)] = max - 1
exitwhen true
endif
set i = i - 1
endloop
endmethod
//============================================================//
// Methods //
//============================================================//
method setPosPrime takes real x, real y, real heightOffset, boolean detach returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
if detach then
set this.target = null
set this.widgetTarg = null
endif
if this.target != null then
set heightOffset = heightOffset - GetUnitFlyHeight(this.target)
endif
set this.cx = x
set this.cy = y
set this.cz = heightOffset
if ApplyPlayerCondition(pIndex) then
if (not (this.dx != 0)) and (not (this.dy != 0)) then
call SetTextTagPos(this.tag, x, y, heightOffset)
return
endif
call DestroyTextTag(this.tag)
set this.tag = CreateTextTag()
call SetTextTagPos(this.tag, x, y, heightOffset)
call SetTextTagText(this.tag, this.str, this.size*HEIGHT_OFFSET)
call SetTextTagColor(this.tag, this.r, this.g, this.b, this.a)
call SetTextTagPermanent(this.tag, this.is_permanent)
if not this.is_permanent then
call SetTextTagLifespan(this.tag, this.dur)
call SetTextTagFadepoint(this.tag, RMaxBJ(this.fadepoint, 0))
endif
endif
endmethod
method setPos takes real x, real y, real heightOffset returns nothing
call setPosPrime(x, y, heightOffset, false)
endmethod
method setVeloc takes real xvel, real yvel returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
if ApplyPlayerCondition(pIndex) then
if xvel != 0 or yvel != 0 then
call SetTextTagVelocity(this.tag, xvel*VELOCITY_OFFSET, yvel*VELOCITY_OFFSET)
else
call this.setPos(this.cx, this.cy, this.cz)
endif
endif
set this.dx = xvel
set this.dy = yvel
endmethod
method setVelocEx takes real speed, real angle returns nothing
call this.setVeloc(Cos(angle*bj_DEGTORAD)*speed, Sin(angle*bj_DEGTORAD)*speed)
endmethod
// Sets visibility of a global text tag to a certain flag towards a certain force.
method applyForceVisibility takes force f, boolean b returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
if pIndex < bj_MAX_PLAYER_SLOTS then
return
endif
if IsPlayerInForce(GetLocalPlayer(), f) then
call SetTextTagVisibility(this.tag, b)
endif
endmethod
// @deprecated
method visible_to_force takes force f, boolean b returns nothing
call BJDebugMsg("TextTag:visible_to_force >> This will be deprecated in later versions. Use applyForceVisibility instead.")
call this.applyForceVisibility(f, b)
endmethod
//============================================================//
// Method operators //
//============================================================//
method operator permanent takes nothing returns boolean
return this.is_permanent
endmethod
method operator permanent= takes boolean flag returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
set this.is_permanent = flag
if not ApplyPlayerCondition(pIndex) then
return
endif
call SetTextTagPermanent(this.tag, flag)
endmethod
method operator duration takes nothing returns real
if this.is_permanent then
return -1.
endif
return this.dur
endmethod
method operator duration= takes real r returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
set this.dur = r
if not ApplyPlayerCondition(pIndex) then
return
endif
call SetTextTagLifespan(this.tag, r)
endmethod
method operator msg takes nothing returns string
return this.str
endmethod
method operator msg= takes string str returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
set this.str = str
if not ApplyPlayerCondition(pIndex) then
return
endif
call SetTextTagText(this.tag, this.str, this.size*HEIGHT_OFFSET)
endmethod
// These methods are wrappers...
method operator message takes nothing returns string
return this.str
endmethod
method operator message= takes string str returns nothing
set this.msg = str
endmethod
// A newer method operator that actually returns the height of the text tag.
method operator z takes nothing returns real
return this.cz
endmethod
method operator z= takes real new returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
if this.widgetTarg != null then
call this.setPos(GetWidgetX(this.widgetTarg), GetWidgetY(this.widgetTarg), new)
elseif this.target != null then
call this.setPos(GetUnitX(this.target), GetUnitY(this.target), new)
else
call this.setPos(cx, cy, new)
endif
endmethod
method operator height2 takes nothing returns real
return this.cz
endmethod
method operator height2= takes real new returns nothing
set this.z = new
endmethod
// Cannot deal away with backwards compatibility here..
method operator height takes nothing returns real
return this.size
endmethod
method operator height= takes real h returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
set this.size = h
if not ApplyPlayerCondition(pIndex) then
return
endif
call SetTextTagText(this.tag, this.str, this.size*HEIGHT_OFFSET)
endmethod
method operator fade takes nothing returns real
return this.fadepoint
endmethod
method operator fade= takes real fader returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
if this.is_permanent then
return
endif
set this.fadepoint = RMinBJ(RAbsBJ(fader), this.dur)
if not ApplyPlayerCondition(pIndex) then
return
endif
call SetTextTagFadepoint(this.tag, fadepoint)
endmethod
method operator red takes nothing returns integer
return this.r
endmethod
method operator red= takes integer value returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
set this.r = value
if not ApplyPlayerCondition(pIndex) then
return
endif
call SetTextTagColor(this.tag, this.r, this.g, this.b, 255 - this.a)
endmethod
method operator green takes nothing returns integer
return this.g
endmethod
method operator green= takes integer value returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
set this.g = value
if not ApplyPlayerCondition(pIndex) then
return
endif
call SetTextTagColor(this.tag, this.r, this.g, this.b, 255 - this.a)
endmethod
method operator blue takes nothing returns integer
return this.b
endmethod
method operator blue= takes integer value returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
set this.b = value
if not ApplyPlayerCondition(pIndex) then
return
endif
call SetTextTagColor(this.tag, this.r, this.g, this.b, 255 - this.a)
endmethod
method operator alpha takes nothing returns integer
return this.a
endmethod
method operator alpha= takes integer value returns nothing
local integer pIndex = integer(this)/ALLOC_SPACE
set this.a = value
if not ApplyPlayerCondition(pIndex) then
return
endif
call SetTextTagColor(this.tag, this.r, this.g, this.b, 255 - this.a)
endmethod
method operator widget takes nothing returns widget
return this.widgetTarg
endmethod
method operator widget= takes widget wid returns nothing
set this.target = null
set this.widgetTarg = wid
if wid != null then
call this.setVeloc(0,0)
call this.setPos(GetWidgetX(wid), GetWidgetY(wid), this.cz)
endif
endmethod
method operator unit takes nothing returns unit
return this.target
endmethod
method operator unit= takes unit u returns nothing
set this.widgetTarg = null
set this.target = u
if u != null then
call this.setVeloc(0,0)
call this.setPos(GetUnitX(u), GetUnitY(u), this.cz)
endif
endmethod
method operator texttag takes nothing returns texttag
return this.tag
endmethod
// ================================= //
// Create and onTick methods //
// ================================= //
private method onTickUpdate takes nothing returns boolean
if this.widgetTarg != null then
call this.setPos(GetWidgetX(this.widgetTarg), GetWidgetY(this.widgetTarg), this.cz)
elseif this.target != null then
call this.setPos(GetUnitX(this.target), GetUnitY(this.target), this.cz)
else
set this.cx = this.cx + this.dx*INTERVAL
set this.cy = this.cy + this.dy*INTERVAL
endif
if this.is_permanent then
return true
endif
set this.dur = this.dur - INTERVAL
set this.fadepoint = this.fadepoint - INTERVAL
if this.dur <= 0. then
call this.destroy()
return false
endif
return true
endmethod
private static method onTick takes nothing returns nothing
local integer pIndex = GetTimerID(GetExpiredTimer())
local integer i = 1
local thistype head = thistype(pIndex*ALLOC_SPACE)
local thistype this = 0
loop
exitwhen i > integer(activeList[integer(head)])
set this = activeList[integer(head) + i]
if not this.onTickUpdate() then
set i = i - 1
endif
set i = i + 1
endloop
if activeList[integer(head)] <= 0 then
call PauseTimer(decayWatcher[pIndex])
endif
endmethod
static method create takes integer pIndex returns thistype
local thistype this = 0
local thistype head = 0
local integer index = 0
local player p = null
if pIndex < 0 or pIndex > bj_MAX_PLAYER_SLOTS then
set pIndex = bj_MAX_PLAYER_SLOTS
endif
set head = thistype(pIndex*ALLOC_SPACE)
set this = thistype.allocate(pIndex)
if this == thistype(-1) then
return this
endif
set index = activeList[integer(head)] + 1
set activeList[integer(head)] = index
set activeList[integer(head) + index] = this
if ApplyPlayerCondition(pIndex) then
set this.tag = CreateTextTag()
endif
if activeList[integer(head)] == 1 then
call TimerStart(decayWatcher[pIndex], INTERVAL, true, /*
*/ function thistype.onTick)
endif
return this
endmethod
// Copies a Text Tag instance to another player
method generate takes integer playerId returns thistype
local thistype new = 0
local integer pIndex = integer(this)/ALLOC_SPACE
if pIndex == playerId then
return this
endif
set new = thistype.create(playerId)
if new == thistype(-1) then
return new
endif
set new.duration = this.dur
set new.fade = this.fadepoint
set new.permanent = this.is_permanent
set new.height = this.size
set new.red = this.r
set new.green = this.g
set new.blue = this.b
set new.alpha = this.a
set new.msg = this.msg
call new.setPos(this.cx, this.cy, this.cz)
call new.setVeloc(this.dx, this.dy)
return new
endmethod
// Same as the method generate but destroys the base instance
method transfer takes integer playerId returns thistype
local thistype that = this.generate(playerId)
if that == -1 then
return this
endif
call this.destroy()
return that
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
local thistype head
loop
exitwhen i > bj_MAX_PLAYER_SLOTS
set head = thistype(i*ALLOC_SPACE)
set head.allocId = head
set activeList[integer(head)] = 0
set decayWatcher[i] = CreateTimer()
call SetTimerID(decayWatcher[i], i)
set i = i + 1
endloop
endmethod
endmodule
struct TextTag extends array
readonly widget widgetTarg
readonly unit target
readonly texttag tag
implement TextTagModule
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 = TextTag(0)
local integer pIndex = bj_MAX_PLAYER_SLOTS
if p != null then
set pIndex = GetPlayerId(p)
endif
set this = TextTag.create(pIndex)
if this == TextTag(-1) then
return this
endif
set this.duration = TextTag.DEFAULT_DURATION
set this.fade = TextTag.DEFAULT_DURATION - 0.5
set this.height = TextTag.DEFAULT_HEIGHT
set this.permanent = false
set this.red = red
set this.green = green
set this.blue = blue
set this.alpha = 0
set this.msg = msg
call this.setPos(x, y, offset)
call this.setVelocEx(TextTag.DEFAULT_VELOC_SPEED, TextTag.DEFAULT_VELOC_ANGLE)
set vj_lastCreatedTextTag = this
return vj_lastCreatedTextTag
endfunction
function CreateTextTagVJ takes player p, real x, real y, real offset, integer red, integer green, integer blue, string msg returns TextTag
return CreateTextTagBJ(p, x, y, offset, red, green, blue, msg)
endfunction
endlibrary
Last edited: