package StringUtils import NoWurst import LinkedList import Texttag import Interpolation import TypeCasting import Annotations import ErrorHandling /** * Credits go here: http://www.hiveworkshop.com/forums/jass-resources-412/snippet-ascii-190746/ */ string array c2s int array s2c int array width constant MAX_INDEX = '~' + 1 constant DEFAULT_WIDTH = 0 constant DEFAULT_STRING = "" constant WC3LIMIT_OBJECTS_DESCRIPTION_LENGTH = 1023 // Should be a global for whole WurstScript or StdLib at least public function texttag.center(vec3 pos, string message, real size) returns texttag var str = message while str.contains("|cff") let idx = str.indexOf("|cff") str = str.substring(0, idx) + str.substring(idx + 10, str.length()) this..setPos(pos - vec2(str.getWidth() / 1000. * bezier3(3.0, 8.0, 11.5, size / 25) * 6.5, 0)) ..setText(message, size) return this public function createCenteredTexttag(vec3 pos, string message, real size) returns texttag return CreateTextTag() ..setPermanent(true) ..setText(message, size) ..center(pos, message, size) ..setVisibility(true) public tuple char(int c) /** Returns the width of the string */ public function string.getWidth() returns int var width = 0 for i = 0 to this.length() - 1 width += char(this.charAt(i)).getWidth() return width public function char(string s) returns char if s == "/" return char('/') else if "\\" == s return char('\') let a = s2c[s.getHash() div 0x1F0748 + 0x3EA] if s != c2s[a] return char(a + 32) return char(a) public function char.toString() returns string if this.c > MAX_INDEX return DEFAULT_STRING return c2s[this.c] public function char.toInt() returns int return this.c public function char.getWidth() returns int if this.c > MAX_INDEX return DEFAULT_WIDTH return width[this.c] public function string.toChar() returns char return char(this) public function string.toCharList() returns LinkedList let res = new LinkedList() for int i = 0 to this.length() - 1 res.add(char(this.charAt(i))) return res public function int.toChar() returns char return char(this) public function charToIndex(char c) returns int return c.toInt() public function charFromIndex(int index) returns char return char(index) /** Splits the string by another string "this..is..an..example" split by the string ".." splits into a list containing four strings ["this", "is", "an", "example"] */ public function string.split(string splitBy) returns LinkedList let list = new LinkedList let offset = splitBy.length() var str = this while true let splitIndex = str.indexOf(splitBy) if splitIndex == -1 list.add(str) break let first = str.substring(0, splitIndex) let second = str.substring(splitIndex + offset, str.length()) list.add(first) str = second return list /** Replaces consecutive repeats of the same string with a single instance Turns "strstr" into "str" */ public function string.reduce(string reduced) returns string let toReduce = reduced + reduced var oldString = this string newString while true newString = oldString.replace(toReduce, reduced) if newString.length() == oldString.length() break else oldString = newString return newString /** Replaces consecutive repeats of the whitespace character with a single instance Turns " " into " " */ public function string.reduce() returns string return this.reduce(" ") public interface ForStringSplitCallback function callback(string str) /** Custom Function which can split strings and runs callback for each string. It can run even with no delimiter present (with single element). Example usage: "H001,H002".forEachIn(",") -> doSomething() */ public function string.forEachIn(string delim, ForStringSplitCallback cb) if this.length() > 0 int i = 0 int pos = this.indexOf(delim, i) if pos == -1 cb.callback(this.substring(i, this.length())) while pos != -1 cb.callback(this.substring(i, pos)) pos += 1 i = pos pos = this.indexOf(delim, pos) if pos == -1 cb.callback(this.substring(i, this.length())) /** Checks whether a string is a number or not.*/ public function string.isNumber() returns bool var isNumber = false var hasDecimalPlaces = false for int i = 0 to this.length()-1 if (this.charAt(i) == "-" and i == 0) or this.charAt(i) == "0" or this.charAt(i) == "1" or this.charAt(i) == "2" or this.charAt(i) == "3" or this.charAt(i) == "4" or this.charAt(i) == "5" or this.charAt(i) == "6" or this.charAt(i) == "7" or this.charAt(i) == "8" or this.charAt(i) == "9" isNumber = true else if this.charAt(i) == "." and not hasDecimalPlaces hasDecimalPlaces = true else return false return isNumber /** Checks whether a string is valid in terms of max WC3 string length for various usages (Ability Description, Quest Description,...).*/ public function string.isValidDescription() returns bool var isValid = true if this.length() > WC3LIMIT_OBJECTS_DESCRIPTION_LENGTH isValid = false error("String <"+this+"> is too long. Length: "+this.length().toString()) return isValid /** Replaces all occurences of any character from given charlist by a given replacement string.*/ public function string.replaceChars(string charset, string replacementChar) returns string var newString = this for replaceChar in charset newString = newString.contains(replaceChar) ? newString.replace(replaceChar, replacementChar) : newString return newString @compiletime function initialize() c2sInit() s2cInit() widthInit() init initialize() stringToIndex("") // just to remove the TypeCasting warning function widthInit() width[0] = 0 width[1] = 0 width[2] = 0 width[3] = 0 width[4] = 0 width[5] = 0 width[6] = 0 width[7] = 0 //\a width[8] = 0 //\b width[9] = 0 //\t width[10] = 1000000000 //\n width[11] = 0 //\v width[12] = 0 //\f width[13] = 0 //\r width[14] = 0 width[15] = 0 width[16] = 0 width[17] = 0 width[18] = 0 width[19] = 0 width[20] = 0 width[21] = 0 width[22] = 0 width[23] = 0 width[24] = 0 width[25] = 0 width[26] = 0 width[27] = 0 //\e width[28] = 0 width[29] = 0 width[30] = 0 width[31] = 0 width[' '] = 70 width['!'] = 60 width['"'] = 80 width['#'] = 180 width['$'] = 140 width['%'] = 199 width['&'] = 219 width['''] = 40 width['('] = 80 width[')'] = 80 width['*'] = 121 width['+'] = 140 width[','] = 55 width['-'] = 104 width['.'] = 51 width['/'] = 121 width['0'] = 160 width['1'] = 60 width['2'] = 160 width['3'] = 160 width['4'] = 180 width['5'] = 160 width['6'] = 160 width['7'] = 140 width['8'] = 160 width['9'] = 160 width[':'] = 60 width[';'] = 60 width['<'] = 140 width['='] = 140 width['>'] = 140 width['?'] = 140 width['@'] = 199 width['A'] = 206 width['B'] = 162 width['C'] = 183 width['D'] = 193 width['E'] = 153 width['F'] = 122 width['G'] = 204 width['H'] = 200 width['I'] = 77 width['J'] = 80 width['K'] = 183 width['L'] = 148 width['M'] = 264 width['N'] = 200 width['O'] = 225 width['P'] = 156 width['Q'] = 237 width['R'] = 179 width['S'] = 156 width['T'] = 151 width['U'] = 187 width['V'] = 183 width['W'] = 282 width['X'] = 204 width['Y'] = 179 width['Z'] = 179 width['['] = 80 width['\'] = 100 width[']'] = 80 width['^'] = 140 width['_'] = 140 width['`'] = 100 width['a'] = 151 width['b'] = 159 width['c'] = 147 width['d'] = 162 width['e'] = 159 width['f'] = 98 width['g'] = 176 width['h'] = 159 width['i'] = 65 width['j'] = 77 width['k'] = 147 width['l'] = 68 width['m'] = 227 width['n'] = 156 width['o'] = 166 width['p'] = 162 width['q'] = 162 width['r'] = 98 width['s'] = 126 width['t'] = 100 width['u'] = 159 width['v'] = 159 width['w'] = 229 width['x'] = 159 width['y'] = 159 width['z'] = 147 width['{'] = 80 width['|'] = 60 width['}'] = 80 width['~'] = 140 width[127] = 0 function s2cInit() for i = 0 to MAX_INDEX if c2s[i].toUpperCase() == c2s[i] s2c[StringHash(c2s[i]) div 0x1F0748 + 0x3EA] = i function c2sInit() c2s[0] = "" c2s[1] = "" c2s[2] = "" c2s[3] = "" c2s[4] = "" c2s[5] = "" c2s[6] = "" c2s[7] = "" //\a c2s[8] = "" //\b c2s[9] = "\t" c2s[10] = "\n" c2s[11] = "" //\v c2s[12] = "" //\f c2s[13] = "\r" c2s[14] = "" c2s[15] = "" c2s[16] = "" c2s[17] = "" c2s[18] = "" c2s[19] = "" c2s[20] = "" c2s[21] = "" c2s[22] = "" c2s[23] = "" c2s[24] = "" c2s[25] = "" c2s[26] = "" c2s[27] = "" //\e c2s[28] = "" c2s[29] = "" c2s[30] = "" c2s[31] = "" c2s[' '] = " " c2s['!'] = "!" c2s['"'] = "\"" c2s['#'] = "#" c2s['$'] = "$" c2s['%'] = "%" c2s['&'] = "&" c2s['''] = "'" c2s['('] = "(" c2s[')'] = ")" c2s['*'] = "*" c2s['+'] = "+" c2s[','] = "," c2s['-'] = "-" c2s['.'] = "." c2s['/'] = "/" c2s['0'] = "0" c2s['1'] = "1" c2s['2'] = "2" c2s['3'] = "3" c2s['4'] = "4" c2s['5'] = "5" c2s['6'] = "6" c2s['7'] = "7" c2s['8'] = "8" c2s['9'] = "9" c2s[':'] = ":" c2s[';'] = ";" c2s['<'] = "<" c2s['='] = "=" c2s['>'] = ">" c2s['?'] = "?" c2s['@'] = "@" c2s['A'] = "A" c2s['B'] = "B" c2s['C'] = "C" c2s['D'] = "D" c2s['E'] = "E" c2s['F'] = "F" c2s['G'] = "G" c2s['H'] = "H" c2s['I'] = "I" c2s['J'] = "J" c2s['K'] = "K" c2s['L'] = "L" c2s['M'] = "M" c2s['N'] = "N" c2s['O'] = "O" c2s['P'] = "P" c2s['Q'] = "Q" c2s['R'] = "R" c2s['S'] = "S" c2s['T'] = "T" c2s['U'] = "U" c2s['V'] = "V" c2s['W'] = "W" c2s['X'] = "X" c2s['Y'] = "Y" c2s['Z'] = "Z" c2s['['] = "[" c2s['\'] = "\\" c2s[']'] = "]" c2s['^'] = "^" c2s['_'] = "_" c2s['`'] = "`" c2s['a'] = "a" c2s['b'] = "b" c2s['c'] = "c" c2s['d'] = "d" c2s['e'] = "e" c2s['f'] = "f" c2s['g'] = "g" c2s['h'] = "h" c2s['i'] = "i" c2s['j'] = "j" c2s['k'] = "k" c2s['l'] = "l" c2s['m'] = "m" c2s['n'] = "n" c2s['o'] = "o" c2s['p'] = "p" c2s['q'] = "q" c2s['r'] = "r" c2s['s'] = "s" c2s['t'] = "t" c2s['u'] = "u" c2s['v'] = "v" c2s['w'] = "w" c2s['x'] = "x" c2s['y'] = "y" c2s['z'] = "z" c2s['{'] = "{" c2s['|'] = "|" c2s['}'] = "}" c2s['~'] = "~" c2s[127] = ""