package Colors import NoWurst import Table import String import Integer import Wurstunit import Playercolor import Annotations import Maths import Real import Player /** Hexadecimal numbers */ public constant hexs = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"] constant decs = new Table() public constant COLOR_WHITE = colorA(255,255,255,255) public constant COLOR_BLACK = colorA(0,0,0,0) public constant COLOR_GOLD = colorA(255, 204, 0, 255) public constant COLOR_WHITE_STR = COLOR_WHITE.toColorString() public constant COLOR_BLACK_STR = COLOR_BLACK.toColorString() public constant COLOR_GOLD_STR = COLOR_GOLD.toColorString() public constant DEFAULT_COLOR_NAME = "black" public constant MAX_PLAYER_COLORS = 23 /** Player color array. Access through playercolor.toColor() */ public constant PLAYER_COLORS = [ color(255,2,2), color(0,65,255), color(27,229,184), color(83,0,128), color(255,252,0), color(254,137,13), color(31,191,0), color(228,90,175), color(148,149,150), color(125,190,241), color(15,97,69), color(77,41,3), color(155,0,0), color(0, 0, 195), color(0, 234, 255), color(190, 0, 254), color(235, 205, 135), color(248, 164, 139), color(191, 255, 128), color(220, 185, 235), color(40, 40, 40), color(235, 240, 255), color(0, 120, 30), color(164, 111, 51) ] /** Player color names array. Access through playercolor.getName() */ public constant PLAYER_COLOR_NAMES = [ "red", "blue", "teal", "purple", "yellow", "orange", "green", "pink", "gray", "light blue", "dark green", "brown", "maroon", "navy", "turquoise", "violet", "wheat", "peach", "mint", "lavender", "coal", "snow", "emerald", "peanut" ] public function player.getNameColored(boolean removeHash) returns string return this.getColor().toColor().toColorString() + this.getName(removeHash) + "|r" public function player.getNameColored() returns string return this.getNameColored(false) /** Returns the name of the player color */ public function playercolor.getName() returns string return this.toInt() <= MAX_PLAYER_COLORS ? PLAYER_COLOR_NAMES[this.toInt()] : DEFAULT_COLOR_NAME /** Returns the color associated with the playercolor */ public function playercolor.toColor() returns color return this.toInt() <= MAX_PLAYER_COLORS ? PLAYER_COLORS[this.toInt()] : COLOR_BLACK.withoutAlpha() /** Tuple for your RGB color needs. 0 = black, 255 = full color */ public tuple color(int red, int green, int blue) /** Tuple for your RGBA color needs. 0 = black/transparent, 255 = full color/opaque */ public tuple colorA(int red, int green, int blue, int alpha) /** Tuple for your HSV(Hue Saturation Value) color needs. All values 0-1 */ public tuple colorHSV(real h, real s, real v) /** Add an alpha value to a simple color tuple */ public function color.withAlpha(int a) returns colorA return colorA(this.red, this.green, this.blue, a) public function colorA.withoutAlpha() returns color return color(this.red, this.green, this.blue) /** Returns the HSV equivalent */ public function color.toHSV() returns colorHSV real s = 0 real h = 0 let r = this.red / 255.0 let g = this.green / 255.0 let b = this.blue / 255.0 let max = max(r, g, b) let min = min(r, g, b) let delta = max - min if max != 0 and delta != 0 s = delta / max if r == max if g < b h = 1 + (g - b) / delta / 6 else h = (g - b) / delta / 6 else if g == max h = 1.0 / 3 + (b - r) / delta / 6 else h = 2.0 / 3 + (r - g) / delta / 6 return colorHSV(h, s, max) /** Returns the RGB equivalent */ public function colorHSV.toRGB() returns color real r real g real b let diff = this.s * this.v let max = this.v * 255 let mix = diff * 6 * 255 let min = (this.v - diff) * 255 if this.h < 1.0 / 6 r = max g = this.h * mix + min b = min else if this.h < 2.0 / 6 r = (2.0 / 6 - this.h) * mix + min g = max b = min else if this.h < 3.0 / 6 r = min g = max b = (this.h - 2.0 / 6) * mix + min else if this.h < 4.0 / 6 r = min g = (4.0 / 6 - this.h) * mix + min b = max else if this.h < 5.0 / 6 r = (this.h - 4.0 / 6) * mix + min g = min b = max else r = max g = min b = (1 - this.h) * mix + min return color(r.toInt(), g.toInt(), b.toInt()) /** Get a colorA tuple from a hexstring */ public function fromHexString(string number) returns colorA let alpha = number.substring(0,2) let red = number.substring(2,4) let green = number.substring(4,6) let blue = number.substring(6,8) return colorA(toDec(red), toDec(green), toDec(blue), toDec(alpha)) public function color.normalize() returns color return color(this.red.abs(), this.green.abs(), this.blue.abs()) public function color.lerp(color target, real smoothness) returns color return color(this.red.lerp(target.red, smoothness),this.green.lerp(target.green, smoothness),this.blue.lerp(target.blue, smoothness)) public function makeColor(int colo) returns colorA int a int r int g int b int col = colo if col < 0 col = -(-col + 0x80000000) a = 0x80 + col div 0x1000000 col = col - (a - 0x80) * 0x1000000 else a = col div 0x1000000 col = col - a * 0x1000000 r = col div 0x10000 col = col-r * 0x10000 g = col div 0x100 b = col-g * 0x100 return colorA(r,g,b,a) /** * Mixes two colors, s would be a number 0<=s<=1 that determines * the weight given to color c2. * * c1.mix(c2,0) = c1 * c1.mix(c2,1) = c2 * c1.mix(c2,0.5) = Mixing the colors c1 and c2 in equal proportions. */ public function colorA.mix(colorA c2, real s) returns colorA return colorA(R2I(c2.red * s + this.red * (1 - s) + 0.5), R2I(c2.green * s + this.green * (1 - s) + 0.5), R2I(c2.blue * s + this.blue * (1 - s) + 0.5), R2I(c2.alpha * s + this.alpha * (1 - s) + 0.5)) /** Set a units color to the tuplevalues with alpha */ public function unit.setVertexColor(colorA col) SetUnitVertexColor(this, col.red, col.green, col.blue, col.alpha) /** Set a units color to the tuplevalues without alpha */ public function unit.setVertexColor(color col) SetUnitVertexColor(this, col.red, col.green, col.blue, 255) /** Returns a string that is in the wc3 hexcolor format (|caarrggbb) */ public function colorA.toColorString() returns string return "|c" + toHex(this.alpha) + toHex(this.red) + toHex(this.green) + toHex(this.blue) /** Returns a string that is in the wc3 hexcolor format (|crrggbb) */ public function color.toColorString() returns string return "|cff" + toHex(this.red) + toHex(this.green) + toHex(this.blue) /** Returns the tuple in string format color(r,g,b) */ public function color.toString() returns string return "color(" + (this.red).toString() + ", " + (this.green).toString() + ", " + (this.blue).toString() + ")" /** Returns the tuple in string format colorA(r,g,b,a) */ public function colorA.toString() returns string return "colorA(" + (this.red).toString() + ", " + (this.green).toString() + ", " + (this.blue).toString() + ", " + (this.alpha).toString() + ")" /** Returns the tuple in string format colorHSV(h,s,v) */ public function colorHSV.toString() returns string return "colorHSV(" + (this.h).toString() + ", " + (this.s).toString() + ", " + (this.v).toString() + ")" /** Converts and int to a hexnumber */ public function toHex(int number) returns string let firstpart = number div 16 let secondpart = number - firstpart * 16 return hexs[firstpart] + hexs[secondpart] /** Converts a twochar string to an int */ public function toDec(string twochar) returns int if twochar.length() > 2 return -1 let first = twochar.substring(0,1).toUpperCase() let second = twochar.substring(1,2).toUpperCase() return decs.loadInt(StringHash(first)) * 16 + decs.loadInt(StringHash(second)) /** Gets the name of the color. Only works on player colors. See PLAYER_COLORS. */ public function color.getName() returns string for i = 0 to MAX_PLAYER_COLORS if (this == PLAYER_COLORS[i]) return PLAYER_COLOR_NAMES[i] return "Unknown Color" /** Returns the player that corresponds to described color. Returns null if a bad string is provided. See PLAYER_COLOR_NAMES for options. Returns players based on starting color, not current color (does not respect SetPlayerColor)*/ public function toPlayerFromColorName(string colorName) returns player let pc = colorName.toPlayerColor() return pc != null ? pc.getPlayer() : null /** Returns the color that the string describes. Only works on player colors. */ public function string.toColor() returns color var col = color(0,0,0) for i = 0 to MAX_PLAYER_COLORS if (this.toLowerCase() == PLAYER_COLOR_NAMES[i]) col = PLAYER_COLORS[i] break return col /** Returns the player color that the string describes. Only works on player colors. */ public function string.toPlayerColor() returns playercolor playercolor pc = null for i = 0 to MAX_PLAYER_COLORS if (this.toLowerCase() == PLAYER_COLOR_NAMES[i]) pc = i.toPlayerColor() break return pc function colorHSV.assert() let delta = 0.01 let translated = this.toRGB().toHSV() let compare = colorHSV((translated.h - this.h).abs(), (translated.s - this.s).abs(), (translated.v - this.v).abs()) if compare.h > delta or compare.s > delta or compare.v > delta testFail("Actual {0}, Expected {1}".format(translated.toString(), this.toString())) public function string.color(string which) returns string return which + this + "|r" public function string.color(color which) returns string return which.toColorString() + this + "|r" public function string.color(colorA which) returns string return which.toColorString() + this + "|r" @compiletime function initializeTable() for i = 0 to 15 decs.saveInt(hexs[i].getHash(), i) init initializeTable() @Test public function testColors() hexs[10].assertEquals("A") decs.loadInt(hexs[10].getHash()).assertEquals(10) let mixed = colorA(0,0,0,0).mix(colorA(255,255,255,255), 0.5) assertTrue(mixed == colorA(128,128,128,128)) assertTrue(fromHexString("33ccff44") == colorA(204, 255, 68, 51)) assertTrue(PLAYER_COLOR_RED != null) @Test public function testHSV() colorHSV(0, 0, 1).assert() colorHSV(0, 0, 0.5).assert() colorHSV(0, 0, 0).assert() for h = 0 to 11 for s = 2 downto 1 for v = 2 downto 1 colorHSV(h / 12.0, s / 2.0, v / 2.0).assert() @Test public function testColorNames() color(255, 2, 2).getName().assertEquals("red") color(164, 111, 51).getName().assertEquals("peanut") assertTrue("red".toColor() == color(255, 2, 2)) assertTrue("peanut".toColor() == color(164, 111, 51)) assertTrue("red".toPlayerColor() == PLAYER_COLOR_RED) assertTrue("peanut".toPlayerColor() == PLAYER_COLOR_PEANUT) @Test public function testPlayerColorConversion() assertTrue(PLAYER_COLOR_BLUE.toColor() == color(0,65,255)) assertTrue(PLAYER_COLOR_RED.toColor() == color(255, 2, 2)) assertTrue(PLAYER_COLOR_PEANUT.toColor() == color(164, 111, 51)) PLAYER_COLOR_RED.getName().assertEquals("red") PLAYER_COLOR_COAL.getName().assertEquals("coal") @Test public function testPlayerFromColorName() assertTrue(toPlayerFromColorName("red") == Player(0)) assertTrue(toPlayerFromColorName("PEANUT") == Player(23)) assertTrue(toPlayerFromColorName("wurstlang") == null)