#include "AppHdr.h"
#include "colour.h"
#include "env.h"
#include "options.h"
#include "player.h"
#include "random.h"
unsigned char random_colour(void)
{
return (1 + random2(15));
}
unsigned char random_uncommon_colour()
{
unsigned char result;
do
result = random_colour();
while (result == LIGHTCYAN || result == CYAN || result == BROWN);
return (result);
}
unsigned char make_low_colour(unsigned char colour)
{
if (colour >= 8 && colour <= 15)
return (colour - 8);
return (colour);
}
unsigned char make_high_colour(unsigned char colour)
{
if (colour <= 7)
return (colour + 8);
return (colour);
}
// returns if a colour is one of the special element colours (ie not regular)
bool is_element_colour( int col )
{
// stripping any COLFLAGS (just in case)
return ((col & 0x007f) >= ETC_FIRE);
}
int element_colour( int element, bool no_random )
{
// Doing this so that we don't have to do recursion here at all
// (these were the only cases which had possible double evaluation):
if (element == ETC_FLOOR)
element = env.floor_colour;
else if (element == ETC_ROCK)
element = env.rock_colour;
// pass regular colours through for safety.
if (!is_element_colour( element ))
return (element);
int ret = BLACK;
// Setting no_random to true will get the first colour in the cases
// below. This is potentially useful for calls to this function
// which might want a consistent result.
int tmp_rand = (no_random ? 0 : random2(120));
// Strip COLFLAGs just in case.
element &= 0x007f;
switch (element)
{
case ETC_FIRE:
ret = (tmp_rand < 40) ? RED :
(tmp_rand < 80) ? YELLOW
: LIGHTRED;
break;
case ETC_ICE:
ret = (tmp_rand < 40) ? LIGHTBLUE :
(tmp_rand < 80) ? BLUE
: WHITE;
break;
case ETC_EARTH:
ret = (tmp_rand < 60) ? BROWN : LIGHTRED;
break;
case ETC_AIR:
ret = (tmp_rand < 60) ? LIGHTGREY : WHITE;
break;
case ETC_ELECTRICITY:
ret = (tmp_rand < 40) ? LIGHTCYAN :
(tmp_rand < 80) ? LIGHTBLUE
: CYAN;
break;
case ETC_POISON:
ret = (tmp_rand < 60) ? LIGHTGREEN : GREEN;
break;
case ETC_WATER:
ret = (tmp_rand < 60) ? BLUE : CYAN;
break;
case ETC_MAGIC:
ret = (tmp_rand < 30) ? LIGHTMAGENTA :
(tmp_rand < 60) ? LIGHTBLUE :
(tmp_rand < 90) ? MAGENTA
: BLUE;
break;
case ETC_MUTAGENIC:
case ETC_WARP:
ret = (tmp_rand < 60) ? LIGHTMAGENTA : MAGENTA;
break;
case ETC_ENCHANT:
ret = (tmp_rand < 60) ? LIGHTBLUE : BLUE;
break;
case ETC_HEAL:
ret = (tmp_rand < 60) ? LIGHTBLUE : YELLOW;
break;
case ETC_BLOOD:
ret = (tmp_rand < 60) ? RED : DARKGREY;
break;
case ETC_DEATH: // assassin
case ETC_NECRO: // necromancer
ret = (tmp_rand < 80) ? DARKGREY : MAGENTA;
break;
case ETC_UNHOLY: // ie demonology
ret = (tmp_rand < 80) ? DARKGREY : RED;
break;
case ETC_DARK:
ret = (tmp_rand < 80) ? DARKGREY : LIGHTGREY;
break;
case ETC_HOLY:
ret = (tmp_rand < 60) ? YELLOW : WHITE;
break;
case ETC_VEHUMET:
ret = (tmp_rand < 40) ? LIGHTRED :
(tmp_rand < 80) ? LIGHTMAGENTA
: LIGHTBLUE;
break;
case ETC_BEOGH:
ret = (tmp_rand < 60) ? LIGHTRED // plain Orc colour
: BROWN; // Orcish mines wall/idol colour
break;
case ETC_CRYSTAL:
ret = (tmp_rand < 40) ? LIGHTGREY :
(tmp_rand < 80) ? GREEN
: LIGHTRED;
break;
case ETC_SLIME:
ret = (tmp_rand < 40) ? GREEN :
(tmp_rand < 80) ? BROWN
: LIGHTGREEN;
break;
case ETC_SMOKE:
ret = (tmp_rand < 30) ? LIGHTGREY :
(tmp_rand < 60) ? DARKGREY :
(tmp_rand < 90) ? LIGHTBLUE
: MAGENTA;
break;
case ETC_JEWEL:
ret = (tmp_rand < 12) ? WHITE :
(tmp_rand < 24) ? YELLOW :
(tmp_rand < 36) ? LIGHTMAGENTA :
(tmp_rand < 48) ? LIGHTRED :
(tmp_rand < 60) ? LIGHTGREEN :
(tmp_rand < 72) ? LIGHTBLUE :
(tmp_rand < 84) ? MAGENTA :
(tmp_rand < 96) ? RED :
(tmp_rand < 108) ? GREEN
: BLUE;
break;
case ETC_ELVEN:
ret = (tmp_rand < 40) ? LIGHTGREEN :
(tmp_rand < 80) ? GREEN :
(tmp_rand < 100) ? LIGHTBLUE
: BLUE;
break;
case ETC_DWARVEN:
ret = (tmp_rand < 40) ? BROWN :
(tmp_rand < 80) ? LIGHTRED :
(tmp_rand < 100) ? LIGHTGREY
: CYAN;
break;
case ETC_ORCISH:
ret = (tmp_rand < 40) ? DARKGREY :
(tmp_rand < 80) ? RED :
(tmp_rand < 100) ? BROWN
: MAGENTA;
break;
case ETC_GILA:
ret = (tmp_rand < 30) ? LIGHTMAGENTA :
(tmp_rand < 60) ? MAGENTA :
(tmp_rand < 90) ? YELLOW :
(tmp_rand < 105) ? LIGHTRED
: RED;
break;
case ETC_KRAKEN:
ret = (tmp_rand < 15) ? GREEN :
(tmp_rand < 30) ? LIGHTGREEN :
(tmp_rand < 45) ? LIGHTCYAN :
(tmp_rand < 60) ? LIGHTBLUE :
(tmp_rand < 75) ? RED :
(tmp_rand < 90) ? LIGHTRED :
(tmp_rand < 105) ? MAGENTA
: LIGHTMAGENTA;
break;
case ETC_STONE:
if (player_in_branch(BRANCH_HALL_OF_ZOT))
ret = env.rock_colour;
else
ret = LIGHTGREY;
break;
case ETC_MIST:
ret = (tmp_rand < 100) ? CYAN : BLUE;
break;
case ETC_SHIMMER_BLUE:
ret = (tmp_rand < 90) ? BLUE :
(tmp_rand < 110) ? LIGHTBLUE
: CYAN;
break;
case ETC_DECAY:
ret = (tmp_rand < 60) ? BROWN : GREEN;
break;
case ETC_SILVER:
ret = (tmp_rand < 90) ? LIGHTGREY : WHITE;
break;
case ETC_GOLD:
ret = (tmp_rand < 60) ? YELLOW : BROWN;
break;
case ETC_IRON:
ret = (tmp_rand < 40) ? CYAN :
(tmp_rand < 80) ? LIGHTGREY :
DARKGREY;
break;
case ETC_BONE:
ret = (tmp_rand < 90) ? WHITE : LIGHTGREY;
break;
case ETC_RANDOM:
ret = random_colour(); // always random
break;
case ETC_FLOOR: // should already be handled
case ETC_ROCK: // should already be handled
default:
break;
}
ASSERT(!is_element_colour(ret));
return ((ret == BLACK) ? GREEN : ret);
}
#ifdef USE_TILE
static std::string tile_cols[24] =
{
"black", "darkgrey", "grey", "lightgrey", "white",
"blue", "lightblue", "darkblue",
"green", "lightgreen", "darkgreen",
"cyan", "lightcyan", "darkcyan",
"red", "lightred", "darkred",
"magenta", "lightmagenta", "darkmagenta",
"yellow", "lightyellow", "darkyellow", "brown"
};
unsigned int str_to_tile_colour(std::string colour)
{
if (colour.empty())
return (0);
lowercase(colour);
if (colour == "darkgray")
colour = "darkgrey";
else if (colour == "gray")
colour = "grey";
else if (colour == "lightgray")
colour = "lightgrey";
for (unsigned int i = 0; i < 24; i++)
{
if (tile_cols[i] == colour)
return (i);
}
return (0);
}
#endif
const std::string cols[16] =
{
"black", "blue", "green", "cyan", "red", "magenta", "brown",
"lightgrey", "darkgrey", "lightblue", "lightgreen", "lightcyan",
"lightred", "lightmagenta", "yellow", "white"
};
const std::string colour_to_str(unsigned char colour)
{
if ( colour >= 16 )
return "lightgrey";
else
return cols[colour];
}
// Returns -1 if unmatched else returns 0-15.
int str_to_colour( const std::string &str, int default_colour,
bool accept_number )
{
int ret;
static const std::string element_cols[] =
{
"fire", "ice", "earth", "electricity", "air", "poison", "water",
"magic", "mutagenic", "warp", "enchant", "heal", "holy", "dark",
"death", "necro", "unholy", "vehumet", "beogh", "crystal",
"blood", "smoke", "slime", "jewel", "elven", "dwarven",
"orcish", "gila", "kraken", "floor", "rock", "stone", "mist",
"shimmer_blue", "decay", "silver", "gold", "iron", "bone",
"random"
};
ASSERT(ARRAYSZ(element_cols) == (ETC_RANDOM - ETC_FIRE) + 1);
for (ret = 0; ret < 16; ++ret)
{
if (str == cols[ret])
break;
}
// Check for alternate spellings.
if (ret == 16)
{
if (str == "lightgray")
ret = 7;
else if (str == "darkgray")
ret = 8;
}
if (ret == 16)
{
// Maybe we have an element colour attribute.
for (unsigned i = 0; i < sizeof(element_cols) / sizeof(*element_cols);
++i)
{
if (str == element_cols[i])
{
// Ugh.
ret = element_type(ETC_FIRE + i);
break;
}
}
}
if (ret == 16 && accept_number)
{
// Check if we have a direct colour index.
const char *s = str.c_str();
char *es = NULL;
const int ci = static_cast<int>(strtol(s, &es, 10));
if (s != (const char *) es && es && ci >= 0 && ci < 16)
ret = ci;
}
return ((ret == 16) ? default_colour : ret);
}
#if defined(TARGET_OS_WINDOWS) || defined(TARGET_OS_DOS) || defined(USE_TILE)
static unsigned short _dos_reverse_brand(unsigned short colour)
{
if (Options.dos_use_background_intensity)
{
// If the console treats the intensity bit on background colours
// correctly, we can do a very simple colour invert.
// Special casery for shadows.
if (colour == BLACK)
colour = (DARKGREY << 4);
else
colour = (colour & 0xF) << 4;
}
else
{
// If we're on a console that takes its DOSness very seriously the
// background high-intensity bit is actually a blink bit. Blinking is
// evil, so we strip the background high-intensity bit. This, sadly,
// limits us to 7 background colours.
// Strip off high-intensity bit. Special case DARKGREY, since it's the
// high-intensity counterpart of black, and we don't want black on
// black.
//
// We *could* set the foreground colour to WHITE if the background
// intensity bit is set, but I think we've carried the
// angry-fruit-salad theme far enough already.
if (colour == DARKGREY)
colour |= (LIGHTGREY << 4);
else if (colour == BLACK)
colour = LIGHTGREY << 4;
else
{
// Zap out any existing background colour, and the high
// intensity bit.
colour &= 7;
// And swap the foreground colour over to the background
// colour, leaving the foreground black.
colour <<= 4;
}
}
return (colour);
}
static unsigned short _dos_hilite_brand(unsigned short colour,
unsigned short hilite)
{
if (!hilite)
return (colour);
if (colour == hilite)
colour = 0;
colour |= (hilite << 4);
return (colour);
}
unsigned short dos_brand( unsigned short colour,
unsigned brand)
{
if ((brand & CHATTR_ATTRMASK) == CHATTR_NORMAL)
return (colour);
colour &= 0xFF;
if ((brand & CHATTR_ATTRMASK) == CHATTR_HILITE)
return _dos_hilite_brand(colour, (brand & CHATTR_COLMASK) >> 8);
else
return _dos_reverse_brand(colour);
}
#endif
#if defined(TARGET_OS_WINDOWS) || defined(TARGET_OS_DOS) || defined(USE_TILE)
static unsigned _colflag2brand(int colflag)
{
switch (colflag)
{
case COLFLAG_ITEM_HEAP:
return (Options.heap_brand);
case COLFLAG_FRIENDLY_MONSTER:
return (Options.friend_brand);
case COLFLAG_NEUTRAL_MONSTER:
return (Options.neutral_brand);
case COLFLAG_WILLSTAB:
return (Options.stab_brand);
case COLFLAG_MAYSTAB:
return (Options.may_stab_brand);
case COLFLAG_FEATURE_ITEM:
return (Options.feature_item_brand);
case COLFLAG_TRAP_ITEM:
return (Options.trap_item_brand);
default:
return (CHATTR_NORMAL);
}
}
#endif
unsigned real_colour(unsigned raw_colour)
{
// This order is important - is_element_colour() doesn't want to see the
// munged colours returned by dos_brand, so it should always be done
// before applying DOS brands.
const int colflags = raw_colour & 0xFF00;
// Evaluate any elemental colours to guarantee vanilla colour is returned
if (is_element_colour( raw_colour ))
raw_colour = colflags | element_colour( raw_colour );
#if defined(TARGET_OS_WINDOWS) || defined(TARGET_OS_DOS) || defined(USE_TILE)
if (colflags)
{
unsigned brand = _colflag2brand(colflags);
raw_colour = dos_brand(raw_colour & 0xFF, brand);
}
#endif
#ifndef USE_COLOUR_OPTS
// Strip COLFLAGs for systems that can't do anything meaningful with them.
raw_colour &= 0xFF;
#endif
return (raw_colour);
}