// ************************************************************* // * TextSplat -- 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 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 CHARS_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 function IsHexadecimal takes string s returns boolean local integer i=0 local integer l=StringLength(s) loop exitwhen i>=l if IsHex[SubString(s, i, i+1)]==0 then // one illegal char aborts return false endif set i=i+1 endloop return true endfunction 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 globals private real array TSPCharXOffset private real array TSPCharYOffset private ARGB array TSPCharColor private integer array TSPCharLine private boolean array TSPCharUsesDefaultColor private real array TSPLineWidth private real TSPWidth private integer TSPCount private integer TSPChunkCount private integer TSPSourceStringLength private integer TSPCurrentLine private ARGB TSPCurrentColor private boolean TSPCustomColor private string TSPCurrentChar private string TSPResultingString private char TSPChar private real TSPSourceX private real TSPSourceY private real TSPOffsetCorrection private location LocZ=Location(0,0) endglobals // this is a bit hacky... but necessary to avoid hitting the op limit. private function processText takes ARGB clr, font F, string text, real height, integer aligntype, integer base returns nothing loop exitwhen TSPChunkCount-base>=CHARS_PER_CHUNK or TSPCount>=TSPSourceStringLength set TSPCurrentChar=SubString(text, TSPCount, TSPCount+1) if TSPCurrentChar=="\n" or TSPCurrentChar=="\r" or (TSPCurrentChar=="|" and SubString(text, TSPCount+1,TSPCount+2)=="n") then // new line if TSPLineWidth[TSPCurrentLine]>TSPWidth or TSPCurrentLine==0 then set TSPWidth=TSPLineWidth[TSPCurrentLine] endif set TSPCurrentLine=TSPCurrentLine+1 set TSPLineWidth[TSPCurrentLine]=0 if TSPCurrentChar=="|" then set TSPCount=TSPCount+1 endif elseif TSPCurrentChar=="|" and SubString(text, TSPCount+1, TSPCount+2)=="c" and StringLength(SubString(text, TSPCount+2, TSPCount+10))==8 and IsHexadecimal(SubString(text, TSPCount+2, TSPCount+10)) then // color tag set TSPCustomColor=true set TSPCurrentColor=ARGB.create(Hex2Dec[SubString(text, TSPCount+2, TSPCount+4)], Hex2Dec[SubString(text, TSPCount+4, TSPCount+6)], Hex2Dec[SubString(text, TSPCount+6, TSPCount+8)], Hex2Dec[SubString(text, TSPCount+8, TSPCount+10)]) set TSPCount=TSPCount+9 elseif TSPCurrentChar=="|" and SubString(text, TSPCount+1, TSPCount+2)=="r" then // reset color set TSPCustomColor=false set TSPCurrentColor=clr set TSPCount=TSPCount+1 else // normal char set TSPResultingString=TSPResultingString+TSPCurrentChar set TSPLineWidth[TSPCurrentLine]=TSPLineWidth[TSPCurrentLine]+(F[TSPCurrentChar].width*TEXT_SIZE_TO_IMAGE_SIZE*height/DEFAULT_IMAGE_SIZE) set TSPCharYOffset[TSPChunkCount]=TSPCurrentLine*height*TEXT_SIZE_TO_IMAGE_SIZE if (TSPChunkCount==0) or (TSPCharYOffset[TSPChunkCount-1]=CHARS_PER_CHUNK or TSPCount>=TSPChunkCount if TSPCount==0 or TSPCharLine[TSPCount]>TSPCharLine[TSPCount-1] then set TSPOffsetCorrection=0 endif set TSPCurrentChar=SubString(TSPResultingString, TSPCount, TSPCount+1) if TSPCurrentChar=="|" and SubString(TSPResultingString, TSPCount+1, TSPCount+2)=="i" then // image set i=TSPCount+2 set b=false loop exitwhen SubString(TSPResultingString, i, i+1)=="|" and SubString(TSPResultingString, i+1, i+2)=="i" if i>=TSPSourceStringLength-2 then // weve reached the end of the text we want to display // dont do anything set b=true exitwhen true endif set i=i+1 endloop if (not b) and F.getImage(SubString(TSPResultingString, TSPCount+2, i))>0 then set TSPChar=char.createImage(F, SubString(TSPResultingString, TSPCount+2, i), TSPSourceX+TSPCharXOffset[TSPCount]+( TextAlignBonus[aligntype]*(TSPWidth-TSPLineWidth[TSPCharLine[TSPCount]]) )-TSPOffsetCorrection, TSPSourceY-TSPCharYOffset[TSPCount], z, height) set TSPOffsetCorrection=TSPOffsetCorrection+(TSPCharXOffset[i+2])-(TSPCharXOffset[TSPCount])-(F.getImage(SubString(TSPResultingString, TSPCount+2, i)).width/DEFAULT_IMAGE_SIZE*height*TEXT_SIZE_TO_IMAGE_SIZE) loop exitwhen TSPCount>=i+1 set t[TSPCount]=0 set TSPCount=TSPCount+1 endloop else set TSPChar=char.createImage(F, TSPCurrentChar, TSPSourceX+TSPCharXOffset[TSPCount]+( TextAlignBonus[aligntype]*(TSPWidth-TSPLineWidth[TSPCharLine[TSPCount]]) )-TSPOffsetCorrection, TSPSourceY-TSPCharYOffset[TSPCount], z, height) endif else set TSPChar=char.createChar(F, TSPCurrentChar, TSPSourceX+TSPCharXOffset[TSPCount]+( TextAlignBonus[aligntype]*(TSPWidth-TSPLineWidth[TSPCharLine[TSPCount]]) )-TSPOffsetCorrection, TSPSourceY-TSPCharYOffset[TSPCount], z, height) endif set TSPChar.DefaultColor=TSPCharUsesDefaultColor[TSPCount] set TSPChar.color=TSPCharColor[TSPCount] set TSPChar.Show=visible call SetImageRenderAlways(TSPChar.Img, visible) set t[TSPCount]=integer(TSPChar) set TSPCount=TSPCount+1 endloop 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 TSPChunkCount=0 set TSPSourceStringLength=StringLength(text) set TSPCurrentLine=0 set TSPCurrentColor=.BGColor set TSPCustomColor=false set TSPResultingString="" set TSPWidth=0 // lets clean up old stuff we dont need anymore call cleanSplat.evaluate(.Chars, .CharCount) set TSPLineWidth[0]=0 // set TSPCount=0 loop exitwhen TSPCount>=TSPSourceStringLength // TSPCount gets incremented in processText call processText.evaluate(.BGColor, .F, text, height, aligntype, TSPChunkCount) endloop if TSPCurrentLine==0 or TSPLineWidth[TSPCurrentLine]>TSPWidth then set TSPWidth=TSPLineWidth[TSPCurrentLine] endif // actually display the shit set TSPSourceX=.X set TSPSourceY=.Y+TSPCurrentLine*height*TEXT_SIZE_TO_IMAGE_SIZE set TSPOffsetCorrection=0 set TSPCount=0 loop exitwhen TSPCount>=TSPChunkCount call displayText.evaluate(height, aligntype, .Z, .Visible, .F, .Chars, TSPCount) endloop set .CharCount=TSPCount set .Text=text set .Width=TSPWidth set .Height=(TSPCurrentLine+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