    -- | The type of game rules and assorted game data.
    module Game.LambdaHack.Content.RuleKind
      ( RuleContent(..), emptyRuleContent, makeData
    #ifdef EXPOSE_INTERNAL
        -- * Internal operations
      , emptyRuleContentRaw, validateSingle
    #endif
      ) where

    import Prelude ()

    import Game.LambdaHack.Core.Prelude

    import qualified Data.Ini as Ini
    import qualified Data.Ini.Types as Ini
    import           Data.Version

    import Game.LambdaHack.Content.ItemKind
      (ItemSymbolsUsedInEngine, emptyItemSymbolsUsedInEngine)
    import Game.LambdaHack.Definition.Defs

    -- | The type of game rules and assorted game data.
    data RuleContent = RuleContent
      { RuleContent -> String
    rtitle            :: String    -- ^ title of the game (not lib)
      , RuleContent -> X
    rWidthMax         :: X         -- ^ maximum level width
      , RuleContent -> X
    rHeightMax        :: Y         -- ^ maximum level height
      , RuleContent -> Version
    rexeVersion       :: Version   -- ^ version of the game
      , RuleContent -> String
    rcfgUIName        :: FilePath  -- ^ name of the UI config file
      , RuleContent -> (Text, Config)
    rcfgUIDefault     :: (Text, Ini.Config)
                                       -- ^ the default UI settings config file
      , RuleContent -> X
    rwriteSaveClips   :: Int       -- ^ game saved that often (not on browser)
      , RuleContent -> X
    rleadLevelClips   :: Int       -- ^ server switches leader level that often
      , RuleContent -> String
    rscoresFileName   :: FilePath  -- ^ name of the scores file
      , RuleContent -> X
    rnearby           :: Int       -- ^ what is a close distance between actors
      , RuleContent -> [Text]
    rstairWordCarried :: [Text]    -- ^ words that can't be dropped from stair
                                       --   name as it goes through levels
      , RuleContent -> ItemSymbolsUsedInEngine
    ritemSymbols      :: ItemSymbolsUsedInEngine
                                       -- ^ item symbols treated specially in engine
      }

    emptyRuleContentRaw :: RuleContent
    emptyRuleContentRaw :: RuleContent
    emptyRuleContentRaw = RuleContent
      { rtitle :: String
    rtitle = String
    ""
      , rWidthMax :: X
    rWidthMax = X
    5
      , rHeightMax :: X
    rHeightMax = X
    2
      , rexeVersion :: Version
    rexeVersion = [X] -> Version
    makeVersion []
      , rcfgUIName :: String
    rcfgUIName = String
    ""
      , rcfgUIDefault :: (Text, Config)
    rcfgUIDefault = (Text
    "", Config
    Ini.emptyConfig)
      , rwriteSaveClips :: X
    rwriteSaveClips = X
    0
      , rleadLevelClips :: X
    rleadLevelClips = X
    0
      , rscoresFileName :: String
    rscoresFileName = String
    ""
      , rnearby :: X
    rnearby = X
    0
      , rstairWordCarried :: [Text]
    rstairWordCarried = []
      , ritemSymbols :: ItemSymbolsUsedInEngine
    ritemSymbols = ItemSymbolsUsedInEngine
    emptyItemSymbolsUsedInEngine
      }

    emptyRuleContent :: RuleContent
    emptyRuleContent :: RuleContent
    emptyRuleContent = Bool -> RuleContent -> RuleContent
    forall a. (?callStack::CallStack) => Bool -> a -> a
    assert ([Text] -> Bool
    forall a. [a] -> Bool
    null ([Text] -> Bool) -> [Text] -> Bool
    forall a b. (a -> b) -> a -> b
    $ RuleContent -> [Text]
    validateSingle RuleContent
    emptyRuleContentRaw)
                              RuleContent
    emptyRuleContentRaw

    -- | Catch invalid rule kind definitions.
    validateSingle :: RuleContent -> [Text]
    validateSingle :: RuleContent -> [Text]
    validateSingle RuleContent{X
    String
    [Text]
    (Text, Config)
    Version
    ItemSymbolsUsedInEngine
    rtitle :: RuleContent -> String
    rWidthMax :: RuleContent -> X
    rHeightMax :: RuleContent -> X
    rexeVersion :: RuleContent -> Version
    rcfgUIName :: RuleContent -> String
    rcfgUIDefault :: RuleContent -> (Text, Config)
    rwriteSaveClips :: RuleContent -> X
    rleadLevelClips :: RuleContent -> X
    rscoresFileName :: RuleContent -> String
    rnearby :: RuleContent -> X
    rstairWordCarried :: RuleContent -> [Text]
    ritemSymbols :: RuleContent -> ItemSymbolsUsedInEngine
    rtitle :: String
    rWidthMax :: X
    rHeightMax :: X
    rexeVersion :: Version
    rcfgUIName :: String
    rcfgUIDefault :: (Text, Config)
    rwriteSaveClips :: X
    rleadLevelClips :: X
    rscoresFileName :: String
    rnearby :: X
    rstairWordCarried :: [Text]
    ritemSymbols :: ItemSymbolsUsedInEngine
    ..} =
      [ Text
    "rWidthMax < 5" | X
    rWidthMax X -> X -> Bool
    forall a. Ord a => a -> a -> Bool
    < X
    5 ]  -- indented (4 prop spaces) text
      [Text] -> [Text] -> [Text]
    forall a. [a] -> [a] -> [a]
    ++ [ Text
    "rHeightMax < 2" | X
    rHeightMax X -> X -> Bool
    forall a. Ord a => a -> a -> Bool
    < X
    2 ]  -- or 4 tiles of sentinel wall

    makeData :: RuleContent -> RuleContent
    makeData :: RuleContent -> RuleContent
    makeData RuleContent
    rc =
      let singleOffenders :: [Text]
    singleOffenders = RuleContent -> [Text]
    validateSingle RuleContent
    rc
      in Bool -> RuleContent -> RuleContent
    forall a. (?callStack::CallStack) => Bool -> a -> a
    assert ([Text] -> Bool
    forall a. [a] -> Bool
    null [Text]
    singleOffenders
                 Bool -> (String, [Text]) -> Bool
    forall v. Show v => Bool -> v -> Bool
    `blame` String
    "Rule Content not valid"
                 String -> [Text] -> (String, [Text])
    forall v. String -> v -> (String, v)
    `swith` [Text]
    singleOffenders)
         RuleContent
    rc