-- | The type of tile kinds. Every terrain tile in the game is
-- an instantiated tile kind.
module Game.LambdaHack.Content.TileKind
  ( pattern S_UNKNOWN_SPACE, pattern S_UNKNOWN_OUTER_FENCE, pattern S_BASIC_OUTER_FENCE, pattern AQUATIC
  , TileKind(..), ProjectileTriggers(..), Feature(..)
  , makeData
  , isUknownSpace, unknownId
  , isSuspectKind, isOpenableKind, isClosableKind
  , talterForStairs, floorSymbol
#ifdef EXPOSE_INTERNAL
    -- * Internal operations
  , validateSingle, validateAll
  , validateDups, mandatoryGroups, mandatoryGroupsSingleton
#endif
  ) where

import Prelude ()

import Game.LambdaHack.Core.Prelude

import Data.Word (Word8)

import Game.LambdaHack.Content.ItemKind (ItemKind)
import Game.LambdaHack.Definition.Color
import Game.LambdaHack.Definition.ContentData
import Game.LambdaHack.Definition.Defs
import Game.LambdaHack.Definition.DefsInternal

-- | The type of kinds of terrain tiles. See @Tile.hs@ for explanation
-- of the absence of a corresponding type @Tile@ that would hold
-- particular concrete tiles in the dungeon.
-- Note that tile names (and any other content names) should not be plural
-- (that would lead to "a stairs"), so "road with cobblestones" is fine,
-- but "granite cobblestones" is wrong.
--
-- Tile kind for unknown space has the minimal @ContentId@ index.
-- The @talter@ for unknown space is @1@ and no other tile kind has that value.
data TileKind = TileKind
  { TileKind -> Char
tsymbol  :: Char         -- ^ map symbol
  , TileKind -> Text
tname    :: Text         -- ^ short description
  , TileKind -> Freqs TileKind
tfreq    :: Freqs TileKind  -- ^ frequency within groups
  , TileKind -> Color
tcolor   :: Color        -- ^ map color
  , TileKind -> Color
tcolor2  :: Color        -- ^ map color when not in FOV
  , TileKind -> Word8
talter   :: Word8        -- ^ minimal skill needed to activate embeds
                             --   and, in case of big actors not standing on
                             --   the tile, to alter the tile in any way
  , TileKind -> [Feature]
tfeature :: [Feature]    -- ^ properties; order matters
  }
  deriving Int -> TileKind -> ShowS
[TileKind] -> ShowS
TileKind -> String
(Int -> TileKind -> ShowS)
-> (TileKind -> String) -> ([TileKind] -> ShowS) -> Show TileKind
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TileKind] -> ShowS
$cshowList :: [TileKind] -> ShowS
show :: TileKind -> String
$cshow :: TileKind -> String
showsPrec :: Int -> TileKind -> ShowS
$cshowsPrec :: Int -> TileKind -> ShowS
Show  -- No Eq and Ord to make extending logically sound

-- | All possible terrain tile features.
data Feature =
    Embed (GroupName ItemKind)
      -- ^ initially an item of this group is embedded;
      --   we assume the item has effects and is supposed to be triggered
  | OpenTo (GroupName TileKind)
      -- ^ goes from a closed to closed or open tile when altered
  | CloseTo (GroupName TileKind)
      -- ^ goes from an open to open or closed tile when altered
  | ChangeTo (GroupName TileKind)
      -- ^ alters tile, but does not change walkability
  | OpenWith ProjectileTriggers
             [(Int, GroupName ItemKind)] (GroupName TileKind)
      -- ^ alters tile, as before, using up all listed items from the ground
      --   and equipment; the list never empty; for simplicity, such tiles
      --   are never taken into account when pathfinding
  | CloseWith ProjectileTriggers
              [(Int, GroupName ItemKind)] (GroupName TileKind)
  | ChangeWith ProjectileTriggers
               [(Int, GroupName ItemKind)] (GroupName TileKind)
  | HideAs (GroupName TileKind)
      -- ^ when hidden, looks as the unique tile of the group
  | BuildAs (GroupName TileKind)
      -- ^ when generating, may be transformed to the unique tile of the group
  | RevealAs (GroupName TileKind)
      -- ^ when generating in opening, can be revealed to belong to the group
  | ObscureAs (GroupName TileKind)
      -- ^ when generating in solid wall, can be revealed to belong to the group
  | Walkable             -- ^ actors can walk through
  | Clear                -- ^ actors can see through
  | Dark                 -- ^ is not lit with an ambient light
  | OftenItem            -- ^ initial items often generated there
  | VeryOftenItem        -- ^ initial items very often generated there
  | OftenActor           -- ^ initial actors often generated there
  | NoItem               -- ^ no items ever generated there
  | NoActor              -- ^ no actors ever generated there
  | ConsideredByAI       -- ^ even if otherwise uninteresting, taken into
                         --   account for triggering by AI
  | Trail                -- ^ used for visible trails throughout the level
  | Spice                -- ^ in place normal legend and in override,
                         --   don't roll a tile kind only once per place,
                         --   but roll for each position; one non-spicy
                         --   (according to frequencies of non-spicy) and
                         --   at most one spicy (according to their frequencies)
                         --   is rolled per place and then, once for each
                         --   position, one of the two is semi-randomly chosen
                         --   (according to their individual frequencies only)
  deriving (Int -> Feature -> ShowS
[Feature] -> ShowS
Feature -> String
(Int -> Feature -> ShowS)
-> (Feature -> String) -> ([Feature] -> ShowS) -> Show Feature
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Feature] -> ShowS
$cshowList :: [Feature] -> ShowS
show :: Feature -> String
$cshow :: Feature -> String
showsPrec :: Int -> Feature -> ShowS
$cshowsPrec :: Int -> Feature -> ShowS
Show, Feature -> Feature -> Bool
(Feature -> Feature -> Bool)
-> (Feature -> Feature -> Bool) -> Eq Feature
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Feature -> Feature -> Bool
$c/= :: Feature -> Feature -> Bool
== :: Feature -> Feature -> Bool
$c== :: Feature -> Feature -> Bool
Eq)

-- | Marks whether projectiles are permitted to trigger the tile transformation
-- action.
data ProjectileTriggers = ProjYes | ProjNo
  deriving (Int -> ProjectileTriggers -> ShowS
[ProjectileTriggers] -> ShowS
ProjectileTriggers -> String
(Int -> ProjectileTriggers -> ShowS)
-> (ProjectileTriggers -> String)
-> ([ProjectileTriggers] -> ShowS)
-> Show ProjectileTriggers
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ProjectileTriggers] -> ShowS
$cshowList :: [ProjectileTriggers] -> ShowS
show :: ProjectileTriggers -> String
$cshow :: ProjectileTriggers -> String
showsPrec :: Int -> ProjectileTriggers -> ShowS
$cshowsPrec :: Int -> ProjectileTriggers -> ShowS
Show, ProjectileTriggers -> ProjectileTriggers -> Bool
(ProjectileTriggers -> ProjectileTriggers -> Bool)
-> (ProjectileTriggers -> ProjectileTriggers -> Bool)
-> Eq ProjectileTriggers
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ProjectileTriggers -> ProjectileTriggers -> Bool
$c/= :: ProjectileTriggers -> ProjectileTriggers -> Bool
== :: ProjectileTriggers -> ProjectileTriggers -> Bool
$c== :: ProjectileTriggers -> ProjectileTriggers -> Bool
Eq)

-- | Validate a single tile kind.
validateSingle :: TileKind -> [Text]
validateSingle :: TileKind -> [Text]
validateSingle t :: TileKind
t@TileKind{Char
Freqs TileKind
[Feature]
Word8
Text
Color
tfeature :: [Feature]
talter :: Word8
tcolor2 :: Color
tcolor :: Color
tfreq :: Freqs TileKind
tname :: Text
tsymbol :: Char
tfeature :: TileKind -> [Feature]
talter :: TileKind -> Word8
tcolor2 :: TileKind -> Color
tcolor :: TileKind -> Color
tfreq :: TileKind -> Freqs TileKind
tname :: TileKind -> Text
tsymbol :: TileKind -> Char
..} =
  [ Text
"suspect tile is walkable" | Feature
Walkable Feature -> [Feature] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Feature]
tfeature
                                 Bool -> Bool -> Bool
&& TileKind -> Bool
isSuspectKind TileKind
t ]
  [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [ Text
"openable tile is open" | Feature
Walkable Feature -> [Feature] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Feature]
tfeature
                                 Bool -> Bool -> Bool
&& TileKind -> Bool
isOpenableKind TileKind
t ]
  [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [ Text
"closable tile is closed" | Feature
Walkable Feature -> [Feature] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Feature]
tfeature
                                   Bool -> Bool -> Bool
&& TileKind -> Bool
isClosableKind TileKind
t ]
  [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [ Text
"walkable tile is considered for activating by AI"
     | Feature
Walkable Feature -> [Feature] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Feature]
tfeature
       Bool -> Bool -> Bool
&& Feature
ConsideredByAI Feature -> [Feature] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Feature]
tfeature ]
  [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [ Text
"trail tile not walkable" | Feature
Walkable Feature -> [Feature] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Feature]
tfeature
                                   Bool -> Bool -> Bool
&& Feature
Trail Feature -> [Feature] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Feature]
tfeature ]
  [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [ Text
"OftenItem and NoItem on a tile" | Feature
OftenItem Feature -> [Feature] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Feature]
tfeature
                                          Bool -> Bool -> Bool
&& Feature
NoItem Feature -> [Feature] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Feature]
tfeature ]
  [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [ Text
"OftenActor and NoActor on a tile" | Feature
OftenItem Feature -> [Feature] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Feature]
tfeature
                                            Bool -> Bool -> Bool
&& Feature
NoItem Feature -> [Feature] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Feature]
tfeature ]
  [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ (let f :: Feature -> Bool
          f :: Feature -> Bool
f OpenTo{} = Bool
True
          f CloseTo{} = Bool
True
          f ChangeTo{} = Bool
True
          f Feature
_ = Bool
False
          ts :: [Feature]
ts = (Feature -> Bool) -> [Feature] -> [Feature]
forall a. (a -> Bool) -> [a] -> [a]
filter Feature -> Bool
f [Feature]
tfeature
      in [ Text
"more than one OpenTo, CloseTo and ChangeTo specification"
         | [Feature] -> Int
forall a. [a] -> Int
length [Feature]
ts Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1 ])
  [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ (let f :: Feature -> Bool
          f :: Feature -> Bool
f HideAs{} = Bool
True
          f Feature
_ = Bool
False
          ts :: [Feature]
ts = (Feature -> Bool) -> [Feature] -> [Feature]
forall a. (a -> Bool) -> [a] -> [a]
filter Feature -> Bool
f [Feature]
tfeature
      in [Text
"more than one HideAs specification" | [Feature] -> Int
forall a. [a] -> Int
length [Feature]
ts Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1])
  [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ (let f :: Feature -> Bool
          f :: Feature -> Bool
f BuildAs{} = Bool
True
          f Feature
_ = Bool
False
          ts :: [Feature]
ts = (Feature -> Bool) -> [Feature] -> [Feature]
forall a. (a -> Bool) -> [a] -> [a]
filter Feature -> Bool
f [Feature]
tfeature
      in [Text
"more than one BuildAs specification" | [Feature] -> Int
forall a. [a] -> Int
length [Feature]
ts Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1])
  [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ (Feature -> [Text]) -> [Feature] -> [Text]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (TileKind -> Feature -> [Text]
validateDups TileKind
t)
       [ Feature
Walkable, Feature
Clear, Feature
Dark, Feature
OftenItem, Feature
OftenActor, Feature
NoItem, Feature
NoActor
       , Feature
ConsideredByAI, Feature
Trail, Feature
Spice ]

validateDups :: TileKind -> Feature -> [Text]
validateDups :: TileKind -> Feature -> [Text]
validateDups TileKind{Char
Freqs TileKind
[Feature]
Word8
Text
Color
tfeature :: [Feature]
talter :: Word8
tcolor2 :: Color
tcolor :: Color
tfreq :: Freqs TileKind
tname :: Text
tsymbol :: Char
tfeature :: TileKind -> [Feature]
talter :: TileKind -> Word8
tcolor2 :: TileKind -> Color
tcolor :: TileKind -> Color
tfreq :: TileKind -> Freqs TileKind
tname :: TileKind -> Text
tsymbol :: TileKind -> Char
..} Feature
feat =
  let ts :: [Feature]
ts = (Feature -> Bool) -> [Feature] -> [Feature]
forall a. (a -> Bool) -> [a] -> [a]
filter (Feature -> Feature -> Bool
forall a. Eq a => a -> a -> Bool
== Feature
feat) [Feature]
tfeature
  in [Text
"more than one" Text -> Text -> Text
<+> Feature -> Text
forall a. Show a => a -> Text
tshow Feature
feat Text -> Text -> Text
<+> Text
"specification" | [Feature] -> Int
forall a. [a] -> Int
length [Feature]
ts Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1]

-- | Validate all tile kinds.
--
-- We don't check it any more, but if tiles look the same on the map
-- (symbol and color), their substantial features should be the same, too,
-- unless there is a good reason they shouldn't. Otherwise the player has
-- to inspect manually all the tiles with this look to see if any is special.
-- This tends to be tedious. Note that tiles may freely differ wrt text blurb,
-- dungeon generation rules, AI preferences, etc., whithout causing the tedium.
validateAll :: [TileKind] -> ContentData TileKind -> [Text]
validateAll :: [TileKind] -> ContentData TileKind -> [Text]
validateAll [TileKind]
content ContentData TileKind
cotile =
  let f :: Feature -> Bool
      f :: Feature -> Bool
f HideAs{} = Bool
True
      f BuildAs{} = Bool
True
      f Feature
_ = Bool
False
      wrongGrooup :: TileKind -> GroupName TileKind -> Bool
wrongGrooup TileKind
k GroupName TileKind
grp = Bool -> Bool
not (ContentData TileKind -> GroupName TileKind -> Bool
forall a. ContentData a -> GroupName a -> Bool
oisSingletonGroup ContentData TileKind
cotile GroupName TileKind
grp)
                          Bool -> Bool -> Bool
|| Maybe Int -> Bool
forall a. Maybe a -> Bool
isJust (GroupName TileKind
grp GroupName TileKind -> Freqs TileKind -> Maybe Int
forall a b. Eq a => a -> [(a, b)] -> Maybe b
`lookup` TileKind -> Freqs TileKind
tfreq TileKind
k)
      wrongFooAsGroups :: [GroupName TileKind]
wrongFooAsGroups =
        [ GroupName TileKind
cgroup
        | TileKind
k <- [TileKind]
content
        , let (GroupName TileKind
cgroup, Bool
notSingleton) = case (Feature -> Bool) -> [Feature] -> Maybe Feature
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find Feature -> Bool
f (TileKind -> [Feature]
tfeature TileKind
k) of
                Just (HideAs GroupName TileKind
grp) | TileKind -> GroupName TileKind -> Bool
wrongGrooup TileKind
k GroupName TileKind
grp -> (GroupName TileKind
grp, Bool
True)
                Just (BuildAs GroupName TileKind
grp) | TileKind -> GroupName TileKind -> Bool
wrongGrooup TileKind
k GroupName TileKind
grp -> (GroupName TileKind
grp, Bool
True)
                Maybe Feature
_ -> (GroupName TileKind
forall a. HasCallStack => a
undefined, Bool
False)
        , Bool
notSingleton
        ]
  in [ Text
"HideAs or BuildAs groups not singletons or point to themselves:"
       Text -> Text -> Text
<+> [GroupName TileKind] -> Text
forall a. Show a => a -> Text
tshow [GroupName TileKind]
wrongFooAsGroups
     | Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [GroupName TileKind] -> Bool
forall a. [a] -> Bool
null [GroupName TileKind]
wrongFooAsGroups ]
     [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [ Text
"unknown tile (the first) should be the unknown one"
        | TileKind -> Word8
talter ([TileKind] -> TileKind
forall a. [a] -> a
head [TileKind]
content) Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
1
          Bool -> Bool -> Bool
|| TileKind -> Text
tname ([TileKind] -> TileKind
forall a. [a] -> a
head [TileKind]
content) Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Text
"unknown space" ]
     [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [ Text
"no tile other than the unknown (the first) should require skill 1"
        | (TileKind -> Bool) -> [TileKind] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\TileKind
tk -> TileKind -> Word8
talter TileKind
tk Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
1) ([TileKind] -> [TileKind]
forall a. [a] -> [a]
tail [TileKind]
content) ]

-- * Mandatory item groups

mandatoryGroupsSingleton :: [GroupName TileKind]
mandatoryGroupsSingleton :: [GroupName TileKind]
mandatoryGroupsSingleton =
       [GroupName TileKind
S_UNKNOWN_SPACE, GroupName TileKind
S_UNKNOWN_OUTER_FENCE, GroupName TileKind
S_BASIC_OUTER_FENCE]

pattern S_UNKNOWN_SPACE, S_UNKNOWN_OUTER_FENCE, S_BASIC_OUTER_FENCE :: GroupName TileKind

mandatoryGroups :: [GroupName TileKind]
mandatoryGroups :: [GroupName TileKind]
mandatoryGroups = []

pattern $bS_UNKNOWN_SPACE :: GroupName TileKind
$mS_UNKNOWN_SPACE :: forall r. GroupName TileKind -> (Void# -> r) -> (Void# -> r) -> r
S_UNKNOWN_SPACE = GroupName "unknown space"
pattern $bS_UNKNOWN_OUTER_FENCE :: GroupName TileKind
$mS_UNKNOWN_OUTER_FENCE :: forall r. GroupName TileKind -> (Void# -> r) -> (Void# -> r) -> r
S_UNKNOWN_OUTER_FENCE = GroupName "unknown outer fence"
pattern $bS_BASIC_OUTER_FENCE :: GroupName TileKind
$mS_BASIC_OUTER_FENCE :: forall r. GroupName TileKind -> (Void# -> r) -> (Void# -> r) -> r
S_BASIC_OUTER_FENCE = GroupName "basic outer fence"

-- * Optional item groups

pattern AQUATIC :: GroupName TileKind

pattern $bAQUATIC :: GroupName TileKind
$mAQUATIC :: forall r. GroupName TileKind -> (Void# -> r) -> (Void# -> r) -> r
AQUATIC = GroupName "aquatic"

isUknownSpace :: ContentId TileKind -> Bool
{-# INLINE isUknownSpace #-}
isUknownSpace :: ContentId TileKind -> Bool
isUknownSpace ContentId TileKind
tt = Word16 -> ContentId TileKind
forall c. Word16 -> ContentId c
toContentId Word16
0 ContentId TileKind -> ContentId TileKind -> Bool
forall a. Eq a => a -> a -> Bool
== ContentId TileKind
tt

unknownId :: ContentId TileKind
{-# INLINE unknownId #-}
unknownId :: ContentId TileKind
unknownId = Word16 -> ContentId TileKind
forall c. Word16 -> ContentId c
toContentId Word16
0

isSuspectKind :: TileKind -> Bool
isSuspectKind :: TileKind -> Bool
isSuspectKind TileKind
t =
  let getTo :: Feature -> Bool
getTo RevealAs{} = Bool
True
      getTo ObscureAs{} = Bool
True
      getTo Feature
_ = Bool
False
  in (Feature -> Bool) -> [Feature] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Feature -> Bool
getTo ([Feature] -> Bool) -> [Feature] -> Bool
forall a b. (a -> b) -> a -> b
$ TileKind -> [Feature]
tfeature TileKind
t

isOpenableKind :: TileKind -> Bool
isOpenableKind :: TileKind -> Bool
isOpenableKind TileKind
t =
  let getTo :: Feature -> Bool
getTo OpenTo{} = Bool
True
      getTo Feature
_ = Bool
False
  in (Feature -> Bool) -> [Feature] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Feature -> Bool
getTo ([Feature] -> Bool) -> [Feature] -> Bool
forall a b. (a -> b) -> a -> b
$ TileKind -> [Feature]
tfeature TileKind
t

isClosableKind :: TileKind -> Bool
isClosableKind :: TileKind -> Bool
isClosableKind TileKind
t =
  let getTo :: Feature -> Bool
getTo CloseTo{} = Bool
True
      getTo Feature
_ = Bool
False
  in (Feature -> Bool) -> [Feature] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Feature -> Bool
getTo ([Feature] -> Bool) -> [Feature] -> Bool
forall a b. (a -> b) -> a -> b
$ TileKind -> [Feature]
tfeature TileKind
t

talterForStairs :: Word8
talterForStairs :: Word8
talterForStairs = Word8
3

floorSymbol :: Char
floorSymbol :: Char
floorSymbol = Char
'·'  -- '\x00B7'

-- Alter skill schema:
-- 0  can be altered by everybody (escape)
-- 1  unknown only
-- 2  openable and suspect
-- 3  stairs
-- 4  closable
-- 5  changeable (e.g., caches)
-- 10  weak obstructions
-- 50  considerable obstructions
-- 100  walls
-- maxBound  impenetrable walls, etc., can never be altered

makeData :: [TileKind] -> [GroupName TileKind] -> [GroupName TileKind]
         -> ContentData TileKind
makeData :: [TileKind]
-> [GroupName TileKind]
-> [GroupName TileKind]
-> ContentData TileKind
makeData [TileKind]
content [GroupName TileKind]
groupNamesAtMostOne [GroupName TileKind]
groupNames =
  String
-> (TileKind -> Text)
-> (TileKind -> Freqs TileKind)
-> (TileKind -> [Text])
-> ([TileKind] -> ContentData TileKind -> [Text])
-> [TileKind]
-> [GroupName TileKind]
-> [GroupName TileKind]
-> ContentData TileKind
forall c.
Show c =>
String
-> (c -> Text)
-> (c -> Freqs c)
-> (c -> [Text])
-> ([c] -> ContentData c -> [Text])
-> [c]
-> [GroupName c]
-> [GroupName c]
-> ContentData c
makeContentData String
"TileKind" TileKind -> Text
tname TileKind -> Freqs TileKind
tfreq TileKind -> [Text]
validateSingle [TileKind] -> ContentData TileKind -> [Text]
validateAll [TileKind]
content
                  ([GroupName TileKind]
mandatoryGroupsSingleton [GroupName TileKind]
-> [GroupName TileKind] -> [GroupName TileKind]
forall a. [a] -> [a] -> [a]
++ [GroupName TileKind]
groupNamesAtMostOne)
                  ([GroupName TileKind]
mandatoryGroups [GroupName TileKind]
-> [GroupName TileKind] -> [GroupName TileKind]
forall a. [a] -> [a] -> [a]
++ [GroupName TileKind]
groupNames)