Tile getSpriteTile(const ViewObject& obj) { if (obj.id() == ViewId::SPECIAL_BEAST) return getSpecialCreatureSprite(obj, false); if (obj.id() == ViewId::SPECIAL_HUMANOID) return getSpecialCreatureSprite(obj, true); return getSprite(obj.id()); }
Vec2 MapGui::getMovementOffset(const ViewObject& object, Vec2 size, double time, int curTimeReal) { if (!object.hasAnyMovementInfo()) return Vec2(0, 0); double state; Vec2 dir; if (screenMovement && curTimeReal >= screenMovement->startTimeReal && curTimeReal <= screenMovement->endTimeReal) { state = (double(curTimeReal) - screenMovement->startTimeReal) / (screenMovement->endTimeReal - screenMovement->startTimeReal); dir = object.getMovementInfo(screenMovement->startTimeGame, screenMovement->endTimeGame, screenMovement->creatureId); } else if (object.hasAnyMovementInfo() && !screenMovement) { ViewObject::MovementInfo info = object.getLastMovementInfo(); dir = info.direction; if (info.direction.length8() == 0 || time >= info.tEnd || time <= info.tBegin) return Vec2(0, 0); state = (time - info.tBegin) / (info.tEnd - info.tBegin); double minStopTime = 0.2; state = min(1.0, max(0.0, (state - minStopTime) / (1.0 - 2 * minStopTime))); } else return Vec2(0, 0); if (object.getLastMovementInfo().type == ViewObject::MovementInfo::ATTACK) if (dir.length8() == 1) return Vec2(0.8 * (state < 0.5 ? state : 1 - state) * dir.x * size.x, (0.8 * (state < 0.5 ? state : 1 - state)* dir.y - getJumpOffset(object, state)) * size.y); return Vec2((state - 1) * dir.x * size.x, ((state - 1)* dir.y - getJumpOffset(object, state)) * size.y); }
void ViewIndex::insert(ViewObject obj) { PROFILE; int ind = objIndex[int(obj.layer())]; if (ind < 100) objects[ind] = std::move(obj); else { objIndex[int(obj.layer())] = objects.size(); objects.push_back(std::move(obj)); } }
static int32 animation_thread(void *cookie) { ViewObject *view = (ViewObject *) cookie; while (1) { view->Render(); view->GLCheckError(); snooze(1); } return B_OK; // keep compiler happy }
void MapGui::drawCreatureHighlights(Renderer& renderer, const ViewObject& object, Rectangle tile) { if (object.hasModifier(ViewObject::Modifier::PLAYER)) { renderer.drawFilledRectangle(tile, Color::Transparent, colors[ColorId::LIGHT_GRAY]); } if (object.hasModifier(ViewObject::Modifier::DRAW_MORALE) && showMorale) drawMorale(renderer, tile, object.getAttribute(ViewObject::Attribute::MORALE)); if (object.hasModifier(ViewObject::Modifier::TEAM_LEADER_HIGHLIGHT)) { renderer.drawFilledRectangle(tile, Color::Transparent, colors[ColorId::YELLOW]); } else if (object.hasModifier(ViewObject::Modifier::TEAM_HIGHLIGHT)) { renderer.drawFilledRectangle(tile, Color::Transparent, transparency(colors[ColorId::YELLOW], 120)); } }
Tile getSpecialCreature(const ViewObject& obj, bool humanoid) { RandomGen r; r.init(hash<string>()(obj.getBareDescription())); string let = humanoid ? "WETUIPLKJHFAXBM" : "qwetyupkfaxbnm"; char c; if (contains(let, obj.getBareDescription()[0])) c = obj.getBareDescription()[0]; else if (contains(let, tolower(obj.getBareDescription()[0]))) c = tolower(obj.getBareDescription()[0]); else c = let[r.get(let.size())]; return Tile::unicode(c, ColorId(Random.get(EnumInfo<ColorId>::getSize()))); }
Color Tile::getColor(const ViewObject& object) { if (object.hasModifier(ViewObject::Modifier::INVISIBLE)) return colors[ColorId::DARK_GRAY]; if (object.hasModifier(ViewObject::Modifier::HIDDEN)) return colors[ColorId::LIGHT_GRAY]; double bleeding = object.getAttribute(ViewObject::Attribute::BLEEDING); if (bleeding > 0) bleeding = 0.5 + bleeding / 2; bleeding = min(1., bleeding); Color color = getAsciiTile(object).color; return Color( (1 - bleeding) * color.r + bleeding * 255, (1 - bleeding) * color.g, (1 - bleeding) * color.b); }
Color Tile::getColor(const ViewObject& object) { if (object.hasModifier(ViewObject::INVISIBLE)) return darkGray; if (object.hasModifier(ViewObject::HIDDEN)) return lightGray; double bleeding = object.getBleeding(); if (bleeding > 0) bleeding = 0.5 + bleeding / 2; bleeding = min(1., bleeding); Color color = getAsciiTile(object).color; return Color( (1 - bleeding) * color.r + bleeding * 255, (1 - bleeding) * color.g, (1 - bleeding) * color.b); }
Tile getSpecialCreature(const ViewObject& obj, bool humanoid) { RandomGen r; r.init(hash<string>()(obj.getBareDescription())); string let = humanoid ? "WETUIPLKJHFAXBM" : "qwetyupkfaxbnm"; char c; if (contains(let, obj.getBareDescription()[0])) c = obj.getBareDescription()[0]; else if (contains(let, tolower(obj.getBareDescription()[0]))) c = tolower(obj.getBareDescription()[0]); else c = let[r.getRandom(let.size())]; Color col(r.getRandom(80, 250), r.getRandom(80, 250), 0); return Tile(c, col); }
Tile getSpecialCreatureSprite(const ViewObject& obj, bool humanoid) { RandomGen r; r.init(hash<string>()(obj.getBareDescription())); if (humanoid) return Tile::byCoord(r.get(7), 10); else return Tile::byCoord(r.get(7, 10), 10); }
static double getJumpOffset(const ViewObject& object, double state) { if (object.hasModifier(ViewObjectModifier::NO_UP_MOVEMENT)) return 0; if (state > 0.5) state -= 0.5; state *= 2; const double maxH = 0.09; return maxH * (1.0 - (2.0 * state - 1) * (2.0 * state - 1)); }
Tile getAsciiTile(const ViewObject& obj) { ViewId id = obj.id(); if (id == ViewId::SPECIAL_BEAST) return getSpecialCreature(obj, false); if (id == ViewId::SPECIAL_HUMANOID) return getSpecialCreature(obj, true); if (symbols.count(id)) return symbols.at(id); else FAIL << "unhandled view id " << EnumInfo<ViewId>::getString(id); return Tile::unicode(' ', ColorId(0)); }
void MapGui::updateObjects(const MapMemory* mem) { lastMemory = mem; floorIds.clear(); shadowed.clear(); for (Vec2 wpos : layout->getAllTiles(getBounds(), objects.getBounds())) if (auto& index = objects[wpos]) { if (index->hasObject(ViewLayer::FLOOR)) { ViewObject object = index->getObject(ViewLayer::FLOOR); if (object.hasModifier(ViewObject::Modifier::CASTS_SHADOW)) { shadowed.erase(wpos); shadowed.insert(wpos + Vec2(0, 1)); } if (auto id = getConnectionId(object)) floorIds.insert(make_pair(wpos, *id)); } else if (index->hasObject(ViewLayer::FLOOR_BACKGROUND)) { if (auto id = getConnectionId(index->getObject(ViewLayer::FLOOR_BACKGROUND))) floorIds.insert(make_pair(wpos, *id)); } else if (auto viewId = index->getHiddenId()) if (auto id = getConnectionId(*viewId)) floorIds.insert(make_pair(wpos, *id)); } }
void MapGui::drawCreatureHighlights(Renderer& renderer, const ViewObject& object, Vec2 pos, Vec2 sz, int curTime) { if (object.hasModifier(ViewObject::Modifier::PLAYER)) drawCreatureHighlight(renderer, pos, sz, colors[ColorId::ALMOST_WHITE]); if (object.hasModifier(ViewObject::Modifier::DRAW_MORALE) && showMorale) drawCreatureHighlight(renderer, pos, sz, getMoraleColor(object.getAttribute(ViewObject::Attribute::MORALE))); if (object.hasModifier(ViewObject::Modifier::TEAM_LEADER_HIGHLIGHT) && (curTime / 1000) % 2) { drawCreatureHighlight(renderer, pos, sz, colors[ColorId::YELLOW]); } else if (object.hasModifier(ViewObject::Modifier::TEAM_HIGHLIGHT)) drawCreatureHighlight(renderer, pos, sz, colors[ColorId::YELLOW]); if (object.getCreatureId()) { Color c = getCreatureHighlight(*object.getCreatureId(), curTime); if (c.a > 0) drawCreatureHighlight(renderer, pos, sz, c); } }
void Renderer::drawViewObject(Vec2 pos, const ViewObject& object, bool useSprite, double scale) { drawViewObject(pos, object.id(), useSprite, scale, getBleedingColor(object)); }
Color Renderer::getBleedingColor(const ViewObject& object) { double bleeding = object.getAttribute(ViewObject::Attribute::BLEEDING); if (bleeding > 0) bleeding = 0.3 + bleeding * 0.7; return Color(255, max(0., (1 - bleeding) * 255), max(0., (1 - bleeding) * 255)); }
void MapGui::drawObjectAbs(Renderer& renderer, int x, int y, const ViewObject& object, int sizeX, int sizeY, Vec2 tilePos) { if (object.hasModifier(ViewObject::Modifier::PLAYER)) { renderer.drawFilledRectangle(x, y, x + sizeX, y + sizeY, Color::Transparent, colors[ColorId::LIGHT_GRAY]); } if (object.hasModifier(ViewObject::Modifier::DRAW_MORALE)) drawMorale(renderer, Rectangle(x, y, x + sizeX, y + sizeY), object.getAttribute(ViewObject::Attribute::MORALE)); if (object.hasModifier(ViewObject::Modifier::TEAM_HIGHLIGHT)) { renderer.drawFilledRectangle(x, y, x + sizeX, y + sizeY, Color::Transparent, colors[ColorId::DARK_GREEN]); } const Tile& tile = Tile::getTile(object, spriteMode); Color color = Renderer::getBleedingColor(object); if (object.hasModifier(ViewObject::Modifier::INVISIBLE) || object.hasModifier(ViewObject::Modifier::HIDDEN)) color = transparency(color, 70); else if (tile.translucent > 0) color = transparency(color, 255 * (1 - tile.translucent)); else if (object.hasModifier(ViewObject::Modifier::ILLUSION)) color = transparency(color, 150); if (object.hasModifier(ViewObject::Modifier::PLANNED)) color = transparency(color, 100); double waterDepth = object.getAttribute(ViewObject::Attribute::WATER_DEPTH); if (waterDepth > 0) { int val = max(0.0, 255.0 - min(2.0, waterDepth) * 60); color = Color(val, val, val); } if (tile.hasSpriteCoord()) { Vec2 move; Vec2 sz = Renderer::tileSize[tile.getTexNum()]; Vec2 off = (Renderer::nominalSize - sz).mult(Vec2(sizeX, sizeY)).div(Renderer::nominalSize * 2); int width = sz.x * sizeX / Renderer::nominalSize.x; int height = sz.y* sizeY / Renderer::nominalSize.y; if (sz.y > Renderer::nominalSize.y) off.y *= 2; EnumSet<Dir> dirs; EnumSet<Dir> borderDirs; if (!object.hasModifier(ViewObject::Modifier::PLANNED)) if (auto connectionId = getConnectionId(object)) for (Vec2 dir : getConnectionDirs(object.id())) { if (tileConnects(*connectionId, tilePos + dir)) dirs.insert(dir.getCardinalDir()); else borderDirs.insert(dir.getCardinalDir()); } Vec2 coord = tile.getSpriteCoord(dirs); if (object.hasModifier(ViewObject::Modifier::MOVE_UP)) move.y = -4* sizeY / Renderer::nominalSize.y; if ((object.layer() == ViewLayer::CREATURE && object.id() != ViewId::BOULDER) || object.hasModifier(ViewObject::Modifier::ROUND_SHADOW)) { renderer.drawSprite(x, y - 2, 2 * Renderer::nominalSize.x, 22 * Renderer::nominalSize.y, Renderer::nominalSize.x, Renderer::nominalSize.y, Renderer::tiles[0], min(Renderer::nominalSize.x, width), min(Renderer::nominalSize.y, height)); move.y = -4* sizeY / Renderer::nominalSize.y; } if (auto background = tile.getBackgroundCoord()) { renderer.drawSprite(x + off.x, y + off.y, background->x * sz.x, background->y * sz.y, sz.x, sz.y, Renderer::tiles[tile.getTexNum()], width, height, color); if (shadowed.count(tilePos)) renderer.drawSprite(x, y, 1 * Renderer::nominalSize.x, 21 * Renderer::nominalSize.y, Renderer::nominalSize.x, Renderer::nominalSize.y, Renderer::tiles[5], width, height); } if (coord.x < 0) return; if (auto dir = object.getAttachmentDir()) move = getAttachmentOffset(*dir, width, height); renderer.drawSprite(x + off.x + move.x, y + move.y + off.y, coord.x * sz.x, coord.y * sz.y, sz.x, sz.y, Renderer::tiles[tile.getTexNum()], width, height, color); if (tile.hasCorners()) { for (Vec2 coord : tile.getCornerCoords(dirs)) renderer.drawSprite(x + off.x + move.x, y + move.y + off.y, coord.x * sz.x, coord.y * sz.y, sz.x, sz.y, Renderer::tiles[tile.getTexNum()], width, height, color); } if (tile.floorBorders) { drawFloorBorders(renderer, borderDirs, x, y); } if (contains({ViewLayer::FLOOR, ViewLayer::FLOOR_BACKGROUND}, object.layer()) && shadowed.count(tilePos) && !tile.noShadow) renderer.drawSprite(x, y, 1 * Renderer::nominalSize.x, 21 * Renderer::nominalSize.y, Renderer::nominalSize.x, Renderer::nominalSize.y, Renderer::tiles[5], width, height); if (object.getAttribute(ViewObject::Attribute::BURNING) > 0) { renderer.drawSprite(x, y, Random.get(10, 12) * Renderer::nominalSize.x, 0 * Renderer::nominalSize.y, Renderer::nominalSize.x, Renderer::nominalSize.y, Renderer::tiles[2], width, height); } if (object.hasModifier(ViewObject::Modifier::LOCKED)) renderer.drawSprite(x + (Renderer::nominalSize.x - Renderer::tileSize[3].x) / 2, y, 5 * Renderer::tileSize[3].x, 6 * Renderer::tileSize[3].y, Renderer::tileSize[3].x, Renderer::tileSize[3].y, Renderer::tiles[3], width / 2, height / 2); } else { renderer.drawText(tile.symFont ? Renderer::SYMBOL_FONT : Renderer::TILE_FONT, sizeY, Tile::getColor(object), x + sizeX / 2, y - 3, tile.text, true); double burningVal = object.getAttribute(ViewObject::Attribute::BURNING); if (burningVal > 0) { renderer.drawText(Renderer::SYMBOL_FONT, sizeY, getFireColor(), x + sizeX / 2, y - 3, L'ѡ', true); if (burningVal > 0.5) renderer.drawText(Renderer::SYMBOL_FONT, sizeY, getFireColor(), x + sizeX / 2, y - 3, L'Ѡ', true); } } }
Optional<ViewId> getConnectionId(const ViewObject& object) { if (object.hasModifier(ViewObject::Modifier::PLANNED)) return Nothing(); else return getConnectionId(object.id()); }
void MapGui::drawObjectAbs(Renderer& renderer, Vec2 pos, const ViewObject& object, Vec2 size, Vec2 tilePos, int curTimeReal, const EnumMap<HighlightType, double>& highlightMap) { const Tile& tile = Tile::getTile(object.id(), spriteMode); Color color = Renderer::getBleedingColor(object); if (object.hasModifier(ViewObject::Modifier::INVISIBLE) || object.hasModifier(ViewObject::Modifier::HIDDEN)) color = transparency(color, 70); else if (tile.translucent > 0) color = transparency(color, 255 * (1 - tile.translucent)); else if (object.hasModifier(ViewObject::Modifier::ILLUSION)) color = transparency(color, 150); if (object.hasModifier(ViewObject::Modifier::PLANNED)) color = transparency(color, 100); double waterDepth = object.getAttribute(ViewObject::Attribute::WATER_DEPTH); if (waterDepth > 0) { int val = max(0.0, 255.0 - min(2.0, waterDepth) * 60); color = Color(val, val, val); } if (spriteMode && tile.hasSpriteCoord()) { DirSet dirs; DirSet borderDirs; if (auto connectionId = getConnectionId(object)) for (Vec2 dir : getConnectionDirs(object.id())) { if ((tilePos + dir).inRectangle(levelBounds) && connectionMap.has(tilePos + dir, *connectionId)) dirs.insert(dir.getCardinalDir()); else borderDirs.insert(dir.getCardinalDir()); } Vec2 move; Vec2 movement = getMovementOffset(object, size, currentTimeGame, curTimeReal); drawCreatureHighlights(renderer, object, pos + movement, size, curTimeReal); if ((object.layer() == ViewLayer::CREATURE && object.id() != ViewId::BOULDER) || object.hasModifier(ViewObject::Modifier::ROUND_SHADOW)) { static auto coord = renderer.getTileCoord("round_shadow"); renderer.drawTile(pos + movement, coord, size, sf::Color(255, 255, 255, 160)); move.y = -4* size.y / renderer.getNominalSize().y; } static auto shortShadow = renderer.getTileCoord("short_shadow"); if (auto background = tile.getBackgroundCoord()) { renderer.drawTile(pos, *background, size, color); if (shadowed.count(tilePos)) renderer.drawTile(pos, shortShadow, size, sf::Color(255, 255, 255, 170)); } if (auto dir = object.getAttachmentDir()) move = getAttachmentOffset(*dir, size); move += movement; if (mirrorSprite(object.id())) renderer.drawTile(pos + move, tile.getSpriteCoord(dirs), size, color, object.getPositionHash() % 2, object.getPositionHash() % 4 > 1); else renderer.drawTile(pos + move, tile.getSpriteCoord(dirs), size, color); if (object.layer() == ViewLayer::FLOOR && highlightMap[HighlightType::CUT_TREE] > 0) if (auto coord = tile.getHighlightCoord()) renderer.drawTile(pos + move, *coord, size, color); if (!buttonViewId) if (auto id = object.getCreatureId()) creatureMap.push_back(CreatureInfo{Rectangle(pos + move, pos + move + size), *id, object.id()}); if (tile.hasCorners()) { for (auto coord : tile.getCornerCoords(dirs)) renderer.drawTile(pos + move, coord, size, color); } /* if (tile.floorBorders) { drawFloorBorders(renderer, borderDirs, x, y); }*/ if ((object.layer() == ViewLayer::FLOOR || object.layer() == ViewLayer::FLOOR_BACKGROUND) && shadowed.count(tilePos) && !tile.noShadow) renderer.drawTile(pos, shortShadow, size, sf::Color(255, 255, 255, 170)); if (object.getAttribute(ViewObject::Attribute::BURNING) > 0) { static auto fire1 = renderer.getTileCoord("fire1"); static auto fire2 = renderer.getTileCoord("fire2"); renderer.drawTile(pos, Random.choose({fire1, fire2}), size); } static auto key = renderer.getTileCoord("key"); if (object.hasModifier(ViewObject::Modifier::LOCKED)) renderer.drawTile(pos, key, size); } else { Vec2 movement = getMovementOffset(object, size, currentTimeGame, curTimeReal); Vec2 tilePos = pos + movement + Vec2(size.x / 2, -3); drawCreatureHighlights(renderer, object, pos, size, curTimeReal); renderer.drawText(tile.symFont ? Renderer::SYMBOL_FONT : Renderer::TILE_FONT, size.y, Tile::getColor(object), tilePos.x, tilePos.y, tile.text, Renderer::HOR); if (!buttonViewId) if (auto id = object.getCreatureId()) creatureMap.push_back(CreatureInfo{Rectangle(tilePos, tilePos + size), *id, object.id()}); double burningVal = object.getAttribute(ViewObject::Attribute::BURNING); if (burningVal > 0) { renderer.drawText(Renderer::SYMBOL_FONT, size.y, getFireColor(), pos.x + size.x / 2, pos.y - 3, L'ѡ', Renderer::HOR); if (burningVal > 0.5) renderer.drawText(Renderer::SYMBOL_FONT, size.y, getFireColor(), pos.x + size.x / 2, pos.y - 3, L'Ѡ', Renderer::HOR); } } }
optional<ViewId> getConnectionId(const ViewObject& object) { return getConnectionId(object.id()); }
Tile getAsciiTile(const ViewObject& obj) { switch (obj.id()) { case ViewId::EMPTY: return Tile(' ', black); case ViewId::PLAYER: return Tile('@', white); case ViewId::KEEPER: return Tile('@', purple); case ViewId::UNKNOWN_MONSTER: return Tile('?', lightGreen); case ViewId::SPECIAL_BEAST: return getSpecialCreature(obj, false); case ViewId::SPECIAL_HUMANOID: return getSpecialCreature(obj, true); case ViewId::ELF: return Tile('@', lightGreen); case ViewId::ELF_ARCHER: return Tile('@', green); case ViewId::ELF_CHILD: return Tile('@', lightGreen); case ViewId::ELF_LORD: return Tile('@', darkGreen); case ViewId::ELVEN_SHOPKEEPER: return Tile('@', lightBlue); case ViewId::LIZARDMAN: return Tile('@', lightBrown); case ViewId::LIZARDLORD: return Tile('@', brown); case ViewId::IMP: return Tile('i', lightBrown); case ViewId::PRISONER: return Tile('@', lightBrown); case ViewId::BILE_DEMON: return Tile('O', green); case ViewId::CHICKEN: return Tile('c', yellow); case ViewId::DWARF: return Tile('h', blue); case ViewId::DWARF_BARON: return Tile('h', darkBlue); case ViewId::DWARVEN_SHOPKEEPER: return Tile('h', lightBlue); case ViewId::FLOOR: return Tile('.', white); case ViewId::BRIDGE: return Tile('_', brown); case ViewId::ROAD: return Tile('.', lightGray); case ViewId::PATH: return Tile('.', lightGray); case ViewId::SAND: return Tile('.', yellow); case ViewId::MUD: return Tile(0x1d0f0, brown, true); case ViewId::GRASS: return Tile(0x1d0f0, green, true); case ViewId::CROPS: return Tile(0x1d0f0, yellow, true); case ViewId::CASTLE_WALL: return Tile('#', lightGray); case ViewId::MUD_WALL: return Tile('#', lightBrown); case ViewId::WALL: return Tile('#', lightGray); case ViewId::MOUNTAIN: return Tile(0x25ee, darkGray, true); case ViewId::MOUNTAIN2: return Tile('#', darkGray); case ViewId::GOLD_ORE: return Tile(L'⁂', yellow, true); case ViewId::IRON_ORE: return Tile(L'⁂', darkBrown, true); case ViewId::STONE: return Tile(L'⁂', lightGray, true); case ViewId::SNOW: return Tile(0x25ee, white, true); case ViewId::HILL: return Tile(0x1d022, darkGreen, true); case ViewId::WOOD_WALL: return Tile('#', darkBrown); case ViewId::BLACK_WALL: return Tile('#', lightGray); case ViewId::YELLOW_WALL: return Tile('#', yellow); case ViewId::LOW_ROCK_WALL: return Tile('#', darkGray); case ViewId::HELL_WALL: return Tile('#', red); case ViewId::SECRETPASS: return Tile('#', lightGray); case ViewId::DUNGEON_ENTRANCE: case ViewId::DUNGEON_ENTRANCE_MUD: return Tile(0x2798, brown, true); case ViewId::DOWN_STAIRCASE_CELLAR: case ViewId::DOWN_STAIRCASE: return Tile(0x2798, almostWhite, true); case ViewId::UP_STAIRCASE_CELLAR: case ViewId::UP_STAIRCASE: return Tile(0x279a, almostWhite, true); case ViewId::DOWN_STAIRCASE_HELL: return Tile(0x2798, red, true); case ViewId::UP_STAIRCASE_HELL: return Tile(0x279a, red, true); case ViewId::DOWN_STAIRCASE_PYR: return Tile(0x2798, yellow, true); case ViewId::UP_STAIRCASE_PYR: return Tile(0x279a, yellow, true); case ViewId::GREAT_GOBLIN: return Tile('O', purple); case ViewId::GOBLIN: return Tile('o', darkBlue); case ViewId::BANDIT: return Tile('@', darkBlue); case ViewId::DARK_KNIGHT: return Tile('@', purple); case ViewId::GREEN_DRAGON: return Tile('D', green); case ViewId::RED_DRAGON: return Tile('D', red); case ViewId::CYCLOPS: return Tile('C', green); case ViewId::WITCH: return Tile('@', brown); case ViewId::GHOST: return Tile('&', white); case ViewId::SPIRIT: return Tile('&', lightBlue); case ViewId::DEVIL: return Tile('&', purple); case ViewId::CASTLE_GUARD: return Tile('@', lightGray); case ViewId::KNIGHT: return Tile('@', lightGray); case ViewId::WARRIOR: return Tile('@', darkGray); case ViewId::SHAMAN: return Tile('@', yellow); case ViewId::AVATAR: return Tile('@', blue); case ViewId::ARCHER: return Tile('@', brown); case ViewId::PESEANT: return Tile('@', green); case ViewId::CHILD: return Tile('@', lightGreen); case ViewId::CLAY_GOLEM: return Tile('Y', yellow); case ViewId::STONE_GOLEM: return Tile('Y', lightGray); case ViewId::IRON_GOLEM: return Tile('Y', orange); case ViewId::LAVA_GOLEM: return Tile('Y', purple); case ViewId::ZOMBIE: return Tile('Z', green); case ViewId::SKELETON: return Tile('Z', white); case ViewId::VAMPIRE: return Tile('V', darkGray); case ViewId::VAMPIRE_LORD: return Tile('V', purple); case ViewId::MUMMY: return Tile('Z', yellow); case ViewId::MUMMY_LORD: return Tile('Z', orange); case ViewId::ACID_MOUND: return Tile('j', green); case ViewId::JACKAL: return Tile('d', lightBrown); case ViewId::DEER: return Tile('R', darkBrown); case ViewId::HORSE: return Tile('H', lightBrown); case ViewId::COW: return Tile('C', white); case ViewId::SHEEP: return Tile('s', white); case ViewId::PIG: return Tile('p', yellow); case ViewId::GOAT: return Tile('g', gray); case ViewId::BOAR: return Tile('b', lightBrown); case ViewId::FOX: return Tile('d', orangeBrown); case ViewId::WOLF: return Tile('d', darkBlue); case ViewId::VODNIK: return Tile('f', green); case ViewId::KRAKEN: return Tile('S', darkGreen); case ViewId::DEATH: return Tile('D', darkGray); case ViewId::KRAKEN2: return Tile('S', green); case ViewId::NIGHTMARE: return Tile('n', purple); case ViewId::FIRE_SPHERE: return Tile('e', red); case ViewId::BEAR: return Tile('N', brown); case ViewId::BAT: return Tile('b', darkGray); case ViewId::GNOME: return Tile('g', green); case ViewId::LEPRECHAUN: return Tile('l', green); case ViewId::RAT: return Tile('r', brown); case ViewId::SPIDER: return Tile('s', brown); case ViewId::FLY: return Tile('b', gray); case ViewId::SCORPION: return Tile('s', lightGray); case ViewId::SNAKE: return Tile('S', yellow); case ViewId::VULTURE: return Tile('v', darkGray); case ViewId::RAVEN: return Tile('v', darkGray); case ViewId::BODY_PART: return Tile('%', red); case ViewId::BONE: return Tile('%', white); case ViewId::BUSH: return Tile('&', darkGreen); case ViewId::DECID_TREE: return Tile(0x1f70d, darkGreen, true); case ViewId::CANIF_TREE: return Tile(0x2663, darkGreen, true); case ViewId::TREE_TRUNK: return Tile('.', brown); case ViewId::BURNT_TREE: return Tile('.', darkGray); case ViewId::WATER: return Tile('~', lightBlue); case ViewId::MAGMA: return Tile('~', red); case ViewId::ABYSS: return Tile('~', darkGray); case ViewId::DOOR: return Tile('|', brown); case ViewId::BARRICADE: return Tile('X', brown); case ViewId::DIG_ICON: return Tile(0x26cf, lightGray, true); case ViewId::SWORD: return Tile(')', lightGray); case ViewId::SPEAR: return Tile('/', lightGray); case ViewId::SPECIAL_SWORD: return Tile(')', yellow); case ViewId::ELVEN_SWORD: return Tile(')', gray); case ViewId::KNIFE: return Tile(')', white); case ViewId::WAR_HAMMER: return Tile(')', blue); case ViewId::SPECIAL_WAR_HAMMER: return Tile(')', lightBlue); case ViewId::BATTLE_AXE: return Tile(')', green); case ViewId::SPECIAL_BATTLE_AXE: return Tile(')', lightGreen); case ViewId::BOW: return Tile(')', brown); case ViewId::ARROW: return Tile('\\', brown); case ViewId::SCROLL: return Tile('?', white); case ViewId::STEEL_AMULET: return Tile('\"', yellow); case ViewId::COPPER_AMULET: return Tile('\"', yellow); case ViewId::CRYSTAL_AMULET: return Tile('\"', yellow); case ViewId::WOODEN_AMULET: return Tile('\"', yellow); case ViewId::AMBER_AMULET: return Tile('\"', yellow); case ViewId::BOOK: return Tile('+', yellow); case ViewId::FIRST_AID: return Tile('+', red); case ViewId::TRAP_ITEM: return Tile('+', yellow); case ViewId::EFFERVESCENT_POTION: return Tile('!', lightRed); case ViewId::MURKY_POTION: return Tile('!', blue); case ViewId::SWIRLY_POTION: return Tile('!', yellow); case ViewId::VIOLET_POTION: return Tile('!', violet); case ViewId::PUCE_POTION: return Tile('!', darkBrown); case ViewId::SMOKY_POTION: return Tile('!', lightGray); case ViewId::FIZZY_POTION: return Tile('!', lightBlue); case ViewId::MILKY_POTION: return Tile('!', white); case ViewId::SLIMY_MUSHROOM: return Tile(0x22c6, darkGray, true); case ViewId::PINK_MUSHROOM: return Tile(0x22c6, pink, true); case ViewId::DOTTED_MUSHROOM: return Tile(0x22c6, green, true); case ViewId::GLOWING_MUSHROOM: return Tile(0x22c6, lightBlue, true); case ViewId::GREEN_MUSHROOM: return Tile(0x22c6, green, true); case ViewId::BLACK_MUSHROOM: return Tile(0x22c6, darkGray, true); case ViewId::FOUNTAIN: return Tile('0', lightBlue); case ViewId::GOLD: return Tile('$', yellow); case ViewId::OPENED_CHEST: case ViewId::CHEST: return Tile('=', brown); case ViewId::OPENED_COFFIN: case ViewId::COFFIN: return Tile(L'⚰', darkGray, true); case ViewId::BOULDER: return Tile(L'●', lightGray, true); case ViewId::PORTAL: return Tile(0x1d6af, lightGreen, true); case ViewId::TRAP: return Tile(L'➹', yellow, true); case ViewId::GAS_TRAP: return Tile(L'☠', green, true); case ViewId::ALARM_TRAP: return Tile(L'^', red, true); case ViewId::WEB_TRAP: return Tile('#', white, true); case ViewId::SURPRISE_TRAP: return Tile('^', blue, true); case ViewId::TERROR_TRAP: return Tile('^', white, true); case ViewId::ROCK: return Tile('*', lightGray); case ViewId::IRON_ROCK: return Tile('*', orange); case ViewId::WOOD_PLANK: return Tile('\\', brown); case ViewId::STOCKPILE: return Tile('.', yellow); case ViewId::PRISON: return Tile('.', blue); case ViewId::BED: return Tile('=', white); case ViewId::DUNGEON_HEART: return Tile(L'♥', white, true); case ViewId::TORCH: return Tile('I', orange); case ViewId::ALTAR: return Tile(L'Ω', white); case ViewId::TORTURE_TABLE: return Tile('=', gray); case ViewId::IMPALED_HEAD: return Tile(L'𐌒', brown); case ViewId::TRAINING_DUMMY: return Tile(L'‡', brown, true); case ViewId::LIBRARY: return Tile(L'▤', brown, true); case ViewId::LABORATORY: return Tile(L'ω', purple, true); case ViewId::ANIMAL_TRAP: return Tile(L'▥', lightGray, true); case ViewId::WORKSHOP: return Tile('&', lightBlue); case ViewId::GRAVE: return Tile(0x2617, gray, true); case ViewId::BARS: return Tile(L'⧻', lightBlue); case ViewId::BORDER_GUARD: return Tile(' ', white); case ViewId::LEATHER_ARMOR: return Tile('[', brown); case ViewId::LEATHER_HELM: return Tile('[', brown); case ViewId::TELEPATHY_HELM: return Tile('[', lightGreen); case ViewId::CHAIN_ARMOR: return Tile('[', lightGray); case ViewId::IRON_HELM: return Tile('[', lightGray); case ViewId::LEATHER_BOOTS: return Tile('[', brown); case ViewId::IRON_BOOTS: return Tile('[', lightGray); case ViewId::SPEED_BOOTS: return Tile('[', lightBlue); case ViewId::DESTROYED_FURNITURE: return Tile('*', brown); case ViewId::BURNT_FURNITURE: return Tile('*', darkGray); case ViewId::FALLEN_TREE: return Tile('*', green); case ViewId::GUARD_POST: return Tile(L'⚐', yellow, true); case ViewId::DESTROY_BUTTON: return Tile('X', red); case ViewId::MANA: return Tile('*', blue); case ViewId::DANGER: return Tile('*', red); case ViewId::FETCH_ICON: return Tile(0x1f44b, lightBrown); } FAIL << "unhandled view id " << (int)obj.id(); return Tile(' ', white); }