Re-enable the walkability checks, allow colours of the form #xxx/xxx, not just #xxxxx...
[SmugglerRL.git] / src / util.d
blobd1b152466f17c0e8cde3bd4b0f28dffd1779d96d
1 public import std.random: uniform;
2 import game;
3 import constants;
4 import std.exception: Exception;
6 public alias rnd = uniform;
8 class DException: Exception {
9 pragma(inline, true) pure this(T...)(T args) {
10 super(format(args));
14 class InternalError: DException {
15 pragma(inline, true) pure this(T...)(T args) {
16 super(args);
20 bool isvalidcolour(string hexcolour) {
21 import std.regex: ctRegex, matchFirst;
22 auto hexcolourmatch = ctRegex!("#?[0-9a-fA-F]{3,6}");
24 if (matchFirst(hexcolour, hexcolourmatch).empty) {
25 return false;
26 } else {
27 return true;
31 struct RGBColour {
32 ubyte r, g, b;
33 pure this(ubyte in_r, ubyte in_g, ubyte in_b) {
34 r = in_r;
35 g = in_g;
36 b = in_b;
39 // Default initializer is 0, so we don't need to change anythign for the default initializer
41 pure this(string hexcolour, bool hasvalidated=false) {
42 import std.conv: to;
44 // strip leading #, if present
45 if ((hexcolour.length == 7) || (hexcolour.length == 4)) {
46 hexcolour = hexcolour[1..$];
49 if (hasvalidated) {
50 if (hexcolour.length == 6) {
51 r = hexcolour[0..2].to!ubyte(16);
52 g = hexcolour[2..4].to!ubyte(16);
53 b = hexcolour[4..6].to!ubyte(16);
54 } else {
55 // The ranges here are to get a string just one character long so to!ubyte works
56 r = cast(ubyte)(hexcolour[0..1].to!ubyte(16)*16);
57 g = cast(ubyte)(hexcolour[1..2].to!ubyte(16)*16);
58 b = cast(ubyte)(hexcolour[2..3].to!ubyte(16)*16);
60 } else {
61 throw new InternalError("RGBColour constructor called but rgbcolour not validated!");
65 this(string hexcolour) {
66 if (!isvalidcolour(hexcolour)) {
67 throw new InternalError("RGBColour constructor called with faulty colour.");
69 this(hexcolour, true);
73 void exit(ubyte code) {
74 import core.runtime: Runtime;
75 static import core.stdc.stdlib;
76 Runtime.terminate();
77 core.stdc.stdlib.exit(code);
80 pure string format(T...)(string s, T args) {
81 import std.array: appender;
82 import std.format: formattedWrite;
83 auto w = appender!string();
84 formattedWrite(w, s, args);
85 return w.data;
88 pure string fillstr(int length, char ch=' ') {
89 string buf;
90 while (length --> 0) {
91 buf ~= ch;
93 return buf;
97 // Taken directly from http://stackoverflow.com/a/41978310
98 /* It's supposed to be incredibly performant...but honestly I used it because
99 * I could copy-paste it easily.
101 pure ubyte get256colour(RGBColour colour) {
102 enum ubyte[6] i2cv = [0, 0x5f, 0x87, 0xaf, 0xd7, 0xff];
103 pragma(inline, true) {
104 pure ubyte function(ubyte) v2ci = cast(ubyte function(ubyte) pure)(ubyte v) => v < 48 ? 0 : v < 115 ? 1 : (v - 35) / 40;
105 auto colour_index = (int r, int g, int b) => 36*r + 6*g + b;
106 auto distance = (int r1, int g1, int b1, int r2, int g2, int b2) => (r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2);
109 ubyte ir = v2ci(colour.r), ig = v2ci(colour.g), ib = v2ci(colour.b);
110 ubyte average = (colour.r + colour.g + colour.b) / 3;
111 ubyte igray = average > 238 ? 23 : (average-3) / 10;
112 ubyte cr = i2cv[ir], cg = i2cv[ig], cb = i2cv[ib];
113 ubyte gv = cast(ubyte)(8 + 10 * igray);
115 int colour_err = distance(cr, cg, cb, colour.r, colour.g, colour.b);
116 int gray_err = distance(gv, gv, gv, colour.r, colour.g, colour.b);
118 return cast(ubyte)(colour_err <= gray_err ? 16 + colour_index(ir, ig, ib) : 232 + igray);
121 // Overloads...
122 pragma(inline, true) ubyte get256colour(ubyte r, ubyte g, ubyte b) { return get256colour(RGBColour(r, g, b)); }
123 pragma(inline, true) ubyte get256colour(string colour) { return get256colour(RGBColour(colour)); }