LambdaHack-0.7.0.0: GameDefinition/Content/TileKind.hs
-- | Terrain tile definitions.
module Content.TileKind
( cdefs
) where
import Prelude ()
import Game.LambdaHack.Common.Prelude
import qualified Data.Text as T
import Game.LambdaHack.Common.Color
import Game.LambdaHack.Common.ContentDef
import Game.LambdaHack.Common.Misc
import Game.LambdaHack.Content.TileKind
cdefs :: ContentDef TileKind
cdefs = ContentDef
{ getSymbol = tsymbol
, getName = tname
, getFreq = tfreq
, validateSingle = validateSingleTileKind
, validateAll = validateAllTileKind
, content = contentFromList $
[unknown, hardRock, bedrock, wall, wallSuspect, wallObscured, wallH, wallSuspectH, wallObscuredDefacedH, wallObscuredFrescoedH, pillar, pillarCache, lampPost, signboardUnread, signboardRead, tree, treeBurnt, treeBurning, rubble, rubbleSpice, doorTrapped, doorClosed, doorTrappedH, doorClosedH, stairsUp, stairsTaintedUp, stairsOutdoorUp, stairsGatedUp, stairsDown, stairsTaintedDown, stairsOutdoorDown, stairsGatedDown, escapeUp, escapeDown, escapeOutdoorDown, wallGlass, wallGlassSpice, wallGlassH, wallGlassHSpice, pillarIce, pulpit, bush, bushBurnt, bushBurning, floorFog, floorFogDark, floorSmoke, floorSmokeDark, doorOpen, doorOpenH, floorCorridor, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem, floorRed, floorBlue, floorGreen, floorBrown, floorArenaShade ]
++ map makeDark ldarkable
++ map makeDarkColor ldarkColorable
}
unknown, hardRock, bedrock, wall, wallSuspect, wallObscured, wallH, wallSuspectH, wallObscuredDefacedH, wallObscuredFrescoedH, pillar, pillarCache, lampPost, signboardUnread, signboardRead, tree, treeBurnt, treeBurning, rubble, rubbleSpice, doorTrapped, doorClosed, doorTrappedH, doorClosedH, stairsUp, stairsTaintedUp, stairsOutdoorUp, stairsGatedUp, stairsDown, stairsTaintedDown, stairsOutdoorDown, stairsGatedDown, escapeUp, escapeDown, escapeOutdoorDown, wallGlass, wallGlassSpice, wallGlassH, wallGlassHSpice, pillarIce, pulpit, bush, bushBurnt, bushBurning, floorFog, floorFogDark, floorSmoke, floorSmokeDark, doorOpen, doorOpenH, floorCorridor, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem, floorRed, floorBlue, floorGreen, floorBrown, floorArenaShade :: TileKind
ldarkable :: [TileKind]
ldarkable = [wall, wallSuspect, wallObscured, wallH, wallSuspectH, wallObscuredDefacedH, wallObscuredFrescoedH, doorTrapped, doorClosed, doorTrappedH, doorClosedH, wallGlass, wallGlassH, doorOpen, doorOpenH, floorCorridor]
ldarkColorable :: [TileKind]
ldarkColorable = [tree, bush, floorArena, floorNoise, floorDirt, floorDirtSpice, floorActor, floorActorItem]
-- Symbols to be used (the Nethack visual tradition imposes inconsistency):
-- LOS noLOS
-- Walk .|-# :;
-- noWalk %^-| -| O&<>+
--
-- can be opened ^&+
-- can be closed |-
-- some noWalk can be changed without opening, regardless of symbol
-- not used yet:
-- ~ (water, acid, ect.)
-- : (curtain, etc., not flowing, but solid and static)
-- `' (not visible enough, would need font modification)
-- Note that for AI hints and UI comfort, most multiple-use @Embed@ tiles
-- should have a variant, which after first use transforms into a different
-- colour tile without @ChangeTo@ and similar (which then AI no longer touches).
-- If a tile is supposed to be repeatedly activated by AI (e.g., cache),
-- it should keep @ChangeTo@ for the whole time.
-- * Main tiles, in other games modified and some removed
-- ** Not walkable
-- *** Not clear
unknown = TileKind -- needs to have index 0 and alter 1
{ tsymbol = ' '
, tname = "unknown space"
, tfreq = [("unknown space", 1)]
, tcolor = defFG
, tcolor2 = defFG
, talter = 1
, tfeature = [Dark, Indistinct]
}
hardRock = TileKind
{ tsymbol = ' '
, tname = "impenetrable bedrock"
, tfreq = [("basic outer fence", 1), ("noise fence", 1)]
, tcolor = defFG
, tcolor2 = defFG
, talter = maxBound -- impenetrable
, tfeature = [Dark, Indistinct]
}
bedrock = TileKind
{ tsymbol = ' '
, tname = "bedrock"
, tfreq = [("fillerWall", 1), ("legendLit", 100), ("legendDark", 100)]
, tcolor = defFG
, tcolor2 = defFG
, talter = 100
, tfeature = [Dark, Indistinct]
-- Bedrock being dark is bad for AI (forces it to backtrack to explore
-- bedrock at corridor turns) and induces human micromanagement
-- if there can be corridors joined diagonally (humans have to check
-- with the xhair if the dark space is bedrock or unexplored).
-- Lit bedrock would be even worse for humans, because it's harder
-- to guess which tiles are unknown and which can be explored bedrock.
-- The setup of Allure is ideal, with lit bedrock that is easily
-- distinguished from an unknown tile. However, LH follows the NetHack,
-- not the Angband, visual tradition, so we can't improve the situation,
-- unless we turn to subtle shades of black or non-ASCII glyphs,
-- but that is yet different aesthetics.
}
wall = TileKind
{ tsymbol = '|'
, tname = "granite wall"
, tfreq = [("legendLit", 100), ("rectWindowsOver_!_Lit", 80)]
, tcolor = BrWhite
, tcolor2 = defFG
, talter = 100
, tfeature = [BuildAs "suspect vertical wall Lit", Indistinct]
}
wallSuspect = TileKind -- only on client
{ tsymbol = '|'
, tname = "suspect uneven wall"
, tfreq = [("suspect vertical wall Lit", 1)]
, tcolor = BrWhite
, tcolor2 = defFG
, talter = 2
, tfeature = [ RevealAs "trapped vertical door Lit"
, ObscureAs "obscured vertical wall Lit"
, Indistinct
]
}
wallObscured = TileKind
{ tsymbol = '|'
, tname = "scratched wall"
, tfreq = [("obscured vertical wall Lit", 1)]
, tcolor = BrWhite
, tcolor2 = defFG
, talter = 5
, tfeature = [ Embed "scratch on wall"
, HideAs "suspect vertical wall Lit"
, Indistinct
]
}
wallH = TileKind
{ tsymbol = '-'
, tname = "sandstone wall"
, tfreq = [("legendLit", 100), ("rectWindowsOver_=_Lit", 80)]
, tcolor = BrWhite
, tcolor2 = defFG
, talter = 100
, tfeature = [ BuildAs "suspect horizontal wall Lit"
, Indistinct
]
}
wallSuspectH = TileKind -- only on client
{ tsymbol = '-'
, tname = "suspect painted wall"
, tfreq = [("suspect horizontal wall Lit", 1)]
, tcolor = BrWhite
, tcolor2 = defFG
, talter = 2
, tfeature = [ RevealAs "trapped horizontal door Lit"
, ObscureAs "obscured horizontal wall Lit"
, Indistinct
]
}
wallObscuredDefacedH = TileKind
{ tsymbol = '-'
, tname = "defaced wall"
, tfreq = [("obscured horizontal wall Lit", 90)]
, tcolor = BrWhite
, tcolor2 = defFG
, talter = 5
, tfeature = [ Embed "obscene pictograms"
, HideAs "suspect horizontal wall Lit"
, Indistinct
]
}
wallObscuredFrescoedH = TileKind
{ tsymbol = '-'
, tname = "frescoed wall"
, tfreq = [("obscured horizontal wall Lit", 10)]
, tcolor = BrWhite
, tcolor2 = defFG
, talter = 5
, tfeature = [ Embed "subtle fresco"
, HideAs "suspect horizontal wall Lit"
, Indistinct
] -- a bit beneficial, but AI would loop if allowed to trigger
}
pillar = TileKind
{ tsymbol = 'O'
, tname = "rock"
, tfreq = [ ("cachable", 70), ("stair terminal", 100)
, ("legendLit", 100), ("legendDark", 100)
, ("noiseSet", 70), ("battleSet", 250), ("brawlSetLit", 50)
, ("shootoutSetLit", 10), ("zooSet", 10) ]
, tcolor = BrCyan -- not BrWhite, to tell from heroes
, tcolor2 = Cyan
, talter = 100
, tfeature = [Indistinct]
}
pillarCache = TileKind
{ tsymbol = 'O'
, tname = "cache"
, tfreq = [("cachable", 30), ("stair terminal", 1)]
, tcolor = BrBlue
, tcolor2 = Blue
, talter = 5
, tfeature = [ Embed "terrain cache", Embed "terrain cache trap"
, ChangeTo "cachable", ConsideredByAI, Indistinct ]
-- Not explorable, but prominently placed, so hard to miss.
-- Very beneficial, so AI eager to trigger.
}
lampPost = TileKind
{ tsymbol = 'O'
, tname = "lamp post"
, tfreq = [("lampPostOver_O", 1)]
, tcolor = BrYellow
, tcolor2 = Brown
, talter = 100
, tfeature = []
}
signboardUnread = TileKind -- client only, indicates never used by this faction
{ tsymbol = 'O'
, tname = "signboard"
, tfreq = [("signboard unread", 1)]
, tcolor = BrCyan
, tcolor2 = Cyan
, talter = 5
, tfeature = [ ConsideredByAI -- changes after use, so safe for AI
, RevealAs "signboard" -- to display as hidden
, Indistinct
]
}
signboardRead = TileKind
{ tsymbol = 'O'
, tname = "signboard"
, tfreq = [("signboard", 1), ("zooSet", 2)]
, tcolor = BrCyan
, tcolor2 = Cyan
, talter = 5
, tfeature = [Embed "signboard", HideAs "signboard unread", Indistinct]
}
tree = TileKind
{ tsymbol = 'O'
, tname = "tree"
, tfreq = [ ("brawlSetLit", 140), ("shootoutSetLit", 10)
, ("escapeSetLit", 30), ("treeShadeOver_O_Lit", 1) ]
, tcolor = BrGreen
, tcolor2 = Green
, talter = 50
, tfeature = []
}
treeBurnt = tree
{ tname = "burnt tree"
, tfreq = [("ambushSet", 3), ("zooSet", 3), ("tree with fire", 30)]
, tcolor = BrBlack
, tcolor2 = BrBlack
, tfeature = Dark : tfeature tree
}
treeBurning = tree
{ tname = "burning tree"
, tfreq = [("ambushSet", 30), ("zooSet", 30), ("tree with fire", 70)]
, tcolor = BrRed
, tcolor2 = Red
, talter = 5
, tfeature = Embed "big fire" : ChangeTo "tree with fire" : tfeature tree
-- dousing off the tree will have more sense when it periodically
-- explodes, hitting and lighting up the team and so betraying it
}
rubble = TileKind
{ tsymbol = '&'
, tname = "rubble"
, tfreq = [] -- [("floorCorridorLit", 1)]
-- disabled while it's all or nothing per cave and per room;
-- we need a new mechanism, Spice is not enough, because
-- we don't want multicolor trailLit corridors
-- ("rubbleOrNot", 70)
-- until we can sync change of tile and activation, it always takes 1 turn
, tcolor = BrYellow
, tcolor2 = Brown
, talter = 5
, tfeature = [OpenTo "rubbleOrNot", Embed "rubble", Indistinct]
}
rubbleSpice = TileKind
{ tsymbol = '&'
, tname = "rubble"
, tfreq = [ ("smokeClumpOver_f_Lit", 1), ("emptySet", 1), ("noiseSet", 5)
, ("zooSet", 100), ("ambushSet", 20) ]
, tcolor = BrYellow
, tcolor2 = Brown
, talter = 5
, tfeature = [Spice, OpenTo "rubbleSpiceOrNot", Embed "rubble", Indistinct]
-- It's not explorable, due to not being walkable nor clear and due
-- to being a door (@OpenTo@), which is kind of OK, because getting
-- the item is risky and, e.g., AI doesn't attempt it.
-- Also, AI doesn't go out of its way to clear the way for heroes.
}
doorTrapped = TileKind
{ tsymbol = '+'
, tname = "trapped door"
, tfreq = [("trapped vertical door Lit", 1)]
, tcolor = BrRed
, tcolor2 = Red
, talter = 2
, tfeature = [ Embed "doorway trap"
, OpenTo "open vertical door Lit"
, HideAs "suspect vertical wall Lit"
, Indistinct
]
}
doorClosed = TileKind
{ tsymbol = '+'
, tname = "closed door"
, tfreq = [("closed vertical door Lit", 1)]
, tcolor = Brown
, tcolor2 = BrBlack
, talter = 2
, tfeature = [OpenTo "open vertical door Lit", Indistinct] -- never hidden
}
doorTrappedH = TileKind
{ tsymbol = '+'
, tname = "trapped door"
, tfreq = [("trapped horizontal door Lit", 1)]
, tcolor = BrRed
, tcolor2 = Red
, talter = 2
, tfeature = [ Embed "doorway trap"
, OpenTo "open horizontal door Lit"
, HideAs "suspect horizontal wall Lit"
, Indistinct
]
}
doorClosedH = TileKind
{ tsymbol = '+'
, tname = "closed door"
, tfreq = [("closed horizontal door Lit", 1)]
, tcolor = Brown
, tcolor2 = BrBlack
, talter = 2
, tfeature = [OpenTo "open horizontal door Lit", Indistinct] -- never hidden
}
stairsUp = TileKind
{ tsymbol = '<'
, tname = "staircase up"
, tfreq = [("staircase up", 9), ("ordinary staircase up", 1)]
, tcolor = BrWhite
, tcolor2 = defFG
, talter = talterForStairs
, tfeature = [Embed "staircase up", ConsideredByAI]
}
stairsTaintedUp = TileKind
{ tsymbol = '<'
, tname = "tainted staircase up"
, tfreq = [("staircase up", 1)]
, tcolor = BrRed
, tcolor2 = Red
, talter = talterForStairs
, tfeature = [ Embed "staircase up", Embed "staircase trap up"
, ConsideredByAI, ChangeTo "ordinary staircase up" ]
-- AI uses despite the trap; exploration more important
}
stairsOutdoorUp = stairsUp
{ tname = "signpost pointing backward"
, tfreq = [("staircase outdoor up", 1)]
}
stairsGatedUp = stairsUp
{ tname = "gated staircase up"
, tfreq = [("gated staircase up", 1)]
, talter = talterForStairs + 1 -- animals and bosses can't use
}
stairsDown = TileKind
{ tsymbol = '>'
, tname = "staircase down"
, tfreq = [("staircase down", 9), ("ordinary staircase down", 1)]
, tcolor = BrWhite
, tcolor2 = defFG
, talter = talterForStairs
, tfeature = [Embed "staircase down", ConsideredByAI]
}
stairsTaintedDown = TileKind
{ tsymbol = '>'
, tname = "tainted staircase down"
, tfreq = [("staircase down", 1)]
, tcolor = BrRed
, tcolor2 = Red
, talter = talterForStairs
, tfeature = [ Embed "staircase down", Embed "staircase trap down"
, ConsideredByAI, ChangeTo "ordinary staircase down" ]
}
stairsOutdoorDown = stairsDown
{ tname = "signpost pointing forward"
, tfreq = [("staircase outdoor down", 1)]
}
stairsGatedDown = stairsDown
{ tname = "gated staircase down"
, tfreq = [("gated staircase down", 1)]
, talter = talterForStairs + 1 -- animals and bosses can't use
}
escapeUp = TileKind
{ tsymbol = '<'
, tname = "exit hatch up"
, tfreq = [("legendLit", 1), ("legendDark", 1)]
, tcolor = BrYellow
, tcolor2 = BrYellow
, talter = 0 -- anybody can escape (or guard escape)
, tfeature = [Embed "escape", ConsideredByAI]
}
escapeDown = TileKind
{ tsymbol = '>'
, tname = "exit trapdoor down"
, tfreq = [("legendLit", 1), ("legendDark", 1)]
, tcolor = BrYellow
, tcolor2 = BrYellow
, talter = 0 -- anybody can escape (or guard escape)
, tfeature = [Embed "escape", ConsideredByAI]
}
escapeOutdoorDown = escapeDown
{ tname = "exit back to town"
, tfreq = [("escape outdoor down", 1)]
}
-- *** Clear
wallGlass = TileKind
{ tsymbol = '|'
, tname = "polished crystal wall"
, tfreq = [("glasshouseOver_!_Lit", 1)]
, tcolor = BrBlue
, tcolor2 = Blue
, talter = 10
, tfeature = [BuildAs "suspect vertical wall Lit", Clear]
}
wallGlassSpice = wallGlass
{ tfreq = [("rectWindowsOver_!_Lit", 20)]
, tfeature = Spice : tfeature wallGlass
}
wallGlassH = TileKind
{ tsymbol = '-'
, tname = "polished crystal wall"
, tfreq = [("glasshouseOver_=_Lit", 1)]
, tcolor = BrBlue
, tcolor2 = Blue
, talter = 10
, tfeature = [BuildAs "suspect horizontal wall Lit", Clear]
}
wallGlassHSpice = wallGlassH
{ tfreq = [("rectWindowsOver_=_Lit", 20)]
, tfeature = Spice : tfeature wallGlassH
}
pillarIce = TileKind
{ tsymbol = '^'
, tname = "ice"
, tfreq = [("noiseSet", 30)]
, tcolor = BrBlue
, tcolor2 = Blue
, talter = 5
, tfeature = [Clear, Embed "frost", OpenTo "damp stone floor"]
-- Is door, due to @OpenTo@, so is not explorable, but it's OK, because
-- it doesn't generate items nor clues. This saves on the need to
-- get each ice pillar into sight range when exploring level.
}
pulpit = TileKind
{ tsymbol = '%'
, tname = "pulpit"
, tfreq = [("pulpit", 1), ("zooSet", 2)]
, tcolor = BrYellow
, tcolor2 = Brown
, talter = 5
, tfeature = [Clear, Embed "pulpit", Indistinct]
-- mixed blessing, so AI ignores, saved for player fun
}
bush = TileKind
{ tsymbol = '%'
, tname = "bush"
, tfreq = [ ("bush Lit", 1), ("shootoutSetLit", 30), ("escapeSetLit", 30)
, ("bushClumpOver_f_Lit", 1) ]
, tcolor = BrGreen
, tcolor2 = Green
, talter = 10
, tfeature = [Clear]
}
bushBurnt = bush
{ tname = "burnt bush"
, tfreq = [ ("battleSet", 30), ("ambushSet", 4), ("zooSet", 30)
, ("bush with fire", 70) ]
, tcolor = BrBlack
, tcolor2 = BrBlack
, tfeature = Dark : tfeature bush
}
bushBurning = bush
{ tname = "burning bush"
, tfreq = [("ambushSet", 40), ("zooSet", 300), ("bush with fire", 30)]
, tcolor = BrRed
, tcolor2 = Red
, talter = 5
, tfeature = Embed "small fire" : ChangeTo "bush with fire" : tfeature bush
}
-- ** Walkable
-- *** Not clear
floorFog = TileKind
{ tsymbol = ';'
, tname = "faint fog"
, tfreq = [ ("lit fog", 1), ("emptySet", 5), ("shootoutSetLit", 20)
, ("fogClumpOver_f_Lit", 60) ]
-- lit fog is OK for shootout, because LOS is mutual, as opposed
-- to dark fog, and so camper has little advantage, especially
-- on big maps, where he doesn't know on which side of fog patch to hide
, tcolor = BrCyan
, tcolor2 = Cyan
, talter = 0
, tfeature = [Walkable, NoItem, Indistinct, OftenActor]
}
floorFogDark = floorFog
{ tname = "thick fog"
, tfreq = [("noiseSet", 10), ("escapeSetDark", 60)]
, tfeature = Dark : tfeature floorFog
}
floorSmoke = TileKind
{ tsymbol = ';'
, tname = "billowing smoke"
, tfreq = [ ("lit smoke", 1)
, ("ambushSet", 30), ("zooSet", 30), ("battleSet", 5)
, ("labTrailLit", 1), ("stair terminal", 2)
, ("smokeClumpOver_f_Lit", 1) ]
, tcolor = Brown
, tcolor2 = BrBlack
, talter = 0
, tfeature = [Walkable, NoItem, Indistinct] -- not dark, embers
}
floorSmokeDark = floorSmoke
{ tname = "lingering smoke"
, tfreq = [("ambushSet", 30)]
, tfeature = Dark : tfeature floorSmoke
}
-- *** Clear
doorOpen = TileKind
{ tsymbol = '-'
, tname = "open door"
, tfreq = [("open vertical door Lit", 1)]
, tcolor = Brown
, tcolor2 = BrBlack
, talter = 4
, tfeature = [ Walkable, Clear, NoItem, NoActor
, CloseTo "closed vertical door Lit"
]
}
doorOpenH = TileKind
{ tsymbol = '|'
, tname = "open door"
, tfreq = [("open horizontal door Lit", 1)]
, tcolor = Brown
, tcolor2 = BrBlack
, talter = 4
, tfeature = [ Walkable, Clear, NoItem, NoActor
, CloseTo "closed horizontal door Lit"
]
}
floorCorridor = TileKind
{ tsymbol = '#'
, tname = "corridor"
, tfreq = [("floorCorridorLit", 99), ("rubbleOrNot", 30)]
, tcolor = BrWhite
, tcolor2 = defFG
, talter = 0
, tfeature = [Walkable, Clear, Indistinct]
}
floorArena = floorCorridor
{ tsymbol = floorSymbol
, tname = "stone floor"
, tfreq = [ ("floorArenaLit", 1), ("rubbleSpiceOrNot", 30)
, ("arenaSetLit", 1), ("emptySet", 97), ("zooSet", 1000) ]
}
floorNoise = floorArena
{ tname = "damp stone floor"
, tfreq = [("noiseSet", 60), ("damp stone floor", 1)]
}
floorDirt = floorArena
{ tname = "dirt"
, tfreq = [ ("battleSet", 1000), ("brawlSetLit", 1000)
, ("shootoutSetLit", 1000), ("escapeSetLit", 1000)
, ("ambushSet", 1000) ]
}
floorDirtSpice = floorDirt
{ tfreq = [ ("treeShadeOver_s_Lit", 1), ("fogClumpOver_f_Lit", 40)
, ("smokeClumpOver_f_Lit", 1), ("bushClumpOver_f_Lit", 1) ]
, tfeature = Spice : tfeature floorDirt
}
floorActor = floorArena
{ tfreq = [("floorActorLit", 1)] -- lit even in dark cave, so no items
, tfeature = OftenActor : tfeature floorArena
}
floorActorItem = floorActor
{ tfreq = [("legendLit", 100)]
, tfeature = OftenItem : tfeature floorActor
}
floorRed = floorCorridor
{ tsymbol = floorSymbol
, tname = "brick pavement"
, tfreq = [("trailLit", 30)]
, tcolor = BrRed
, tcolor2 = Red
, tfeature = Trail : tfeature floorCorridor -- no Indistinct
}
floorBlue = floorRed
{ tname = "cobblestone path"
, tfreq = [("trailLit", 100)]
, tcolor = BrBlue
, tcolor2 = Blue
}
floorGreen = floorRed
{ tname = "mossy stone path"
, tfreq = [("trailLit", 100)]
, tcolor = BrGreen
, tcolor2 = Green
}
floorBrown = floorRed
{ tname = "rotting mahogany deck"
, tfreq = [("trailLit", 10)]
, tcolor = BrMagenta
, tcolor2 = Magenta
}
floorArenaShade = floorActor
{ tname = "shaded ground"
, tfreq = [("shaded ground", 1), ("treeShadeOver_s_Lit", 2)]
, tcolor2 = BrBlack
, tfeature = Dark : NoItem : tfeature floorActor
}
makeDark :: TileKind -> TileKind
makeDark k = let darkText :: GroupName TileKind -> GroupName TileKind
darkText t = maybe t (toGroupName . (<> "Dark"))
$ T.stripSuffix "Lit" $ tshow t
darkFrequency = map (first darkText) $ tfreq k
darkFeat (OpenTo t) = Just $ OpenTo $ darkText t
darkFeat (CloseTo t) = Just $ CloseTo $ darkText t
darkFeat (ChangeTo t) = Just $ ChangeTo $ darkText t
darkFeat (HideAs t) = Just $ HideAs $ darkText t
darkFeat (BuildAs t) = Just $ BuildAs $ darkText t
darkFeat (RevealAs t) = Just $ RevealAs $ darkText t
darkFeat (ObscureAs t) = Just $ ObscureAs $ darkText t
darkFeat OftenItem = Nothing -- items not common in the dark
darkFeat feat = Just feat
in k { tfreq = darkFrequency
, tfeature = Dark : mapMaybe darkFeat (tfeature k)
}
makeDarkColor :: TileKind -> TileKind
makeDarkColor k = (makeDark k) {tcolor2 = BrBlack}