Ejemplo n.º 1
0
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());
}
Ejemplo n.º 2
0
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));
}
Ejemplo n.º 3
0
void Renderer::drawViewObject(Vec2 pos, const ViewObject& object, bool useSprite, double scale) {
  drawViewObject(pos, object.id(), useSprite, scale, getBleedingColor(object));
}
Ejemplo n.º 4
0
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);
    }
  }
}
Ejemplo n.º 5
0
Optional<ViewId> getConnectionId(const ViewObject& object) {
  if (object.hasModifier(ViewObject::Modifier::PLANNED))
    return Nothing();
  else
    return getConnectionId(object.id());
}
Ejemplo n.º 6
0
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);
    }
  }
}
Ejemplo n.º 7
0
optional<ViewId> getConnectionId(const ViewObject& object) {
  return getConnectionId(object.id());
}
Ejemplo n.º 8
0
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);
}