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