1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
-- | The type of definitions of screen layout and features.
module Game.LambdaHack.Client.UI.Content.Screen
( ScreenContent(..), emptyScreenContent, makeData
#ifdef EXPOSE_INTERNAL
-- * Internal operations
, emptyScreenContentRaw, validateSingle
#endif
) where
import Prelude ()
import Game.LambdaHack.Core.Prelude
import qualified Data.ByteString as BS
import qualified Data.EnumMap.Strict as EM
import qualified Data.Text as T
import Game.LambdaHack.Content.ItemKind (ItemKind)
import qualified Game.LambdaHack.Content.RuleKind as RK
import Game.LambdaHack.Definition.Defs
-- | Screen layout and features definition.
--
-- Warning: this type is not abstract, but its values should not be
-- created ad hoc, even for unit tests, but should be constructed
-- with @makeData@, which includes validation,
--
-- The @emptyScreenContent@ is one such valid by construction value
-- of this type. It's suitable for bootstrapping and for testing.
data ScreenContent = ScreenContent
{ rwidth :: X -- ^ screen width
, rheight :: Y -- ^ screen height
, rwebAddress :: String -- ^ an extra blurb line for the main menu
, rintroScreen :: ([String], [[String]])
-- ^ the intro screen (first help screen) text
-- and the rest of the manual
, rapplyVerbMap :: EM.EnumMap (ContentSymbol ItemKind) T.Text
-- ^ verbs to use for apply actions
, rFontFiles :: [(FilePath, BS.ByteString)]
-- ^ embedded game-supplied font files
}
emptyScreenContentRaw :: ScreenContent
emptyScreenContentRaw = ScreenContent { rwidth = 5
, rheight = 5
, rwebAddress = ""
, rintroScreen = ([], [])
, rapplyVerbMap = EM.empty
, rFontFiles = []
}
emptyScreenContent :: ScreenContent
emptyScreenContent =
assert (null $ validateSingle RK.emptyRuleContent emptyScreenContentRaw)
emptyScreenContentRaw
-- | Catch invalid rule kind definitions.
validateSingle :: RK.RuleContent -> ScreenContent -> [Text]
validateSingle corule ScreenContent{..} =
(let tsGt80 = filter ((> 80) . T.length) $ map T.pack [rwebAddress]
in case tsGt80 of
[] -> []
tGt80 : _ -> ["rwebAddress's length is over 80:" <> tGt80])
++ (let tsGt41 = filter ((> 41) . T.length) $ map T.pack $ fst rintroScreen
in case tsGt41 of
[] -> []
tGt41 : _ -> ["intro screen has a line with length over 41:" <> tGt41])
++ (let tsGt80 = filter ((> 80) . T.length) $ map T.pack $ intercalate [""]
$ snd rintroScreen
in case tsGt80 of
[] -> []
tGt80 : _ -> ["manual has a line with length over 80:" <> tGt80])
-- The following reflect the only current UI implementation.
++ [ "rwidth /= RK.rWidthMax" | rwidth /= RK.rWidthMax corule ]
++ [ "rheight /= RK.rHeightMax + 3" | rheight /= RK.rHeightMax corule + 3]
makeData :: RK.RuleContent -> ScreenContent -> ScreenContent
makeData corule sc =
let singleOffenders = validateSingle corule sc
in assert (null singleOffenders
`blame` "Screen Content not valid"
`swith` singleOffenders)
sc
|