1 #include "AppHdr.h"
2 
3 #include "colour.h"
4 
5 #include <cmath>
6 #include <memory>
7 #include <utility>
8 #include <unordered_map>
9 
10 #include "areas.h"
11 #include "branch.h"
12 #include "cloud.h"
13 #include "dgn-height.h"
14 #include "options.h"
15 #include "stringutil.h"
16 #include "tag-version.h"
17 #include "tiles-build-specific.h"
18 #include "libutil.h" // map_find
19 
20 static FixedVector<unique_ptr<base_colour_calc>, NUM_COLOURS> element_colours;
21 // Values point into element_colours.
22 static unordered_map<string, base_colour_calc*> element_colours_str;
23 
24 typedef vector< pair<int, int> > random_colour_map;
25 typedef int (*randomized_element_colour_calculator)(int, const coord_def&,
26                                                     random_colour_map);
27 
28 struct random_element_colour_calc : public base_colour_calc
29 {
random_element_colour_calcrandom_element_colour_calc30     random_element_colour_calc(element_type _type, string _name,
31                                vector< pair<int, int> > _rand_vals)
32         : base_colour_calc(_type, _name), rand_vals(_rand_vals)
33     {
34         rand_max = 0;
35         for (const auto &pair : rand_vals)
36             rand_max += pair.first;
37     };
38 
39     virtual int get(const coord_def& loc = coord_def(),
40                     bool non_random = false) override;
41 
42 protected:
43     random_colour_map rand_vals;
44 };
45 
rand(bool non_random)46 int base_colour_calc::rand(bool non_random)
47 {
48     return non_random ? 0 : ui_random(rand_max);
49 }
50 
get(const coord_def & loc,bool non_random)51 int element_colour_calc::get(const coord_def& loc, bool non_random)
52 {
53     return (*calc)(rand(non_random), loc);
54 }
55 
get(const coord_def &,bool non_random)56 int random_element_colour_calc::get(const coord_def& /*loc*/, bool non_random)
57 {
58     const auto max_val = rand(non_random);
59     int accum = 0;
60     for (const auto &entry : rand_vals)
61         if ((accum += entry.first) > max_val)
62             return entry.second;
63     return BLACK;
64 }
65 
random_colour(bool ui_rand)66 colour_t random_colour(bool ui_rand)
67 {
68     return 1 + (ui_rand ? ui_random : random2)(15);
69 }
70 
_ui_coinflip()71 static bool _ui_coinflip()
72 {
73     return static_cast<bool>(ui_random(2));
74 }
75 
random_uncommon_colour()76 colour_t random_uncommon_colour()
77 {
78     colour_t result;
79 
80     do
81     {
82         result = random_colour();
83     }
84     while (result == LIGHTCYAN || result == CYAN || result == BROWN);
85 
86     return result;
87 }
88 
is_low_colour(colour_t colour)89 bool is_low_colour(colour_t colour)
90 {
91     return colour <= 7;
92 }
93 
is_high_colour(colour_t colour)94 bool is_high_colour(colour_t colour)
95 {
96     return colour >= 8 && colour <= 15;
97 }
98 
make_low_colour(colour_t colour)99 colour_t make_low_colour(colour_t colour)
100 {
101     if (is_high_colour(colour))
102         return colour - 8;
103 
104     return colour;
105 }
106 
make_high_colour(colour_t colour)107 colour_t make_high_colour(colour_t colour)
108 {
109     if (is_low_colour(colour))
110         return colour + 8;
111 
112     return colour;
113 }
114 
115 // returns if a colour is one of the special element colours (ie not regular)
_is_element_colour(int col)116 static bool _is_element_colour(int col)
117 {
118     // stripping any COLFLAGS (just in case)
119     col = col & 0x007f;
120     ASSERT(col < NUM_COLOURS);
121     return col >= ETC_FIRE;
122 }
123 
_etc_floor(int,const coord_def & loc)124 static int _etc_floor(int, const coord_def& loc)
125 {
126     return element_colour(env.floor_colour, false, loc);
127 }
128 
_etc_rock(int,const coord_def & loc)129 static int _etc_rock(int, const coord_def& loc)
130 {
131     return element_colour(env.rock_colour, false, loc);
132 }
133 
_etc_elven_brick(int,const coord_def & loc)134 static int _etc_elven_brick(int, const coord_def& loc)
135 {
136     if ((loc.x + loc.y) % 2)
137         return WHITE;
138     else
139     {
140         if ((loc.x / 2 + loc.y / 2) % 2)
141             return LIGHTGREEN;
142         else
143             return LIGHTBLUE;
144     }
145 }
146 
_etc_waves(int,const coord_def & loc)147 static int _etc_waves(int, const coord_def& loc)
148 {
149     // Shouldn't have this outside of Shoals, but it can happen.
150     // See !lg lakren crash 8 .
151     if (!env.heightmap)
152         return CYAN;
153     short height = dgn_height_at(loc);
154     int cycle_point = you.num_turns % 20;
155     int min_height = -90 + 5 * cycle_point,
156         max_height = -80 + 5 * cycle_point;
157     if (height > min_height && height < max_height)
158         return LIGHTCYAN;
159     else
160         return CYAN;
161 }
162 
_etc_elemental(int,const coord_def & loc)163 static int _etc_elemental(int, const coord_def& loc)
164 {
165     int cycle = (you.elapsed_time / 200) % 4;
166     switch (cycle)
167     {
168         default:
169         case 0:
170             return element_colour(ETC_EARTH, false, loc);
171         case 1:
172             return element_colour(_ui_coinflip() ? ETC_AIR : ETC_ELECTRICITY,
173                                   false, loc);
174         case 2:
175             // Not ETC_FIRE, which is Makhleb; instead do magma-y colours.
176             if (_ui_coinflip())
177                 return RED;
178             return _ui_coinflip() ? BROWN : LIGHTRED;
179         case 3:
180             return element_colour(ETC_ICE, false, loc);
181     }
182 }
183 
get_disjunct_phase(const coord_def & loc)184 int get_disjunct_phase(const coord_def& loc)
185 {
186     static int turns = you.num_turns;
187     static coord_def centre = find_centre_for(loc,
188                                               area_centre_type::disjunction);
189 
190     if (turns != you.num_turns || (centre-loc).abs() > 15)
191     {
192         centre = find_centre_for(loc, area_centre_type::disjunction);
193         turns = you.num_turns;
194     }
195 
196     if (centre.origin())
197         return 2;
198 
199     int x = loc.x - centre.x;
200     int y = loc.y - centre.y;
201     double dist = sqrt(x*x + y*y);
202     int parity = ((int) (dist / PI) + you.frame_no / 11) % 2 ? 1 : -1;
203     double dir = sin(atan2(x, y)*PI + parity * you.frame_no / 3) + 1;
204     return 1 + (int) floor(dir * 2);
205 }
206 
_etc_disjunction(int,const coord_def & loc)207 static int _etc_disjunction(int, const coord_def& loc)
208 {
209     switch (get_disjunct_phase(loc))
210     {
211     case 1:
212         return LIGHTBLUE;
213     case 2:
214         return BLUE;
215     case 3:
216         return MAGENTA;
217     default:
218         return LIGHTMAGENTA;
219     }
220 }
221 
_etc_liquefied(int,const coord_def & loc)222 static int _etc_liquefied(int, const coord_def& loc)
223 {
224     static int turns = you.num_turns;
225     static coord_def centre = find_centre_for(loc, area_centre_type::liquid);
226 
227     if (turns != you.num_turns || (centre-loc).abs() > 15)
228     {
229         centre = find_centre_for(loc, area_centre_type::liquid);
230         turns = you.num_turns;
231     }
232 
233     if (centre.origin())
234         return BROWN;
235 
236     int x = loc.x - centre.x;
237     int y = loc.y - centre.y;
238     double dir = atan2(x, y)/PI;
239     double dist = sqrt(x*x + y*y);
240     bool phase = ((int)floor(dir*0.3 + dist*0.5 + (you.frame_no % 54)/2.7))&1;
241 
242     if (branches[you.where_are_you].floor_colour == BROWN)
243         return phase ? LIGHTRED : RED;
244     else
245         return phase ? YELLOW : BROWN;
246 }
247 
_etc_tree(int,const coord_def & loc)248 static int _etc_tree(int, const coord_def& loc)
249 {
250     uint32_t h = loc.x;
251     h+=h<<10; h^=h>>6;
252     h += loc.y;
253     h+=h<<10; h^=h>>6;
254     h+=h<<3; h^=h>>11; h+=h<<15;
255     return (h>>30) ? GREEN : LIGHTGREEN;
256 }
257 
_etc_mangrove(int,const coord_def & loc)258 static int _etc_mangrove(int, const coord_def& loc)
259 {
260     static int col = _etc_tree(0, loc);
261     return col == LIGHTGREEN ? BROWN : col;
262 }
263 
get_vortex_phase(const coord_def & loc)264 bool get_vortex_phase(const coord_def& loc)
265 {
266     coord_def center = get_cloud_originator(loc);
267     if (center.origin())
268         return _ui_coinflip(); // source died/went away
269     else
270     {
271         int x = loc.x - center.x;
272         int y = loc.y - center.y;
273         double dir = atan2(x, y)/PI;
274         double dist = sqrt(x*x + y*y);
275         return ((int)floor(dir*2 + dist*0.33 - (you.frame_no % 54)/2.7))&1;
276     }
277 }
278 
_etc_vortex(int,const coord_def & loc)279 static int _etc_vortex(int, const coord_def& loc)
280 {
281     const bool phase = get_vortex_phase(loc);
282     switch (env.grid(loc))
283     {
284     case DNGN_LAVA:
285         return phase ? LIGHTRED : one_chance_in(3) ? MAGENTA : RED;
286     case DNGN_SHALLOW_WATER: // XX color overlap between this and land, how annoying is it?
287         return phase ? LIGHTCYAN : CYAN;
288     case DNGN_DEEP_WATER:
289         return phase ? BLUE : coinflip() ? LIGHTBLUE : DARKGREY;
290     default:
291         return phase ? WHITE : one_chance_in(3) ? LIGHTCYAN : LIGHTGREY;
292     }
293 }
294 
get_orb_phase(const coord_def & loc)295 bool get_orb_phase(const coord_def& loc)
296 {
297     int dist = (loc - env.orb_pos).abs();
298     return (you.frame_no - dist*2/3)&4;
299 }
300 
_etc_orb_glow(int,const coord_def & loc)301 static int _etc_orb_glow(int, const coord_def& loc)
302 {
303     return get_orb_phase(loc) ? LIGHTMAGENTA : MAGENTA;
304 }
305 
dam_colour(const monster_info & mi)306 int dam_colour(const monster_info& mi)
307 {
308     switch (mi.dam)
309     {
310         case MDAM_OKAY:                 return Options.enemy_hp_colour[0];
311         case MDAM_LIGHTLY_DAMAGED:      return Options.enemy_hp_colour[1];
312         case MDAM_MODERATELY_DAMAGED:   return Options.enemy_hp_colour[2];
313         case MDAM_HEAVILY_DAMAGED:      return Options.enemy_hp_colour[3];
314         case MDAM_SEVERELY_DAMAGED:     return Options.enemy_hp_colour[4];
315         case MDAM_ALMOST_DEAD:          return Options.enemy_hp_colour[5];
316         case MDAM_DEAD:                 return BLACK; // this should never happen
317         default:                        return CYAN; // this should really never happen
318     }
319 }
320 
rune_colour(int type)321 colour_t rune_colour(int type)
322 {
323     switch (type)
324     {
325         case RUNE_SWAMP: return GREEN;
326         case RUNE_SNAKE: return GREEN;
327         case RUNE_SHOALS: return LIGHTBLUE;
328         case RUNE_SLIME: return LIGHTGREEN;
329         case RUNE_VAULTS: return WHITE;
330         case RUNE_TOMB: return YELLOW;
331         case RUNE_DIS: return CYAN;
332         case RUNE_GEHENNA: return RED;
333         case RUNE_COCYTUS: return LIGHTCYAN;
334         case RUNE_TARTARUS: return LIGHTMAGENTA;
335         case RUNE_ABYSSAL: return MAGENTA;
336         case RUNE_DEMONIC: return MAGENTA;
337         case RUNE_MNOLEG: return LIGHTGREEN;
338         case RUNE_LOM_LOBON: return BLUE;
339         case RUNE_CEREBOV: return RED;
340         case RUNE_GLOORX_VLOQ: return DARKGRAY;
341         case RUNE_SPIDER: return BROWN;
342         default: return GREEN;
343     }
344 }
345 
_etc_random(int,const coord_def &)346 static int _etc_random(int, const coord_def&)
347 {
348     return random_colour(true);
349 }
350 
add_element_colour(base_colour_calc * colour)351 void add_element_colour(base_colour_calc *colour)
352 {
353     // or else lookups won't work: we strip high bits (because of colflags)
354     ASSERT(colour->type < 128);
355     COMPILE_CHECK(NUM_COLOURS <= 128);
356     if (colour->type >= ETC_FIRST_LUA)
357     {
358         ASSERT(element_colours[colour->type].get()
359                == element_colours_str[colour->name]);
360     }
361     else
362     {
363         ASSERT(!element_colours[colour->type]);
364         ASSERT(!element_colours_str.count(colour->name));
365     }
366     element_colours[colour->type].reset(colour);
367     element_colours_str[colour->name] = colour;
368 }
369 
init_element_colours()370 void init_element_colours()
371 {
372     add_element_colour(new random_element_colour_calc(
373                             ETC_FIRE, "fire",
374                             { {40,  RED},
375                               {40,  YELLOW},
376                               {40,  LIGHTRED},
377                             }));
378     add_element_colour(new random_element_colour_calc(
379                             ETC_ICE, "ice",
380                             { {40,  LIGHTBLUE},
381                               {40,  BLUE},
382                               {40,  WHITE},
383                             }));
384     add_element_colour(new random_element_colour_calc(
385                             ETC_EARTH, "earth",
386                             { {70,  BROWN},
387                               {50,  GREEN},
388                             }));
389     add_element_colour(new random_element_colour_calc(
390                             ETC_ELECTRICITY, "electricity",
391                             { {40,  LIGHTCYAN},
392                               {40,  LIGHTBLUE},
393                               {40,  CYAN},
394                             }));
395     add_element_colour(new random_element_colour_calc(
396                             ETC_AIR, "air",
397                             { {60,  LIGHTGREY},
398                               {60,  WHITE},
399                             }));
400     add_element_colour(new random_element_colour_calc(
401                             ETC_POISON, "poison",
402                             { {60,  LIGHTGREEN},
403                               {60,  GREEN},
404                             }));
405     add_element_colour(new random_element_colour_calc(
406                             ETC_WATER, "water",
407                             { {60,  BLUE},
408                               {60,  CYAN},
409                             }));
410     add_element_colour(new random_element_colour_calc(
411                             ETC_MAGIC, "magic",
412                             { {30,  LIGHTMAGENTA},
413                               {30,  LIGHTBLUE},
414                               {30,  MAGENTA},
415                               {30,  BLUE},
416                             }));
417     add_element_colour(new random_element_colour_calc(
418                             ETC_MUTAGENIC, "mutagenic",
419                             { {60,  LIGHTMAGENTA},
420                               {60,  MAGENTA},
421                             }));
422     add_element_colour(new random_element_colour_calc(
423                             ETC_WARP, "warp",
424                             { {60,  LIGHTMAGENTA},
425                               {60,  MAGENTA},
426                             }));
427     add_element_colour(new random_element_colour_calc(
428                             ETC_ENCHANT, "enchant",
429                             { {60,  LIGHTBLUE},
430                               {60,  BLUE},
431                             }));
432     add_element_colour(new random_element_colour_calc(
433                             ETC_HEAL, "heal",
434                             { {60,  LIGHTBLUE},
435                               {60,  YELLOW},
436                             }));
437     add_element_colour(new random_element_colour_calc(
438                             ETC_HOLY, "holy",
439                             { {60,  YELLOW},
440                               {60,  WHITE},
441                             }));
442     add_element_colour(new random_element_colour_calc(
443                             ETC_DARK, "dark",
444                             { {80,  DARKGREY},
445                               {40,  LIGHTGREY},
446                             }));
447     // assassin, necromancer
448     add_element_colour(new random_element_colour_calc(
449                             ETC_DEATH, "death",
450                             { {80,  DARKGREY},
451                               {40,  MAGENTA},
452                             }));
453     // ie demonology
454     add_element_colour(new random_element_colour_calc(
455                             ETC_UNHOLY, "unholy",
456                             { {80,  DARKGREY},
457                               {40,  RED},
458                             }));
459     add_element_colour(new random_element_colour_calc(
460                             ETC_VEHUMET, "vehumet",
461                             { {40,  LIGHTRED},
462                               {40,  LIGHTMAGENTA},
463                               {40,  LIGHTBLUE},
464                             }));
465     add_element_colour(new random_element_colour_calc(
466                             ETC_BEOGH, "beogh",
467                             { {60,  LIGHTRED}, // plain Orc colour
468                               {60,  BROWN},    // Orcish mines wall/idol colour
469                             }));
470     add_element_colour(new random_element_colour_calc(
471                             ETC_CRYSTAL, "crystal",
472                             { {40,  LIGHTGREY},
473                               {40,  GREEN},
474                               {40,  LIGHTRED},
475                             }));
476     add_element_colour(new random_element_colour_calc(
477                             ETC_BLOOD, "blood",
478                             { {60,  RED},
479                               {60,  DARKGREY},
480                             }));
481     add_element_colour(new random_element_colour_calc(
482                             ETC_SMOKE, "smoke",
483                             { {30,  LIGHTGREY},
484                               {30,  DARKGREY},
485                               {30,  LIGHTBLUE},
486                               {30,  MAGENTA},
487                             }));
488     add_element_colour(new random_element_colour_calc(
489                             ETC_SLIME, "slime",
490                             { {40,  GREEN},
491                               {40,  BROWN},
492                               {40,  LIGHTGREEN},
493                             }));
494     add_element_colour(new random_element_colour_calc(
495                             ETC_JEWEL, "jewel",
496                             { {12,  WHITE},
497                               {12,  YELLOW},
498                               {12,  LIGHTMAGENTA},
499                               {12,  LIGHTRED},
500                               {12,  LIGHTGREEN},
501                               {12,  LIGHTBLUE},
502                               {12,  MAGENTA},
503                               {12,  RED},
504                               {12,  GREEN},
505                               {12,  BLUE},
506                             }));
507     add_element_colour(new random_element_colour_calc(
508                             ETC_ELVEN, "elven",
509                             { {40,  LIGHTGREEN},
510                               {40,  GREEN},
511                               {20,  LIGHTBLUE},
512                               {20,  BLUE},
513                             }));
514     add_element_colour(new random_element_colour_calc(
515                             ETC_DWARVEN, "dwarven",
516                             { {40,  BROWN},
517                               {40,  LIGHTRED},
518                               {20,  LIGHTGREY},
519                               {20,  CYAN},
520                             }));
521     add_element_colour(new random_element_colour_calc(
522                             ETC_ORCISH, "orcish",
523                             { {40,  DARKGREY},
524                               {40,  RED},
525                               {20,  BROWN},
526                               {20,  MAGENTA},
527                             }));
528     add_element_colour(new random_element_colour_calc(
529                             ETC_FLASH, "flash",
530                             { {30,  LIGHTMAGENTA},
531                               {30,  MAGENTA},
532                               {30,  YELLOW},
533                               {15,  LIGHTRED},
534                               {15,  RED},
535                             }));
536     add_element_colour(new element_colour_calc(
537                             ETC_FLOOR, "floor", _etc_floor
538                        ));
539     add_element_colour(new element_colour_calc(
540                             ETC_ROCK, "rock", _etc_rock
541                        ));
542     add_element_colour(new random_element_colour_calc(
543                             ETC_MIST, "mist",
544                             { {100, CYAN},
545                               {20,  BLUE},
546                             }));
547     add_element_colour(new random_element_colour_calc(
548                             ETC_SHIMMER_BLUE, "shimmer_blue",
549                             { {90,  BLUE},
550                               {20,  LIGHTBLUE},
551                               {10,  CYAN},
552                             }));
553     add_element_colour(new random_element_colour_calc(
554                             ETC_DECAY, "decay",
555                             { {60,  BROWN},
556                               {60,  GREEN},
557                             }));
558     add_element_colour(new random_element_colour_calc(
559                             ETC_SILVER, "silver",
560                             { {90,  LIGHTGREY},
561                               {30,  WHITE},
562                             }));
563     add_element_colour(new random_element_colour_calc(
564                             ETC_GOLD, "gold",
565                             { {60,  YELLOW},
566                               {60,  BROWN},
567                             }));
568     add_element_colour(new random_element_colour_calc(
569                             ETC_IRON, "iron",
570                             { {40,  CYAN},
571                               {40,  LIGHTGREY},
572                               {40,  DARKGREY},
573                             }));
574     add_element_colour(new random_element_colour_calc(
575                             ETC_BONE, "bone",
576                             { {90,  WHITE},
577                               {30,  LIGHTGREY},
578                             }));
579     add_element_colour(new element_colour_calc(
580                             ETC_ELVEN_BRICK, "elven_brick", _etc_elven_brick
581                        ));
582     add_element_colour(new element_colour_calc(
583                             ETC_WAVES, "waves", _etc_waves
584                        ));
585     add_element_colour(new element_colour_calc(
586                             ETC_TREE, "tree", _etc_tree
587                        ));
588     add_element_colour(new element_colour_calc(
589                             ETC_MANGROVE, "mangrove", _etc_mangrove
590                        ));
591     add_element_colour(new element_colour_calc(
592                             ETC_VORTEX, "vortex", _etc_vortex
593                        ));
594     add_element_colour(new element_colour_calc(
595                             ETC_LIQUEFIED, "liquefied", _etc_liquefied
596                        ));
597     add_element_colour(new element_colour_calc(
598                             ETC_ORB_GLOW, "orb_glow", _etc_orb_glow
599                        ));
600     add_element_colour(new element_colour_calc(
601                             ETC_DISJUNCTION, "disjunction", _etc_disjunction
602                        ));
603     add_element_colour(new element_colour_calc(
604                             ETC_RANDOM, "random", _etc_random
605                        ));
606     add_element_colour(new random_element_colour_calc(
607                             ETC_DITHMENOS, "dithmenos",
608                             { {40,  DARKGREY},
609                               {40,  MAGENTA},
610                               {40,  BLUE},
611                             }));
612     add_element_colour(new element_colour_calc(
613                             ETC_ELEMENTAL, "elemental", _etc_elemental
614                        ));
615     add_element_colour(new random_element_colour_calc(
616                             ETC_INCARNADINE, "incarnadine",
617                             { {60,  MAGENTA},
618                               {60,  RED},
619                             }));
620 #if TAG_MAJOR_VERSION == 34
621     add_element_colour(new random_element_colour_calc(
622                             ETC_PAKELLAS, "pakellas",
623                             { {40,  LIGHTGREEN},
624                               {40,  LIGHTMAGENTA},
625                               {40,  LIGHTCYAN},
626                             }));
627 #endif
628     add_element_colour(new random_element_colour_calc(
629                             ETC_AWOKEN_FOREST, "awoken_forest",
630                             { {40, RED},
631                               {20, LIGHTRED},
632                             }));
633     add_element_colour(new random_element_colour_calc(
634                             ETC_WU_JIAN, "wu_jian",
635                             { {40, LIGHTRED},
636                               {40, YELLOW},
637                               {10, WHITE},
638                             }));
639     // redefined by Lua later
640     add_element_colour(new element_colour_calc(
641                             ETC_DISCO, "disco", _etc_random
642                        ));
643 }
644 
element_colour(int element,bool no_random,const coord_def & loc)645 int element_colour(int element, bool no_random, const coord_def& loc)
646 {
647     // pass regular colours through for safety.
648     if (!_is_element_colour(element))
649         return element;
650 
651     // Strip COLFLAGs just in case.
652     element &= 0x007f;
653 
654     ASSERT(element_colours[element]);
655     int ret = element_colours[element]->get(loc, no_random);
656 
657     ASSERT(!_is_element_colour(ret));
658 
659     return (ret == BLACK) ? GREEN : ret;
660 }
661 
662 #ifdef USE_TILE
_hex(char c)663 static int _hex(char c)
664 {
665     if (c >= '0' && c <= '9')
666         return c - '0';
667     if (c >= 'a' && c <= 'f')
668         return 10 + c - 'a';
669     if (c >= 'A' && c <= 'F')
670         return 10 + c - 'A';
671     return 0;
672 }
673 
str_to_tile_colour(string colour)674 VColour str_to_tile_colour(string colour)
675 {
676     if (colour.empty())
677         return VColour(0, 0, 0);
678 
679     if (colour[0] == '#' && colour.length() == 7)
680     {
681         return VColour((_hex(colour[1]) << 4) + _hex(colour[2]),
682                 (_hex(colour[3]) << 4) + _hex(colour[4]),
683                 (_hex(colour[5]) << 4) + _hex(colour[6]));
684     }
685     else
686     {
687         lowercase(colour);
688 
689         if (colour == "darkgray")
690             colour = "darkgrey";
691         else if (colour == "gray")
692             colour = "grey";
693         else if (colour == "lightgray")
694             colour = "lightgrey";
695 
696         if (colour == "black")             return VColour(  0,   0,   0);
697         else if (colour == "darkgrey")     return VColour(128, 128, 128);
698         else if (colour == "grey")         return VColour(160, 160, 160);
699         else if (colour == "lightgrey")    return VColour(192, 192, 192);
700         else if (colour == "white")        return VColour(255, 255, 255);
701         else if (colour == "blue")         return VColour(  0,  64, 255);
702         else if (colour == "lightblue")    return VColour(128, 128, 255);
703         else if (colour == "darkblue")     return VColour(  0,  32, 128);
704         else if (colour == "green")        return VColour(  0, 255,   0);
705         else if (colour == "lightgreen")   return VColour(128, 255, 128);
706         else if (colour == "darkgreen")    return VColour(  0, 128,   0);
707         else if (colour == "cyan")         return VColour(  0, 255, 255);
708         else if (colour == "lightcyan")    return VColour( 64, 255, 255);
709         else if (colour == "darkcyan")     return VColour(  0, 128, 128);
710         else if (colour == "red")          return VColour(255,   0,   0);
711         else if (colour == "lightred")     return VColour(255, 128, 128);
712         else if (colour == "darkred")      return VColour(128,   0,   0);
713         else if (colour == "magenta")      return VColour(192,   0, 255);
714         else if (colour == "lightmagenta") return VColour(255, 128, 255);
715         else if (colour == "darkmagenta")  return VColour( 96,   0, 128);
716         else if (colour == "yellow")       return VColour(255, 255,   0);
717         else if (colour == "lightyellow")  return VColour(255, 255,  64);
718         else if (colour == "darkyellow")   return VColour(128, 128,   0);
719         else if (colour == "brown")        return VColour(165,  91,   0);
720         else return VColour(0, 0, 0);
721     }
722 }
723 #endif
724 
725 static const char* const cols[16] =
726 {
727     "black", "blue", "green", "cyan", "red", "magenta", "brown",
728     "lightgrey", "darkgrey", "lightblue", "lightgreen", "lightcyan",
729     "lightred", "lightmagenta", "yellow", "white"
730 };
731 COMPILE_CHECK(ARRAYSZ(cols) == NUM_TERM_COLOURS);
732 
colour_to_str(colour_t colour)733 const string colour_to_str(colour_t colour)
734 {
735     if (colour >= NUM_TERM_COLOURS)
736         return "lightgrey";
737     else
738         return cols[colour];
739 }
740 
741 // Returns default_colour (default -1) if unmatched else returns 0-15.
str_to_colour(const string & str,int default_colour,bool accept_number,bool accept_elemental)742 int str_to_colour(const string &str, int default_colour, bool accept_number,
743                   bool accept_elemental)
744 {
745     int ret;
746 
747     for (ret = 0; ret < NUM_TERM_COLOURS; ++ret)
748     {
749         if (str == cols[ret])
750             break;
751     }
752 
753     // Check for alternate spellings.
754     if (ret == NUM_TERM_COLOURS)
755     {
756         if (str == "lightgray")
757             ret = 7;
758         else if (str == "darkgray")
759             ret = 8;
760     }
761 
762     if (ret == NUM_TERM_COLOURS && accept_elemental)
763     {
764         // Maybe we have an element colour attribute.
765         if (base_colour_calc **calc = map_find(element_colours_str, str))
766         {
767             ASSERT(*calc);
768             ret = (*calc)->type;
769         }
770     }
771 
772     if (ret == NUM_TERM_COLOURS && accept_number)
773     {
774         // Check if we have a direct colour index.
775         const char *s = str.c_str();
776         char *es = nullptr;
777         const int ci = static_cast<int>(strtol(s, &es, 10));
778         if (s != es && es && ci >= 0 && ci < NUM_TERM_COLOURS)
779             ret = ci;
780     }
781 
782     return (ret == NUM_TERM_COLOURS) ? default_colour : ret;
783 }
784 
real_colour(unsigned raw_colour,const coord_def & loc)785 unsigned real_colour(unsigned raw_colour, const coord_def& loc)
786 {
787     // This order is important - is_element_colour() doesn't want to see the
788     // munged colours returned by dos_brand, so it should always be done
789     // before applying DOS brands.
790     const int colflags = raw_colour & 0xFF00;
791 
792     // Evaluate any elemental colours to guarantee vanilla colour is returned
793     if (_is_element_colour(raw_colour))
794         raw_colour = colflags | element_colour(raw_colour, false, loc);
795 
796     return raw_colour;
797 }
798