//TESH.scrollpos=-1
//TESH.alwaysfold=0
//
Name | Type | is_array | initial_value |
//TESH.scrollpos=-1
//TESH.alwaysfold=0
// *************************************************************
// * TextSplat -- Version 1.3.2
// * by Deaod
// *************************************************************
// *
// * CREDITS:
// * - MasterofSickness (reported bugs and gave a cool optimization idea)
// * - Vexorian (JassHelper, ARGB, Table)
// * - PitzerMike (JassNewGenPack, original TextSplat system)
// * - MindWorX (JassNewGenPack)
// * - Pipedream (Grimoire)
// * - SFilip (TESH)
// *
// * HOW TO IMPORT:
// * * C'n'P the code into your map
// * * If you haven't done that already, import ARGB and Table into your map
// * * Set up a Font (a HOW-TO can be found inside the Font library)
// *
// * HOW TO USE:
// *
// * * Theres a procedural API and an object oriented API
// * The procedural resembles the API of texttags with one exception: You have to pass a font to the CreateTextSplat function.
// * Other than that, simply replace TextTag in the function names with TextSplat to switch over to TextSplats.
// * Note that there might be discrepancies between texttags and textsplats concerning the more obscure features of texttags,
// * such as the "suspended" attribute.
// *
// * The object oriented API, however, has more options, for example you can read the width of the textsplat in WC3 units of length.
// *
// * * declare a variable of type textsplat
// *
// * * use textsplat.create(font Font) to create a new image
// * - Refer to the documentation of the Font library for detailed information on Fonts
// *
// * * you can change the text of the textsplat by calling the method yourtsplat.setText(string text, real height, integer aligntype).
// * - text is the new text the textsplat should read
// * - height is the fontsize of the text
// * - aligntype is where the text should be aligned. Possible aligntypes:
// * TEXTSPLAT_TEXT_ALIGN_LEFT, TEXTSPLAT_TEXT_ALIGN_CENTER, TEXTSPLAT_TEXT_ALIGN_RIGHT
// * you can embed images into text (as long as the Font supports the embedded images) by surrounding the images identifier by "|i"
// * Example: "|igold|i" would be converted into the gold coin image (if the font supports it).
// * Note that image idenitifiers are case- and slash-insensitive (the latter meaning that / == \). "|ilumber|i" displays the same image as
// * "|iLuMBeR|i" does.
// *
// * * you can change the velocity of a textsplat by calling the method yourtsplat.setVelocity(real xvel, real yvel, real zvel)
// * Velocities are in (WC3 units of length)/second
// *
// * * you can change the color of the textsplat by calling the method yourtsplat.setColor(integer red, integer green, integer blue, integer alpha)
// * All parameters can take values from 0 to 255 (including 0 and 255).
// * This changes the color of all chars outside |cAARRGGBB - |r tags.
// * Changes in the value of the alpha channel are prohibited if the textsplat is currently fading.
// * Note that textsplats, unlike texttags, have a working alpha channel.
// *
// * * you can change the position of a textsplat by calling the method yourtsplat.setPosition(real x, real y, real z)
// * the point specified is the lower left corner of the textsplat.
// * Theres also a variant of this function (yourtsplat.setPosUnit(unit u, real z)) that aligns the textsplats lower left corner
// * to the units origin and with the specified z offset (from 0., not the units locations z).
// *
// * * you can access the standard attributes (lifespan, fadepoint, age, permanent, visible) of texttags as variable members of the struct.
// * Example: set yourtsplat.fadepoint=2.
// * Note that some things may not work exactly like they did with texttags. If you notice such a discrepancy, tell me about it.
// *
// * * you can access the width of the textsplat by reading the width member of the struct (yourtsplat.width).
// * Note that this member is read only.
// * It returns the width of the textsplat in standard WC3 units of length.
// *
// * * you can access the height of the textsplat by read the height member of the structs (yourtsplat.height).
// * This returns the Y size of the textsplat, much like the width member returns the X size.
// * The returned values are in standard WC3 units of length.
// *
// * * you can access and change the font of a textsplat on the fly by reading/writing the .font member
// * Note that any changes to the font only take place after the next call to .setText()
// *
// * * to destroy a textsplat use yourtsplat.destroy()
// *
// *************************************************************
library TextSplat initializer Init uses ARGB, ImageUtils, Table, Font
globals
private constant real TICK = 1./40
private constant integer DEFAULT_COLOR = 0xFFFFFFFF // white
private constant integer DEFAULT_IMAGE_TYPE = IMAGE_TYPE_SELECTION
constant integer DEFAULT_IMAGE_SIZE = 32 // If you dont know what this is used for, you might want to leave it alone to not fuck things up
constant integer TEXTSPLAT_TEXT_ALIGN_LEFT = 1
constant integer TEXTSPLAT_TEXT_ALIGN_CENTER = 2
constant integer TEXTSPLAT_TEXT_ALIGN_RIGHT = 3
constant real TEXT_SIZE_TO_IMAGE_SIZE = 4.146479
private constant integer TOKENS_PER_CHUNK = 40 // lower this if you make heavy use of |cAARRGGBB strings in textsplats. Maximum working value is about 65.
endglobals
globals
private real array TextAlignBonus
private StringTable Hex2Dec
private StringTable IsHex
endglobals
private struct char
image Img
string Path
real SizeX
real SizeY
real X
real Y
real Z
integer Type
boolean Show
boolean DefaultColor
integer ColorAlpha
integer ColorRed
integer ColorBlue
integer ColorGreen
private method Recreate takes nothing returns nothing
if .Img!=null then
call ReleaseImage(.Img)
endif
set .Img=NewImage(.Path, .SizeX, .SizeY, 0, .X, .Y, 0, 0, 0, 0, .Type)
call SetImageConstantHeight(.Img, true, .Z)
call SetImageColor(.Img, .ColorRed, .ColorGreen, .ColorBlue, .ColorAlpha)
call SetImageRenderAlways(.Img, .Show)
endmethod
method operator color= takes ARGB col returns nothing
set .ColorAlpha=col.alpha
set .ColorRed=col.red
set .ColorGreen=col.green
set .ColorBlue=col.blue
call SetImageColor(.Img, .ColorRed, .ColorGreen, .ColorBlue, .ColorAlpha)
endmethod
private static method create takes string path, real sizex, real sizey, real x, real y, real z returns thistype
local thistype s=.allocate()
set s.Path=path
set s.SizeX=sizex
set s.SizeY=sizey
set s.X=x
set s.Y=y
set s.Z=z
set s.Show=true
set s.Type=DEFAULT_IMAGE_TYPE
set s.color=DEFAULT_COLOR
call s.Recreate()
return s
endmethod
static method createChar takes font f, string ch, real x, real y, real z, real size returns thistype
return .create(f[ch].path, size*TEXT_SIZE_TO_IMAGE_SIZE, size*TEXT_SIZE_TO_IMAGE_SIZE, x, y, z)
endmethod
static method createImage takes font f, string img, real x, real y, real z, real size returns thistype
return .create(f.getImage(img).path, size*TEXT_SIZE_TO_IMAGE_SIZE, size*TEXT_SIZE_TO_IMAGE_SIZE, x, y, z)
endmethod
method onDestroy takes nothing returns nothing
if .Img!=null then
call ReleaseImage(.Img)
endif
set .Img=null
endmethod
endstruct
private struct TextToken extends array
integer tokenType
string value
ARGB valueColor
boolean isDefaultColor
integer line
real posX
real posY
static constant integer TOKEN_TYPE_INVALID = 0
static constant integer TOKEN_TYPE_NORMAL = 1
static constant integer TOKEN_TYPE_NEWLINE = 2
static constant integer TOKEN_TYPE_COLOR = 3
static constant integer TOKEN_TYPE_COLOREND = 4
static constant integer TOKEN_TYPE_IMAGE = 5
endstruct
globals
private real array LineWidth
private string array TextChars
private real MaxLineWidth
private integer TSPCount
private integer TSPSourceStringLength
private integer CurrentLine
private ARGB CurrentColor
private boolean IsDefaultColor
private char TSPChar
private real SourceX
private real SourceY
private integer TokenAmount
private TextToken CurrentToken
private location LocZ=Location(0,0)
endglobals
private function IsHexadecimal takes integer offset returns boolean
local integer i = offset
local integer l = i + 8
loop
exitwhen i >= l
if IsHex[TextChars[i]] == 0 then
// one illegal char aborts
return false
endif
set i=i+1
endloop
return true
endfunction
private function prepareText takes string text returns nothing
local integer i = 0
loop
exitwhen i >= TSPSourceStringLength
set TextChars[i] = SubString(text, i, i+1)
set i = i + 1
endloop
// zero termination
set TextChars[i] = null
endfunction
// this is a bit hacky... but necessary to avoid hitting the op limit.
private function tokenizeText takes TextToken base returns nothing
local integer i = TSPCount
local string curChar
local TextToken token = CurrentToken
loop
exitwhen (integer(token) - integer(base) >= TOKENS_PER_CHUNK) or (i >= TSPSourceStringLength)
set curChar = TextChars[i]
// check for \n or \r\n or |n
if curChar=="\n" or (curChar=="\r" and TextChars[i + 1] == "\n") or (curChar=="|" and TextChars[i + 1]=="n") then
set token.tokenType = TextToken.TOKEN_TYPE_NEWLINE
set token = TextToken(integer(token) + 1)
if curChar != "\n" then
set i = i + 1
endif
elseif curChar=="|" and TextChars[i + 1] == "c" and TSPSourceStringLength - i >= 10 and IsHexadecimal(i + 2) then
set token.tokenType = TextToken.TOKEN_TYPE_COLOR
set token.valueColor = ARGB.create(Hex2Dec[TextChars[i + 2] + TextChars[i + 3]], Hex2Dec[TextChars[i + 4] + TextChars[i + 5]], Hex2Dec[TextChars[i + 6] + TextChars[i + 7]], Hex2Dec[TextChars[i + 8] + TextChars[i + 9]])
set token = TextToken(integer(token) + 1)
set i = i + 9
elseif curChar=="|" and TextChars[i + 1] == "r" then
set token.tokenType = TextToken.TOKEN_TYPE_COLOREND
set token = TextToken(integer(token) + 1)
set i = i + 1
elseif curChar == "|" and TextChars[i + 1] == "i" then
set i = i + 2
set token.tokenType = TextToken.TOKEN_TYPE_IMAGE
set token.value = ""
loop
exitwhen (TextChars[i] == "|" and TextChars[i + 1] == "i") or (i >= TSPSourceStringLength)
set token.value = token.value + TextChars[i]
set i = i + 1
endloop
set token = TextToken(integer(token) + 1)
set i = i + 1
else // normal char
set token.tokenType = TextToken.TOKEN_TYPE_NORMAL
set token.value = curChar
set token = TextToken(integer(token) + 1)
endif
set i = i + 1
endloop
set CurrentToken = token
set TSPCount = i
endfunction
private function layoutText takes TextToken base, ARGB backgroundColor, font textFont, real lineHeight returns nothing
local TextToken token = CurrentToken
local real width
loop
exitwhen (integer(token) - integer(base) >= TOKENS_PER_CHUNK) or (integer(token) >= TokenAmount)
if token.tokenType == TextToken.TOKEN_TYPE_NEWLINE then
if LineWidth[CurrentLine] > MaxLineWidth or CurrentLine == 0 then
set MaxLineWidth = LineWidth[CurrentLine]
endif
set CurrentLine = CurrentLine + 1
set LineWidth[CurrentLine] = 0
elseif token.tokenType == TextToken.TOKEN_TYPE_COLOR then
set CurrentColor = token.valueColor
set IsDefaultColor = false
elseif token.tokenType == TextToken.TOKEN_TYPE_COLOREND then
set CurrentColor = backgroundColor
set IsDefaultColor = true
elseif token.tokenType == TextToken.TOKEN_TYPE_IMAGE or token.tokenType == TextToken.TOKEN_TYPE_NORMAL then
set token.valueColor = CurrentColor
set token.isDefaultColor = IsDefaultColor
set token.line = CurrentLine
if token.tokenType == TextToken.TOKEN_TYPE_IMAGE then
set width = (textFont.getImage(token.value).width * TEXT_SIZE_TO_IMAGE_SIZE * lineHeight / DEFAULT_IMAGE_SIZE)
else
set width = (textFont[token.value].width * TEXT_SIZE_TO_IMAGE_SIZE * lineHeight / DEFAULT_IMAGE_SIZE)
endif
set token.posY = CurrentLine * lineHeight * TEXT_SIZE_TO_IMAGE_SIZE
set token.posX = LineWidth[CurrentLine]
set LineWidth[CurrentLine] = LineWidth[CurrentLine] + width
endif
set token = TextToken(integer(token) + 1)
endloop
set CurrentToken = token
endfunction
private function displayText takes TextToken base, real lineHeight, integer alignType, real z, boolean visible, font textFont, Table t returns nothing
local integer i
local boolean b
local TextToken token = CurrentToken
local real x
local real y
loop
exitwhen (integer(token) - integer(base) >= TOKENS_PER_CHUNK) or (integer(token) >= TokenAmount)
if token.tokenType == TextToken.TOKEN_TYPE_IMAGE or token.tokenType == TextToken.TOKEN_TYPE_NORMAL then
set x = SourceX + token.posX + ( TextAlignBonus[alignType] * (MaxLineWidth - LineWidth[token.line]) )
set y = SourceY - token.posY
if token.tokenType == TextToken.TOKEN_TYPE_IMAGE then
set TSPChar = char.createImage(textFont, token.value, x, y, z, lineHeight)
else
set TSPChar = char.createChar(textFont, token.value, x, y, z, lineHeight)
endif
set TSPChar.DefaultColor = token.isDefaultColor
set TSPChar.color = token.valueColor
set TSPChar.Show = visible
call SetImageRenderAlways(TSPChar.Img, visible)
set t[TSPCount] = integer(TSPChar)
set TSPCount=TSPCount+1
endif
set token = TextToken(integer(token) + 1)
endloop
set CurrentToken = token
endfunction
// destroys all chars of the textsplat
private function cleanSplat takes Table t, integer count returns nothing
local integer i=count-1
local integer j
loop
exitwhen i<0
set j=t[i]
if j>0 then
call char(j).destroy()
endif
set i=i-1
endloop
endfunction
struct textsplat
private font F
private Table Chars
private integer CharCount=0
private real X=0.
private real Y=0.
private real Z=0.
private real Dx=0.
private real Dy=0.
private real Dz=0.
private real Age=0.
private real Lifespan=0.
private real Fadepoint=0.
private real Width=0.
private real Height=0.
private boolean Suspended=false
private boolean Permanent=true
private boolean Visible=true
private string Text=""
private ARGB BGColor=ARGB(DEFAULT_COLOR)
private integer i
private static thistype array Structs
private static timer T=CreateTimer()
private static integer Count=0
method onDestroy takes nothing returns nothing
local integer i=0
call cleanSplat.evaluate(.Chars, .CharCount)
call .Chars.destroy()
// clean your struct here
set .Count=.Count-1
set .Structs[.i]=.Structs[.Count]
set .Structs[.i].i=.i
if .Count==0 then
call PauseTimer(.T)
endif
endmethod
private static method Callback takes nothing returns nothing
local integer i=.Count-1
local thistype s
local integer j
local char ch
local boolean b1
local real alphafactor
loop
exitwhen i<0
set s=.Structs[i]
if (not s.Suspended) then
if s.Lifespan>s.Age then
set s.Age=s.Age+TICK
if s.Age>=s.Lifespan then
if s.Permanent then
set s.Suspended=true
else
call s.destroy()
endif
endif
endif
if (s.Dx!=0 or s.Dy!=0 or s.Dz!=0) then
set s.X=s.X+s.Dx
set s.Y=s.Y+s.Dy
set s.Z=s.Z+s.Dz
set j=s.CharCount-1
set b1=s.Dz!=0.
if s.Age>s.Fadepoint then
set alphafactor=1-(s.Age-s.Fadepoint)/(s.Lifespan-s.Fadepoint)
else
set alphafactor=1.
endif
loop
exitwhen j<0
set ch=s.Chars[j]
if ch>0 then
set ch.X=ch.X+s.Dx
set ch.Y=ch.Y+s.Dy
call SetImagePosition(ch.Img, ch.X, ch.Y, 0)
if b1 then // s.Dz!=0.
set ch.Z=ch.Z+s.Dz
call SetImageConstantHeight(ch.Img, true, ch.Z)
endif
call SetImageColor(ch.Img, ch.ColorRed, ch.ColorGreen, ch.ColorBlue, R2I(ch.ColorAlpha*alphafactor))
endif
set j=j-1
endloop
endif
endif
set i=i-1
endloop
endmethod
method setText takes string text, real height, integer aligntype returns nothing
set TSPSourceStringLength=StringLength(text)
set CurrentLine=0
set CurrentColor=.BGColor
set IsDefaultColor = true
set MaxLineWidth=0
// lets clean up old stuff we dont need anymore
call cleanSplat.evaluate(.Chars, .CharCount)
call prepareText.evaluate(text)
set LineWidth[0]=0
//
set TSPCount=0
set CurrentToken = TextToken(0)
loop
exitwhen TSPCount >= TSPSourceStringLength // TSPCount gets incremented in processText
call tokenizeText.evaluate(CurrentToken)
endloop
set TokenAmount = integer(CurrentToken)
set CurrentToken = TextToken(0)
loop
exitwhen integer(CurrentToken) >= TokenAmount
call layoutText.evaluate(CurrentToken, .BGColor, .F, height)
endloop
if CurrentLine == 0 or LineWidth[CurrentLine] > MaxLineWidth then
set MaxLineWidth = LineWidth[CurrentLine]
endif
// actually display the shit
set SourceX = .X
set SourceY = .Y + CurrentLine * height * TEXT_SIZE_TO_IMAGE_SIZE
set TSPCount=0
set CurrentToken = TextToken(0)
loop
exitwhen integer(CurrentToken) >= TokenAmount
call displayText.evaluate(CurrentToken, height, aligntype, .Z, .Visible, .F, .Chars)
endloop
set .CharCount = TSPCount
set .Text = text
set .Width = MaxLineWidth
set .Height = (CurrentLine + 1) * height * TEXT_SIZE_TO_IMAGE_SIZE
endmethod
method setVelocity takes real xvel, real yvel, real zvel returns nothing
set .Dx = xvel * TICK
set .Dy = yvel * TICK
set .Dz = zvel * TICK
endmethod
method setColor takes integer red, integer green, integer blue, integer alpha returns nothing
local integer i=0
local char ch
local real alphafactor
set .BGColor=ARGB.create(alpha, red, green, blue)
if .Age>.Fadepoint and not(.Lifespan==.Fadepoint) then
set alphafactor=1-(.Age-.Fadepoint)/(.Lifespan-.Fadepoint)
else
set alphafactor=1.
endif
loop
exitwhen i>=.CharCount
set ch=char(.Chars[i])
if ch>0 and ch.DefaultColor then
set ch.ColorRed=red
set ch.ColorGreen=green
set ch.ColorBlue=blue
set ch.ColorAlpha=alpha
call SetImageColor(ch.Img, red, green, blue, R2I(alpha*alphafactor))
endif
set i=i+1
endloop
endmethod
method setPosition takes real x, real y, real z returns nothing
local integer i=.CharCount-1
local real dx=x-.X
local real dy=y-.Y
local real dz=z-.Z
local char c
set .X=x
set .Y=y
set .Z=z
loop
exitwhen i<0
set c=char(.Chars[i])
if c>0 then
set c.X=c.X+dx
set c.Y=c.Y+dy
set c.Z=c.Z+dz
call SetImagePosition(c.Img, c.X, c.Y, 0)
call SetImageConstantHeight(c.Img, true, c.Z)
endif
set i=i-1
endloop
endmethod
method setPosUnit takes unit u, real z returns nothing
call .setPosition(GetUnitX(u), GetUnitY(u), z)
endmethod
method operator age takes nothing returns real
return .Age
endmethod
method operator lifespan takes nothing returns real
return .Lifespan
endmethod
method operator fadepoint takes nothing returns real
return .Fadepoint
endmethod
method operator width takes nothing returns real
return .Width
endmethod
method operator height takes nothing returns real
return .Height
endmethod
method operator suspended takes nothing returns boolean
return .Suspended
endmethod
method operator permanent takes nothing returns boolean
return .Permanent
endmethod
method operator visible takes nothing returns boolean
return .Visible
endmethod
method operator font takes nothing returns font
return .F
endmethod
method operator age= takes real new returns nothing
set .Age=new
endmethod
method operator lifespan= takes real new returns nothing
set .Lifespan=new
endmethod
method operator fadepoint= takes real new returns nothing
set .Fadepoint=new
endmethod
//
// -- Width is readonly
//
//
// -- Height is readonly
//
method operator suspended= takes boolean flag returns nothing
set .Suspended=flag
endmethod
method operator permanent= takes boolean flag returns nothing
set .Permanent=flag
endmethod
method operator visible= takes boolean flag returns nothing
local integer i=0
local char c
set .Visible=flag
loop
exitwhen i>=.CharCount
set c=char(.Chars[i])
if c>0 then
set c.Show=flag
call SetImageRenderAlways(c.Img, flag)
endif
set i=i+1
endloop
endmethod
method operator font= takes font F returns nothing
set .F=F
endmethod
static method create takes font F returns thistype
local thistype s=.allocate()
set s.F=F
set s.Chars=Table.create()
set .Structs[.Count]=s
set s.i=.Count
if .Count==0 then
call TimerStart(.T, TICK, true, function thistype.Callback)
endif
set .Count=.Count+1
return s
endmethod
endstruct
// Standard API
// a replacement for the TextTag API
function CreateTextSplat takes font F returns textsplat
return textsplat.create(F)
endfunction
function DestroyTextSplat takes textsplat which returns nothing
call which.destroy()
endfunction
function SetTextSplatAge takes textsplat t, real age returns nothing
set t.age=age
endfunction
function SetTextSplatColor takes textsplat t, integer red, integer green, integer blue, integer alpha returns nothing
call t.setColor(red, green, blue, alpha)
endfunction
function SetTextSplatFadepoint takes textsplat t, real fadepoint returns nothing
set t.fadepoint=fadepoint
endfunction
function SetTextSplatLifespan takes textsplat t, real lifespan returns nothing
set t.lifespan=lifespan
endfunction
function SetTextSplatPermanent takes textsplat t, boolean flag returns nothing
set t.permanent=flag
endfunction
function SetTextSplatPos takes textsplat t, real x, real y, real heightOffset returns nothing
call t.setPosition(x,y, heightOffset)
endfunction
function SetTextSplatPosUnit takes textsplat t, unit whichUnit, real heightOffset returns nothing
call t.setPosUnit(whichUnit, heightOffset)
endfunction
function SetTextSplatSuspended takes textsplat t, boolean flag returns nothing
set t.suspended=flag
endfunction
function SetTextSplatText takes textsplat t, string s, real height returns nothing
call t.setText(s, height, TEXTSPLAT_TEXT_ALIGN_CENTER)
endfunction
function SetTextSplatVelocity takes textsplat t, real xvel, real yvel returns nothing
call t.setVelocity(xvel, yvel, 0)
endfunction
function SetTextSplatVisibility takes textsplat t, boolean flag returns nothing
set t.visible=flag
endfunction
//! textmacro Hex2DecUpper_Macro takes L
set Hex2Dec["$L$0"]=0x$L$0
set Hex2Dec["$L$1"]=0x$L$1
set Hex2Dec["$L$2"]=0x$L$2
set Hex2Dec["$L$3"]=0x$L$3
set Hex2Dec["$L$4"]=0x$L$4
set Hex2Dec["$L$5"]=0x$L$5
set Hex2Dec["$L$6"]=0x$L$6
set Hex2Dec["$L$7"]=0x$L$7
set Hex2Dec["$L$8"]=0x$L$8
set Hex2Dec["$L$9"]=0x$L$9
set Hex2Dec["$L$A"]=0x$L$A
set Hex2Dec["$L$B"]=0x$L$B
set Hex2Dec["$L$C"]=0x$L$C
set Hex2Dec["$L$D"]=0x$L$D
set Hex2Dec["$L$E"]=0x$L$E
set Hex2Dec["$L$F"]=0x$L$F
//! endtextmacro
private function Init takes nothing returns nothing
set Hex2Dec=StringTable.create()
//! runtextmacro Hex2DecUpper_Macro("0")
//! runtextmacro Hex2DecUpper_Macro("1")
//! runtextmacro Hex2DecUpper_Macro("2")
//! runtextmacro Hex2DecUpper_Macro("3")
//! runtextmacro Hex2DecUpper_Macro("4")
//! runtextmacro Hex2DecUpper_Macro("5")
//! runtextmacro Hex2DecUpper_Macro("6")
//! runtextmacro Hex2DecUpper_Macro("7")
//! runtextmacro Hex2DecUpper_Macro("8")
//! runtextmacro Hex2DecUpper_Macro("9")
//! runtextmacro Hex2DecUpper_Macro("A")
//! runtextmacro Hex2DecUpper_Macro("B")
//! runtextmacro Hex2DecUpper_Macro("C")
//! runtextmacro Hex2DecUpper_Macro("D")
//! runtextmacro Hex2DecUpper_Macro("E")
//! runtextmacro Hex2DecUpper_Macro("F")
set IsHex=StringTable.create()
set IsHex["0"]=1
set IsHex["1"]=1
set IsHex["2"]=1
set IsHex["3"]=1
set IsHex["4"]=1
set IsHex["5"]=1
set IsHex["6"]=1
set IsHex["7"]=1
set IsHex["8"]=1
set IsHex["9"]=1
set IsHex["A"]=1
set IsHex["B"]=1
set IsHex["C"]=1
set IsHex["D"]=1
set IsHex["E"]=1
set IsHex["F"]=1
set TextAlignBonus[TEXTSPLAT_TEXT_ALIGN_LEFT ] = 0.0
set TextAlignBonus[TEXTSPLAT_TEXT_ALIGN_CENTER ] = 0.5
set TextAlignBonus[TEXTSPLAT_TEXT_ALIGN_RIGHT ] = 1.0
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
// *************************************************************
// * Font -- Version 1.3.1
// * by Deaod
// *************************************************************
// *
// * CREDITS:
// * - Vexorian (JassHelper, ARGB, Table)
// * - PitzerMike (JassNewGenPack, original TextSplat system)
// * - MindWorX (JassNewGenPack)
// * - Pipedream (Grimoire)
// * - SFilip (TESH)
// *
// * HOW TO IMPORT:
// * * C'n'P the code into your map
// * * If you haven't done that already, import Table into your map
// *
// * HOW TO USE:
// *
// * * declare a variable of type font
// *
// * * use font.create(font Parent) to create a new font
// * - Parent is the font thats accessed should a char not be available in this font
// *
// * * you can add a new symbol to the font by calling the method yourfont.addChar(string which, real width, string path).
// * - which is the symbol you want to add to the font
// * - width is the width of the symbol in pixels
// * - path is the path to the image file thatll be used to display the symbol.
// * PitzerMike attached a program for creating new fonts to his TextSplat system. I suggest you use it.
// * The paths of the imported blps dont matter, but you should copy the width of the individual chars from the .j file that program creates.
// * Refer to [url]http://www.wc3c.net/showthread.php?t=87798[/url] (--> Importing custom Fonts) for a guide on how to create custom fonts.
// *
// * * you can access the width of individual characters like this: CustomFont["C"].width.
// * To access the path associated with the character use the path attribute.
// * Example: CustomFont["C"].path
// * "C" can be replaced with any character that has been previously added to the font using CustomFont.addChar()
// * The double quote character can be used like this: \" (dont be scared by the broken highlighting of TESH, itll save just fine)
// * The backslash character like this: \\
// *
// * * you can add custom images to a font by calling the method .addImage(string which, real width, string path)
// * Parameters work almost exactly like the ones of .addChar(), with the exception of which being case-insensitive
// * and "slash-insensitive" (/ and \ being the same).
// * Images are fully compatible with parents.
// *
// * * to access such an image you have to use CustomFont.getImage(string which)
// * which being the same or an equivalent (slash/case-insensitivity!) of the which you passed to .addImage().
// *
// * * Fonts are not meant to be destroyed. Just dont do it.
// *
// *************************************************************
library Font initializer Init requires Table
globals
private constant integer ASCII_CHAR_COUNT = 256
private constant integer COLLISION_DEPTH = 2 // how many individual chars collide at most
endglobals
globals
private StringTable Collisions
private StringTable Single
private string array CollisionMapping
private integer array CollisionResult
endglobals
private function ASCII2Int takes string char returns integer
local integer id
local integer i
set char=SubString(char, 0, 1)
if char == "" or char == null then // manually filter out 0
return 0
endif
set id=Single[char] // see if the char is a non-colliding char
if id>0 then // if it is,
return id // return immediately
else // if it isnt
set id=Collisions[char] // get the ID of the collision
set i=0
loop // and see which char of the two colliding ones it is
exitwhen i>=COLLISION_DEPTH
if CollisionMapping[id*COLLISION_DEPTH+i]==char then
return CollisionResult[id*COLLISION_DEPTH+i] // found it! Return immediately, to shorten the algorithm
endif
set i=i+1
endloop
endif
debug call BJDebugMsg("TextSplat: Faulty Setup of Collisions for ASCII2Int.")
return 0 // this line normally shouldnt be reached. If however, it is reached, you have a faulty Setup of the Collisions
endfunction
private struct fontchar
string path
real width
static method create takes string path, real width returns thistype
local thistype s=.allocate()
set s.path=path
set s.width=width
return s
endmethod
endstruct
private struct fontimage
string path
real width
static method create takes string path, real width returns thistype
local thistype s=.allocate()
set s.path=path
set s.width=width
return s
endmethod
endstruct
struct font
private font parent=0
private fontchar array Symbol[ASCII_CHAR_COUNT]
private StringTable Images
method operator [] takes string ch returns fontchar
local fontchar f=.Symbol[ASCII2Int(ch)]
if f==0 then
if .parent!=0 then
return .parent[ch]
debug else
debug call BJDebugMsg("TextSplat: Char '"+ch+"' is not available in font "+I2S(this)+".")
endif
endif
return f
endmethod
method addChar takes string which, real width, string path returns nothing
local integer i=ASCII2Int(which)
if i>0 then
if .Symbol[i]==0 then
set .Symbol[i]=fontchar.create(path, width)
else
set .Symbol[i].path=path
set .Symbol[i].width=width
endif
debug else
debug call BJDebugMsg("TextSplat: font.addChar: '"+which+"' could not be found in the CharMap!")
endif
endmethod
method getImage takes string which returns fontimage
local fontimage fi=fontimage(.Images[which])
if fi==0 then
if .parent!=0 then
return .parent.getImage(which)
debug else
debug call BJDebugMsg("TextSplat: Image '"+which+"' is not available in font "+I2S(this)+".")
endif
endif
return fi
endmethod
method addImage takes string which, real width, string path returns nothing
if .Images[which]>0 then
set fontimage(.Images[which]).path=path
set fontimage(.Images[which]).width=width
else
set .Images[which]=fontimage.create(path, width)
endif
endmethod
static method create takes font Parent returns thistype
local thistype s=.allocate()
set s.parent=Parent
set s.Images=StringTable.create()
return s
endmethod
private method destroy takes nothing returns nothing
endmethod
endstruct
// What im doing here is basically precalculating some things thatll lead to a speed gain in the ASCII2Int function
private function Init takes nothing returns nothing
set Collisions=StringTable.create()
set Single=StringTable.create()
// First, all chars that dont collide.
// Note that they must be !=0
set Single["\b"]=8
set Single["\t"]=9
set Single["\n"]=10
set Single["\f"]=12
set Single["\r"]=13
set Single[" "]=32
set Single["!"]=33
set Single["\""]=34
set Single["#"]=35
set Single["$"]=36
set Single["%"]=37
set Single["&"]=38
set Single["'"]=39
set Single["("]=40
set Single[")"]=41
set Single["*"]=42
set Single["+"]=43
set Single[","]=44
set Single["-"]=45
set Single["."]=46
set Single["0"]=48
set Single["1"]=49
set Single["2"]=50
set Single["3"]=51
set Single["4"]=52
set Single["5"]=53
set Single["6"]=54
set Single["7"]=55
set Single["8"]=56
set Single["9"]=57
set Single[":"]=58
set Single[";"]=59
set Single["<"]=60
set Single["="]=61
set Single[">"]=62
set Single["?"]=63
set Single["@"]=64
set Single["["]=91
set Single["]"]=93
set Single["^"]=94
set Single["_"]=95
set Single["`"]=96
set Single["{"]=123
set Single["|"]=124
set Single["}"]=125
set Single["~"]=126
// -------------------
// This is the initialization of the arrays that will map from individual chars to integers later on
set CollisionResult[(0*COLLISION_DEPTH)+0]=65
set CollisionResult[(1*COLLISION_DEPTH)+0]=66
set CollisionResult[(2*COLLISION_DEPTH)+0]=67
set CollisionResult[(3*COLLISION_DEPTH)+0]=68
set CollisionResult[(4*COLLISION_DEPTH)+0]=69
set CollisionResult[(5*COLLISION_DEPTH)+0]=70
set CollisionResult[(6*COLLISION_DEPTH)+0]=71
set CollisionResult[(7*COLLISION_DEPTH)+0]=72
set CollisionResult[(8*COLLISION_DEPTH)+0]=73
set CollisionResult[(9*COLLISION_DEPTH)+0]=74
set CollisionResult[(10*COLLISION_DEPTH)+0]=75
set CollisionResult[(11*COLLISION_DEPTH)+0]=76
set CollisionResult[(12*COLLISION_DEPTH)+0]=77
set CollisionResult[(13*COLLISION_DEPTH)+0]=78
set CollisionResult[(14*COLLISION_DEPTH)+0]=79
set CollisionResult[(15*COLLISION_DEPTH)+0]=80
set CollisionResult[(16*COLLISION_DEPTH)+0]=81
set CollisionResult[(17*COLLISION_DEPTH)+0]=82
set CollisionResult[(18*COLLISION_DEPTH)+0]=83
set CollisionResult[(19*COLLISION_DEPTH)+0]=84
set CollisionResult[(20*COLLISION_DEPTH)+0]=85
set CollisionResult[(21*COLLISION_DEPTH)+0]=86
set CollisionResult[(22*COLLISION_DEPTH)+0]=87
set CollisionResult[(23*COLLISION_DEPTH)+0]=88
set CollisionResult[(24*COLLISION_DEPTH)+0]=89
set CollisionResult[(25*COLLISION_DEPTH)+0]=90
set CollisionResult[(26*COLLISION_DEPTH)+0]=47
set CollisionResult[(0*COLLISION_DEPTH)+1]=97
set CollisionResult[(1*COLLISION_DEPTH)+1]=98
set CollisionResult[(2*COLLISION_DEPTH)+1]=99
set CollisionResult[(3*COLLISION_DEPTH)+1]=100
set CollisionResult[(4*COLLISION_DEPTH)+1]=101
set CollisionResult[(5*COLLISION_DEPTH)+1]=102
set CollisionResult[(6*COLLISION_DEPTH)+1]=103
set CollisionResult[(7*COLLISION_DEPTH)+1]=104
set CollisionResult[(8*COLLISION_DEPTH)+1]=105
set CollisionResult[(9*COLLISION_DEPTH)+1]=106
set CollisionResult[(10*COLLISION_DEPTH)+1]=107
set CollisionResult[(11*COLLISION_DEPTH)+1]=108
set CollisionResult[(12*COLLISION_DEPTH)+1]=109
set CollisionResult[(13*COLLISION_DEPTH)+1]=110
set CollisionResult[(14*COLLISION_DEPTH)+1]=111
set CollisionResult[(15*COLLISION_DEPTH)+1]=112
set CollisionResult[(16*COLLISION_DEPTH)+1]=113
set CollisionResult[(17*COLLISION_DEPTH)+1]=114
set CollisionResult[(18*COLLISION_DEPTH)+1]=115
set CollisionResult[(19*COLLISION_DEPTH)+1]=116
set CollisionResult[(20*COLLISION_DEPTH)+1]=117
set CollisionResult[(21*COLLISION_DEPTH)+1]=118
set CollisionResult[(22*COLLISION_DEPTH)+1]=119
set CollisionResult[(23*COLLISION_DEPTH)+1]=120
set CollisionResult[(24*COLLISION_DEPTH)+1]=121
set CollisionResult[(25*COLLISION_DEPTH)+1]=122
set CollisionResult[(26*COLLISION_DEPTH)+1]=92
// --------------------
// This maps the ID of the collision onto the colliding chars, which are stored in this virtual 2D array
set CollisionMapping[ 0*(COLLISION_DEPTH)+0]="A"
set CollisionMapping[ 1*(COLLISION_DEPTH)+0]="B"
set CollisionMapping[ 2*(COLLISION_DEPTH)+0]="C"
set CollisionMapping[ 3*(COLLISION_DEPTH)+0]="D"
set CollisionMapping[ 4*(COLLISION_DEPTH)+0]="E"
set CollisionMapping[ 5*(COLLISION_DEPTH)+0]="F"
set CollisionMapping[ 6*(COLLISION_DEPTH)+0]="G"
set CollisionMapping[ 7*(COLLISION_DEPTH)+0]="H"
set CollisionMapping[ 8*(COLLISION_DEPTH)+0]="I"
set CollisionMapping[ 9*(COLLISION_DEPTH)+0]="J"
set CollisionMapping[10*(COLLISION_DEPTH)+0]="K"
set CollisionMapping[11*(COLLISION_DEPTH)+0]="L"
set CollisionMapping[12*(COLLISION_DEPTH)+0]="M"
set CollisionMapping[13*(COLLISION_DEPTH)+0]="N"
set CollisionMapping[14*(COLLISION_DEPTH)+0]="O"
set CollisionMapping[15*(COLLISION_DEPTH)+0]="P"
set CollisionMapping[16*(COLLISION_DEPTH)+0]="Q"
set CollisionMapping[17*(COLLISION_DEPTH)+0]="R"
set CollisionMapping[18*(COLLISION_DEPTH)+0]="S"
set CollisionMapping[19*(COLLISION_DEPTH)+0]="T"
set CollisionMapping[20*(COLLISION_DEPTH)+0]="U"
set CollisionMapping[21*(COLLISION_DEPTH)+0]="V"
set CollisionMapping[22*(COLLISION_DEPTH)+0]="W"
set CollisionMapping[23*(COLLISION_DEPTH)+0]="X"
set CollisionMapping[24*(COLLISION_DEPTH)+0]="Y"
set CollisionMapping[25*(COLLISION_DEPTH)+0]="Z"
set CollisionMapping[26*(COLLISION_DEPTH)+0]="/"
set CollisionMapping[ 0*(COLLISION_DEPTH)+1]="a"
set CollisionMapping[ 1*(COLLISION_DEPTH)+1]="b"
set CollisionMapping[ 2*(COLLISION_DEPTH)+1]="c"
set CollisionMapping[ 3*(COLLISION_DEPTH)+1]="d"
set CollisionMapping[ 4*(COLLISION_DEPTH)+1]="e"
set CollisionMapping[ 5*(COLLISION_DEPTH)+1]="f"
set CollisionMapping[ 6*(COLLISION_DEPTH)+1]="g"
set CollisionMapping[ 7*(COLLISION_DEPTH)+1]="h"
set CollisionMapping[ 8*(COLLISION_DEPTH)+1]="i"
set CollisionMapping[ 9*(COLLISION_DEPTH)+1]="j"
set CollisionMapping[10*(COLLISION_DEPTH)+1]="k"
set CollisionMapping[11*(COLLISION_DEPTH)+1]="l"
set CollisionMapping[12*(COLLISION_DEPTH)+1]="m"
set CollisionMapping[13*(COLLISION_DEPTH)+1]="n"
set CollisionMapping[14*(COLLISION_DEPTH)+1]="o"
set CollisionMapping[15*(COLLISION_DEPTH)+1]="p"
set CollisionMapping[16*(COLLISION_DEPTH)+1]="q"
set CollisionMapping[17*(COLLISION_DEPTH)+1]="r"
set CollisionMapping[18*(COLLISION_DEPTH)+1]="s"
set CollisionMapping[19*(COLLISION_DEPTH)+1]="t"
set CollisionMapping[20*(COLLISION_DEPTH)+1]="u"
set CollisionMapping[21*(COLLISION_DEPTH)+1]="v"
set CollisionMapping[22*(COLLISION_DEPTH)+1]="w"
set CollisionMapping[23*(COLLISION_DEPTH)+1]="x"
set CollisionMapping[24*(COLLISION_DEPTH)+1]="y"
set CollisionMapping[25*(COLLISION_DEPTH)+1]="z"
set CollisionMapping[26*(COLLISION_DEPTH)+1]="\\"
// --------------------
// These are all the chars that collide
// Note that i have left out their counterparts (with which they would collide)
set Collisions["A"]= 0
set Collisions["B"]= 1
set Collisions["C"]= 2
set Collisions["D"]= 3
set Collisions["E"]= 4
set Collisions["F"]= 5
set Collisions["G"]= 6
set Collisions["H"]= 7
set Collisions["I"]= 8
set Collisions["J"]= 9
set Collisions["K"]=10
set Collisions["L"]=11
set Collisions["M"]=12
set Collisions["N"]=13
set Collisions["O"]=14
set Collisions["P"]=15
set Collisions["Q"]=16
set Collisions["R"]=17
set Collisions["S"]=18
set Collisions["T"]=19
set Collisions["U"]=20
set Collisions["V"]=21
set Collisions["W"]=22
set Collisions["X"]=23
set Collisions["Y"]=24
set Collisions["Z"]=25
set Collisions["/"]=26
set Collisions["\\"]=26
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
// *************************************************************
// * ImageUtils
// * by Deaod
// *************************************************************
// *
// * CREDITS:
// * - Vexorian (JassHelper, ARGB)
// * - MindWorX and PitzerMike (JassNewGenPack)
// * - Pipedream (Grimoire)
// * - SFilip (TESH)
// *
// * HOW TO IMPORT:
// * * C'n'P the code into your map
// * * If you haven't done that already, import ARGB into your map
// *
// * HOW TO USE:
// * * this library provides you with wrappers for CreateImage and DestroyImage (NewImage and ReleaseImage respectively).
// * Those are necessary to work around creating invalid images. They also catch attempts to destroy images created by WC3 itself
// * (although thats rather conditional, you need to use NewImage and ReleaseImage correctly for it to work).
// * CreateImageEx also exists (for backwards compatibility), but is deprecated.
// *
// * This library also comes with an object oriented wrapper for images, heres how to use those:
// *
// * * declare a variable of type imagex
// *
// * * use imagex.create(string path, real sizeX, real sizeY, real posX, real posY, real posZ, boolean show) to create a new image
// * - path is the path to the imagefile that you want to display
// * - sizeX and sizeY are the dimensions of the image displayed in standard WC3 units of length
// * - posX, posY and posZ specifiy the position where the image is created.
// * Note that this point is the lower left corner of the image.
// *
// * * you can change the path of the image youre displaying by setting the path member of an instance of the imagex struct.
// * Example: set yourimage.path="Path\\To\\The\\Image.blp"
// *
// * * you can change the size of the image by setting the sizeX and sizeY member of an instance of the imagex struct.
// * Example: set yourimage.sizeX=64.
// * set yourimage.sizeY=64.
// * Theres also a method combining those two: yourimage.setSize(real sizex, real sizey)
// * Example: call yourimage.setSize(64., 64.)
// * Sizes work like describen in the create method.
// *
// * * you can change the position of the image by setting the X, Y and Z members of an instance of the imagex struct.
// * Example: set yourimage.X=128.
// * set yourimage.Y=128.
// * set yourimage.Z=0.
// * Theres also a method combining those three: yourimage.setPosition(real x, real y, real z)
// * Example: call yourimage.setPosition(128.,128.,0.)
// * The point specified is the lower left corner of the image.
// *
// * * you can access the individual values of the red, green, blue and alpha channels of the current color of the image
// * with the red, green, blue and alpha members of an instance of the imagex struct.
// * Example: set red = yourimage.red
// * set green = yourimage.green
// * set blue = yourimage.blue
// * set alpha = yourimage.alpha
// * I planned adding a way to change the value of the individual color channels,
// * but unfortunately i cant due to a limitation in JassHelper.
// *
// * * you can change the color of the image by setting the color member of an instance of the imagex struct.
// * Example: set yourimage.color=ARGB(0xFF808080)
// * Refer to ARGBs manual for more information on what is a valid ARGB instance.
// *
// * * you can decide whether to display the image or not by setting the show member of an instance of the imagex struct.
// * Example: set yourimage.show=true
// * true displays the image, false hides it.
// *
// * * you can make the image wrap to the ground by setting the wrap member of an instance of the imagex struct.
// * Example: set yourimage.wrap=true
// * true makes the image wrap to the ground, but makes the image ignore its Z position.
// * false allows you to change the Z position of the image freely.
// * Defaults to false for new instances.
// *
// * * you can change the type of an image by setting the type member of an instance of the imagex struct.
// * Example: set yourimage.type=IMAGE_TYPE_INDICATOR
// * A list of all known image types can be found below.
// * Note that not every image type known works, and that image types influence
// * the order in which images are stacked on top of each other.
// *
// * NOTE: although i have only shown examples for changing the value of members,
// * its also possible to read them, unless stated otherwise.
// *
// * * to destroy an image use yourimage.destroy()
// *
// *************************************************************
library ImageUtils requires ARGB
globals
private constant integer MAX_IMAGES = 8190
// Doesnt get rendered
// using this type in CreateImage returns an invalid image (id of -1)
constant integer IMAGE_TYPE_SHADOW = 0
// Gets drawn above fog of war
constant integer IMAGE_TYPE_SELECTION = 1
// Gets drawn above fog of war
constant integer IMAGE_TYPE_INDICATOR = 2
// Gets drawn above fog of war
constant integer IMAGE_TYPE_OCCLUSION_MASK = 3
// Gets tinted based on time of day ingame.
// Gets drawn below fog of war
constant integer IMAGE_TYPE_UBERSPLAT = 4
// Doesnt get rendered
constant integer IMAGE_TYPE_TOPMOST = 5
private constant integer DEFAULT_IMAGE_TYPE = IMAGE_TYPE_INDICATOR
private ARGB DEFAULT_COLOR = 0xFFFFFFFF
private constant integer INVALID_IMAGE_ID = -1 // go complain about that at Blizzard,
// i have nothing to do with that
endglobals
globals
private boolean array ImageValid[MAX_IMAGES]
endglobals
function NewImage takes string path, real sizex, real sizey, real sizez, real posx, real posy, real posz, real offx, real offy, real offz, integer imagetype returns image
local image i=CreateImage(path, sizex, sizey, sizez, posx, posy, posz, offx, offy, offz, imagetype)
local integer id=GetHandleId(i)
if id<0 then
debug call BJDebugMsg("NewImage: Invalid imagepath! ("+path+")")
return null
elseif id>=MAX_IMAGES then
debug call BJDebugMsg("NewImage: Exceeded Maximum Images!")
return i
endif
set ImageValid[id]=true
return i
endfunction
function CreateImageEx takes string path, real sizex, real sizey, real sizez, real posx, real posy, real posz, real offx, real offy, real offz, integer imagetype returns image
debug call BJDebugMsg("CreateImageEx: Use NewImage instead, CreateImageEx is deprecated!")
return NewImage(path, sizex, sizey, sizez, posx, posy, posz, offx, offy, offz, imagetype)
endfunction
function ReleaseImage takes image i returns nothing
local integer id=GetHandleId(i)
if id>=MAX_IMAGES then
call DestroyImage(i)
elseif id>0 and ImageValid[id] then
call DestroyImage(i)
set ImageValid[id]=false
debug elseif id>0 then
debug call BJDebugMsg("ReleaseImage: Double free of image "+I2S(id)+".")
debug else
debug call BJDebugMsg("ReleaseImage: Trying to free invalid image.")
endif
endfunction
struct imagex[MAX_IMAGES]
private image img
private string Path
private real SizeX
private real SizeY
private real X
private real Y
private real Z
private ARGB Color
private boolean Show
private boolean Wrap
private integer Type
// Get Methods
method operator path takes nothing returns string
return .Path
endmethod
method operator sizeX takes nothing returns real
return .SizeX
endmethod
method operator sizeY takes nothing returns real
return .SizeY
endmethod
method operator x takes nothing returns real
return .X
endmethod
method operator y takes nothing returns real
return .Y
endmethod
method operator z takes nothing returns real
return .Z
endmethod
method operator red takes nothing returns integer
return .Color.red
endmethod
method operator green takes nothing returns integer
return .Color.green
endmethod
method operator blue takes nothing returns integer
return .Color.blue
endmethod
method operator alpha takes nothing returns integer
return .Color.alpha
endmethod
method operator color takes nothing returns ARGB
return .Color
endmethod
method operator show takes nothing returns boolean
return .Show
endmethod
method operator wrap takes nothing returns boolean
return not .Wrap
endmethod
method operator type takes nothing returns integer
return .Type
endmethod
// Private Proxies
private method NewPosition takes nothing returns nothing
call SetImagePosition(.img, .x, .y, 0)
endmethod
private method NewZPos takes real z returns nothing
call SetImageConstantHeight(.img, .wrap, z)
endmethod
private method Recolor takes nothing returns nothing
call SetImageColor(.img, .red, .green, .blue, .alpha)
endmethod
private method Recreate takes nothing returns nothing
if .img!=null then
call ReleaseImage(.img) // never destroy null images, if you dont want hell unleashed
endif
set .img=NewImage(.path, .sizeX, .sizeY, 0, .x, .y, 0, 0, 0, 0, .type)
call .NewZPos(.z)
call .Recolor()
call SetImageRenderAlways(.img, .show)
endmethod
// Set Methods
// Set the image's filepath
method operator path= takes string path returns nothing
set .Path=path
call .Recreate()
endmethod
// Set the size of the image
method operator sizeX= takes real sizex returns nothing
set .SizeX=sizex
call .Recreate()
endmethod
method operator sizeY= takes real sizey returns nothing
set .SizeY=sizey
call .Recreate()
endmethod
method setSize takes real sizex, real sizey returns nothing
set .SizeX=sizex
set .SizeY=sizey
call .Recreate()
endmethod
// Set the position of the image
method operator x= takes real x returns nothing
set .X=x
call .NewPosition()
endmethod
method operator y= takes real y returns nothing
set .Y=y
call .NewPosition()
endmethod
method operator z= takes real z returns nothing
set .Z=z
call .NewZPos(z)
endmethod
method setPosition takes real x, real y, real z returns nothing
set .X=x
set .Y=y
set .Z=z
call .NewPosition()
call .NewZPos(z)
endmethod
// Set the color of the image // due to a limtation in JassHelper, only the operator color= works
/*method operator red= takes integer red returns nothing
set .Color.red=red
call .Recolor()
endmethod
method operator green= takes integer green returns nothing
set .Color.green=green
call .Recolor()
endmethod
method operator blue= takes integer blue returns nothing
set .Color.blue=blue
call .Recolor()
endmethod
method operator alpha= takes integer alpha returns nothing
set .Color.alpha=alpha
call .Recolor()
endmethod*/
method operator color= takes ARGB new returns nothing
set .Color=new
call .Recolor()
endmethod
// Do you want to display the image?
method operator show= takes boolean show returns nothing
set .Show=show
call SetImageRenderAlways(.img, .show)
endmethod
method operator wrap= takes boolean wrap returns nothing
set .Wrap=not wrap
call .NewZPos(.z)
endmethod
// On which layer should the image be rendered?
method operator type= takes integer imageType returns nothing
set .Type=imageType
call SetImageType(.img, imageType)
endmethod
// constructor and destructor
static method create takes string path, real sizeX, real sizeY, real posX, real posY, real posZ, boolean show returns thistype
local thistype s=.allocate()
set s.Path=path
set s.SizeX=sizeX
set s.SizeY=sizeY
set s.X=posX
set s.Y=posY
set s.Z=posZ
set s.Show=show
set s.Wrap=false
set s.Type=DEFAULT_IMAGE_TYPE
set s.Color=DEFAULT_COLOR
call s.Recreate()
return s
endmethod
method onDestroy takes nothing returns nothing
if .img!=null then
call ReleaseImage(.img)
endif
set .img=null
endmethod
private static method onInit takes nothing returns nothing
if GetHandleId(CreateImage("ReplaceableTextures\\CommandButtons\\BTNSlowOn.blp", 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)) != null then
debug call BJDebugMsg("ImageUtils: image(null) already allocated, there might be errors")
endif
endmethod
endstruct
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library Table
//***************************************************************
//* Table object 3.0
//* ------------
//*
//* set t=Table.create() - instanceates a new table object
//* call t.destroy() - destroys it
//* t[1234567] - Get value for key 1234567
//* (zero if not assigned previously)
//* set t[12341]=32 - Assigning it.
//* call t.flush(12341) - Flushes the stored value, so it
//* doesn't use any more memory
//* t.exists(32) - Was key 32 assigned? Notice
//* that flush() unassigns values.
//* call t.reset() - Flushes the whole contents of the
//* Table.
//*
//* call t.destroy() - Does reset() and also recycles the id.
//*
//* If you use HandleTable instead of Table, it is the same
//* but it uses handles as keys, the same with StringTable.
//*
//* You can use Table on structs' onInit if the struct is
//* placed in a library that requires Table or outside a library.
//*
//* You can also do 2D array syntax if you want to touch
//* mission keys directly, however, since this is shared space
//* you may want to prefix your mission keys accordingly:
//*
//* set Table["thisstring"][ 7 ] = 2
//* set Table["thisstring"][ 5 ] = Table["thisstring"][7]
//*
//***************************************************************
//=============================================================
globals
private constant integer MAX_INSTANCES=8100 //400000
//Feel free to change max instances if necessary, it will only affect allocation
//speed which shouldn't matter that much.
//=========================================================
private hashtable ht
endglobals
private struct GTable[MAX_INSTANCES]
method reset takes nothing returns nothing
call FlushChildHashtable(ht, integer(this) )
endmethod
private method onDestroy takes nothing returns nothing
call this.reset()
endmethod
//=============================================================
// initialize it all.
//
private static method onInit takes nothing returns nothing
set ht = InitHashtable()
endmethod
endstruct
//Hey: Don't instanciate other people's textmacros that you are not supposed to, thanks.
//! textmacro Table__make takes name, type, key
struct $name$ extends GTable
method operator [] takes $type$ key returns integer
return LoadInteger(ht, integer(this), $key$)
endmethod
method operator []= takes $type$ key, integer value returns nothing
call SaveInteger(ht, integer(this) ,$key$, value)
endmethod
method flush takes $type$ key returns nothing
call RemoveSavedInteger(ht, integer(this), $key$)
endmethod
method exists takes $type$ key returns boolean
return HaveSavedInteger( ht, integer(this) ,$key$)
endmethod
static method flush2D takes string firstkey returns nothing
call $name$(- StringHash(firstkey)).reset()
endmethod
static method operator [] takes string firstkey returns $name$
return $name$(- StringHash(firstkey) )
endmethod
endstruct
//! endtextmacro
//! runtextmacro Table__make("Table","integer","key" )
//! runtextmacro Table__make("StringTable","string", "StringHash(key)" )
//! runtextmacro Table__make("HandleTable","handle","GetHandleId(key)" )
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library ARGB initializer init
//******************************************************************************
//*
//* ARGB 1.1
//* ====
//* For your color needs.
//*
//* An ARGB object is a by-value struct, this means that assigning copies the
//* contents of the struct and that you don't have to use .destroy(), the
//* downside is that you cannot assign its members (can't do set c.r= 123 )
//*
//* This library should have plenty of uses, for example, if your spell involves
//* some unit recoloring you can allow users to input the color in the config
//* section as 0xAARRGGBB and you can then use this to decode that stuff.
//*
//* You can also easily merge two colors and make fading effects using ARGB.mix
//*
//* There's ARGB.fromPlayer which gets an ARGB object containing the player's
//* color. Then you can use the previous utilities on it.
//*
//* The .str() instance method can recolor a string, and the recolorUnit method
//* will apply the ARGB on a unit
//*
//* For other uses, you can use the .red, .green, .blue and .alpha members to get
//* an ARGB object's color value (from 0 to 255).
//*
//* structs that have a recolor method that takes red,green,blue and alpha as 0.255
//* integers can implement the ARGBrecolor module to gain an ability to quickly
//* recolor using an ARGB object.
//*
//********************************************************************************
//=================================================================================
globals
private string array i2cc
endglobals
//this double naming stuff is beginning to make me insane, if only TriggerEvaluate() wasn't so slow...
struct ARGB extends array
static method create takes integer a, integer r, integer g, integer b returns ARGB
return ARGB(b + g*0x100 + r*0x10000 + a*0x1000000)
endmethod
static method fromPlayer takes player p returns ARGB
local playercolor pc=GetPlayerColor(p)
if(pc==PLAYER_COLOR_RED) then
return 0xFFFF0303
elseif(pc==PLAYER_COLOR_BLUE) then
return 0xFF0042FF
elseif(pc==PLAYER_COLOR_CYAN) then
return 0xFF1CB619
elseif(pc==PLAYER_COLOR_PURPLE) then
return 0xFF540081
elseif(pc==PLAYER_COLOR_YELLOW) then
return 0xFFFFFF01
elseif(pc==PLAYER_COLOR_ORANGE) then
return 0xFFFE8A0E
elseif(pc==PLAYER_COLOR_GREEN) then
return 0xFF20C000
elseif(pc==PLAYER_COLOR_PINK) then
return 0xFFE55BB0
elseif(pc==PLAYER_COLOR_LIGHT_GRAY) then
return 0xFF959697
elseif(pc==PLAYER_COLOR_LIGHT_BLUE) then
return 0xFF7EBFF1
elseif(pc==PLAYER_COLOR_AQUA) then
return 0xFF106246
elseif(pc==PLAYER_COLOR_BROWN) then
return 0xFF4E2A04
endif
return 0xFF111111
endmethod
method operator alpha takes nothing returns integer
if( integer(this) <0) then
return 0x80+(-(-integer(this)+0x80000000))/0x1000000
else
return (integer(this))/0x1000000
endif
endmethod
method operator alpha= takes integer na returns ARGB
local integer a
local integer r
local integer g
local integer b
local integer col=integer(this)
if (col<0) then
set col=-(-col+0x80000000)
set a=0x80+col/0x1000000
set col=col-(a-0x80)*0x1000000
else
set a=col/0x1000000
set col=col-a*0x1000000
endif
set r=col/0x10000
set col=col-r*0x10000
set g=col/0x100
set b=col-g*0x100
return ARGB(b + g*0x100 + r*0x10000 + na*0x1000000)
endmethod
method operator red takes nothing returns integer
local integer c=integer(this)*0x100
if(c<0) then
return 0x80+(-(-c+0x80000000))/0x1000000
else
return c/0x1000000
endif
endmethod
method operator red= takes integer nr returns ARGB
local integer a
local integer r
local integer g
local integer b
local integer col=integer(this)
if (col<0) then
set col=-(-col+0x80000000)
set a=0x80+col/0x1000000
set col=col-(a-0x80)*0x1000000
else
set a=col/0x1000000
set col=col-a*0x1000000
endif
set r=col/0x10000
set col=col-r*0x10000
set g=col/0x100
set b=col-g*0x100
return ARGB(b + g*0x100 + nr*0x10000 + a*0x1000000)
endmethod
method operator green takes nothing returns integer
local integer c=integer(this)*0x10000
if(c<0) then
return 0x80+(-(-c+0x80000000))/0x1000000
else
return c/0x1000000
endif
endmethod
method operator green= takes integer ng returns ARGB
local integer a
local integer r
local integer g
local integer b
local integer col=integer(this)
if (col<0) then
set col=-(-col+0x80000000)
set a=0x80+col/0x1000000
set col=col-(a-0x80)*0x1000000
else
set a=col/0x1000000
set col=col-a*0x1000000
endif
set r=col/0x10000
set col=col-r*0x10000
set g=col/0x100
set b=col-g*0x100
return ARGB(b + ng*0x100 + r*0x10000 + a*0x1000000)
endmethod
//=======================================================
//
//
method operator blue takes nothing returns integer
local integer c=integer(this)*0x1000000
if(c<0) then
return 0x80+(-(-c+0x80000000))/0x1000000
else
return c/0x1000000
endif
endmethod
method operator blue= takes integer nb returns ARGB
local integer a
local integer r
local integer g
local integer b
local integer col=integer(this)
if (col<0) then
set col=-(-col+0x80000000)
set a=0x80+col/0x1000000
set col=col-(a-0x80)*0x1000000
else
set a=col/0x1000000
set col=col-a*0x1000000
endif
set r=col/0x10000
set col=col-r*0x10000
set g=col/0x100
set b=col-g*0x100
return ARGB(nb + g*0x100 + r*0x10000 + a*0x1000000)
endmethod
//====================================================================
// Mixes two colors, s would be a number 0<=s<=1 that determines
// the weight given to color c2.
//
// mix(c1,c2,0) = c1
// mix(c1,c2,1) = c2
// mix(c1,c2,0.5) = Mixing the colors c1 and c2 in equal proportions.
//
static method mix takes ARGB c1, ARGB c2, real s returns ARGB
//widest function ever
return ARGB( R2I(c2.blue*s+c1.blue*(1-s)+0.5) + R2I(c2.green*s+c1.green*(1-s)+0.5)*0x100 + R2I(c2.red*s+c1.red*(1-s)+0.5)*0x10000 + R2I((c2.alpha*s)+(c1.alpha*(1-s))+0.5)*0x1000000)
endmethod
method str takes string s returns string
return "|c"+i2cc[.alpha]+i2cc[.red]+i2cc[.green]+i2cc[.blue]+s+"|r"
endmethod
method recolorUnit takes unit u returns nothing
local integer a
local integer r
local integer g
local integer b
local integer col=integer(this)
if (col<0) then
set col=-(-col+0x80000000)
set a=0x80+col/0x1000000
set col=col-(a-0x80)*0x1000000
else
set a=col/0x1000000
set col=col-a*0x1000000
endif
set r=col/0x10000
set col=col-r*0x10000
set g=col/0x100
set b=col-g*0x100
call SetUnitVertexColor(u,r,g,b,a)
endmethod
endstruct
module ARGBrecolor
method ARGBrecolor takes ARGB color returns nothing
local integer a
local integer r
local integer g
local integer b
local integer col=integer(this)
if (col<0) then
set col=-(-col+0x80000000)
set a=0x80+col/0x1000000
set col=col-(a-0x80)*0x1000000
else
set a=col/0x1000000
set col=col-a*0x1000000
endif
set r=col/0x10000
set col=col-r*0x10000
set g=col/0x100
set b=col-g*0x100
call this.recolor(r, g , b, a)
endmethod
endmodule
private function init takes nothing returns nothing
local integer i=0
// Don't run textmacros you don't own!
//! textmacro ARGB_CHAR takes int, chr
set i=0
loop
exitwhen i==16
set i2cc[$int$*16+i]="$chr$"+i2cc[$int$*16+i]
set i2cc[i*16+$int$]=i2cc[i*16+$int$]+"$chr$"
set i=i+1
endloop
//! endtextmacro
//! runtextmacro ARGB_CHAR( "0","0")
//! runtextmacro ARGB_CHAR( "1","1")
//! runtextmacro ARGB_CHAR( "2","2")
//! runtextmacro ARGB_CHAR( "3","3")
//! runtextmacro ARGB_CHAR( "4","4")
//! runtextmacro ARGB_CHAR( "5","5")
//! runtextmacro ARGB_CHAR( "6","6")
//! runtextmacro ARGB_CHAR( "7","7")
//! runtextmacro ARGB_CHAR( "8","8")
//! runtextmacro ARGB_CHAR( "9","9")
//! runtextmacro ARGB_CHAR("10","A")
//! runtextmacro ARGB_CHAR("11","B")
//! runtextmacro ARGB_CHAR("12","C")
//! runtextmacro ARGB_CHAR("13","D")
//! runtextmacro ARGB_CHAR("14","E")
//! runtextmacro ARGB_CHAR("15","F")
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library Init initializer Init uses TextSplat
private function Init takes nothing returns nothing
local unit u=CreateUnit(Player(0), 'hfoo', 0,0,0)
local textsplat t=CreateTextSplat(TREBUCHET)
local string str = " !\"#$%%&'()*+,-./012345678|n9:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
call SetCameraPosition(0,0)
call t.setText(str, 10, TEXTSPLAT_TEXT_ALIGN_CENTER)
call SetTextSplatPos(t, -t.width/2, -256, 0)
call SetTextSplatVelocity(t, 0, 48)
call SetTextSplatLifespan(t, 10)
call SetTextSplatFadepoint(t, 8)
call SetTextSplatPermanent(t, false)
endfunction
endlibrary
library FontInit initializer Init uses Font
globals
font TREBUCHET
endglobals
private function Init takes nothing returns nothing
set TREBUCHET=font.create(0) // no parent
call TREBUCHET.addChar(" ", 16, "Trebuchet\\32.blp")
call TREBUCHET.addChar("!", 8, "Trebuchet\\33.blp")
call TREBUCHET.addChar("\"", 10, "Trebuchet\\34.blp")
call TREBUCHET.addChar("#", 19, "Trebuchet\\35.blp")
call TREBUCHET.addChar("$", 16, "Trebuchet\\36.blp")
call TREBUCHET.addChar("%", 20, "Trebuchet\\37.blp")
call TREBUCHET.addChar("&", 22, "Trebuchet\\38.blp")
call TREBUCHET.addChar("'", 6, "Trebuchet\\39.blp")
call TREBUCHET.addChar("(", 11, "Trebuchet\\40.blp")
call TREBUCHET.addChar(")", 10, "Trebuchet\\41.blp")
call TREBUCHET.addChar("*", 14, "Trebuchet\\42.blp")
call TREBUCHET.addChar("+", 16, "Trebuchet\\43.blp")
call TREBUCHET.addChar(",", 9, "Trebuchet\\44.blp")
call TREBUCHET.addChar("-", 10, "Trebuchet\\45.blp")
call TREBUCHET.addChar(".", 8, "Trebuchet\\46.blp")
call TREBUCHET.addChar("/", 15, "Trebuchet\\47.blp")
call TREBUCHET.addChar("0", 18, "Trebuchet\\48.blp")
call TREBUCHET.addChar("1", 11, "Trebuchet\\49.blp")
call TREBUCHET.addChar("2", 18, "Trebuchet\\50.blp")
call TREBUCHET.addChar("3", 16, "Trebu\\51.blp")
call TREBUCHET.addChar("4", 19, "Trebuchet\\52.blp")
call TREBUCHET.addChar("5", 16, "Trebuchet\\53.blp")
call TREBUCHET.addChar("6", 18, "Trebuchet\\54.blp")
call TREBUCHET.addChar("7", 18, "Trebuchet\\55.blp")
call TREBUCHET.addChar("8", 18, "Trebuchet\\56.blp")
call TREBUCHET.addChar("9", 17, "Trebuchet\\57.blp")
call TREBUCHET.addChar(":", 8, "Trebuchet\\58.blp")
call TREBUCHET.addChar(";", 9, "Trebuchet\\59.blp")
call TREBUCHET.addChar("<", 15, "Trebuchet\\60.blp")
call TREBUCHET.addChar("=", 17, "Trebuchet\\61.blp")
call TREBUCHET.addChar(">", 15, "Trebuchet\\62.blp")
call TREBUCHET.addChar("?", 13, "Trebuchet\\63.blp")
call TREBUCHET.addChar("@", 24, "Trebuchet\\64.blp")
call TREBUCHET.addChar("A", 22, "Trebuchet\\65.blp")
call TREBUCHET.addChar("B", 18, "Trebuchet\\66.blp")
call TREBUCHET.addChar("C", 20, "Trebuchet\\67.blp")
call TREBUCHET.addChar("D", 19, "Trebuchet\\68.blp")
call TREBUCHET.addChar("E", 17, "Trebuchet\\69.blp")
call TREBUCHET.addChar("F", 18, "Trebuchet\\70.blp")
call TREBUCHET.addChar("G", 21, "Trebuchet\\71.blp")
call TREBUCHET.addChar("H", 20, "Trebuchet\\72.blp")
call TREBUCHET.addChar("I", 7, "Trebuchet\\73.blp")
call TREBUCHET.addChar("J", 15, "Trebuchet\\74.blp")
call TREBUCHET.addChar("K", 20, "Trebuchet\\75.blp")
call TREBUCHET.addChar("L", 17, "Trebuchet\\76.blp")
call TREBUCHET.addChar("M", 26, "Trebuchet\\77.blp")
call TREBUCHET.addChar("N", 19, "Trebuchet\\78.blp")
call TREBUCHET.addChar("O", 22, "Trebuchet\\79.blp")
call TREBUCHET.addChar("P", 18, "Trebuchet\\80.blp")
call TREBUCHET.addChar("Q", 26, "Trebuchet\\81.blp")
call TREBUCHET.addChar("R", 19, "Trebuchet\\82.blp")
call TREBUCHET.addChar("S", 16, "Trebuchet\\83.blp")
call TREBUCHET.addChar("T", 21, "Trebuchet\\84.blp")
call TREBUCHET.addChar("U", 19, "Trebuchet\\85.blp")
call TREBUCHET.addChar("V", 21, "Trebuchet\\86.blp")
call TREBUCHET.addChar("W", 29, "Trebuchet\\87.blp")
call TREBUCHET.addChar("X", 20, "Trebuchet\\88.blp")
call TREBUCHET.addChar("Y", 21, "Trebuchet\\89.blp")
call TREBUCHET.addChar("Z", 18, "Trebuchet\\90.blp")
call TREBUCHET.addChar("[", 11, "Trebuchet\\91.blp")
call TREBUCHET.addChar("\\", 14, "Trebuchet\\92.blp")
call TREBUCHET.addChar("]", 11, "Trebuchet\\93.blp")
call TREBUCHET.addChar("^", 15, "Trebuchet\\94.blp")
call TREBUCHET.addChar("_", 20, "Trebuchet\\95.blp")
call TREBUCHET.addChar("`", 9, "Trebuchet\\96.blp")
call TREBUCHET.addChar("a", 16, "Trebuchet\\97.blp")
call TREBUCHET.addChar("b", 13, "Trebuchet\\98.blp")
call TREBUCHET.addChar("c", 15, "Trebuchet\\99.blp")
call TREBUCHET.addChar("d", 14, "Trebuchet\\100.blp")
call TREBUCHET.addChar("e", 12, "Trebuchet\\101.blp")
call TREBUCHET.addChar("f", 13, "Trebuchet\\102.blp")
call TREBUCHET.addChar("g", 16, "Trebuchet\\103.blp")
call TREBUCHET.addChar("h", 14, "Trebuchet\\104.blp")
call TREBUCHET.addChar("i", 5, "Trebuchet\\105.blp")
call TREBUCHET.addChar("j", 11, "Trebuchet\\106.blp")
call TREBUCHET.addChar("k", 15, "Trebuchet\\107.blp")
call TREBUCHET.addChar("l", 13, "Trebuchet\\108.blp")
call TREBUCHET.addChar("m", 19, "Trebuchet\\109.blp")
call TREBUCHET.addChar("n", 14, "Trebuchet\\110.blp")
call TREBUCHET.addChar("o", 16, "Trebuchet\\111.blp")
call TREBUCHET.addChar("p", 14, "Trebuchet\\112.blp")
call TREBUCHET.addChar("q", 18, "Trebuchet\\113.blp")
call TREBUCHET.addChar("r", 14, "Trebuchet\\114.blp")
call TREBUCHET.addChar("s", 12, "Trebuchet\\115.blp")
call TREBUCHET.addChar("t", 16, "Trebuchet\\116.blp")
call TREBUCHET.addChar("u", 14, "Trebuchet\\117.blp")
call TREBUCHET.addChar("v", 16, "Trebuchet\\118.blp")
call TREBUCHET.addChar("w", 21, "Trebuchet\\119.blp")
call TREBUCHET.addChar("x", 15, "Trebuchet\\120.blp")
call TREBUCHET.addChar("y", 16, "Trebuchet\\121.blp")
call TREBUCHET.addChar("z", 13, "Trebuchet\\122.blp")
call TREBUCHET.addChar("{", 14, "Trebuchet\\123.blp")
call TREBUCHET.addChar("|", 6, "Trebuchet\\124.blp")
call TREBUCHET.addChar("}", 14, "Trebuchet\\125.blp")
call TREBUCHET.addChar("~", 15, "Trebuchet\\126.blp")
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library ImageUtilsDemo initializer Init uses ImageUtils
private function Init takes nothing returns nothing
// create a new image: // Note that because this uses an invalid path it will generate errors in debug mode
local imagex i=imagex.create("some\\Path.blp", /*Size in X*/32, /*Size inY*/32, /*X pos*/0, /*Y pos*/0, /*Z pos*/0, /*show image?*/ true)
// you can change the path on the fly like this:
set i.path="new\\path.blp" // still no valid path --> errors in debug mode
// you can also change the size of the image on the fly:
set i.sizeX=48
set i.sizeY=48
// for speed reasons i added a method that combines those two
call i.setSize(/*Size X*/48, /*Size Y*/48)
// you can change the position of the image like this:
set i.x=32
set i.y=32
set i.z=32
// for speed reasons ive also added a method that combines those three
call i.setPosition(/*X*/32, /*Y*/32, /*Z*/32)
// you can also change the color of the image:
set i.color=0xFFFFFFFF // format: 0xAARRGGBB // refer to ARGBs manual for more information
// i had planned to add the following as well,
/* but due to limiations in JassHelper they are currently read only
set i.red=0xFF
set i.green=0xFF
set i.blue=0xFF
set i.alpha=0xFF*/
// you can also change the type of the image on the fly
set i.type=IMAGE_TYPE_SELECTION
/* the available IMAGE_TYPEs are:
IMAGE_TYPE_SHADOW
IMAGE_TYPE_SELECTION
IMAGE_TYPE_INDICATOR
IMAGE_TYPE_OCCLUSION_MASK
IMAGE_TYPE_UBERSPLAT
IMAGE_TYPE_TOPMOST
unfortunately, SHADOW and TOPMOST currently dont work*/
// you can also show and hide the image
set i.show=true // true to display the image, false to hide it
// when youre done with the image, destroy it like this:
call i.destroy()
// every member also has a read counterpart, except for the method members, obviously
endfunction
endlibrary