module Game.LambdaHack.Content.ModeKind
( Caves, Roster(..), Player(..), ModeKind(..), Tactic(..)
, LeaderMode(..), AutoLeader(..)
, validateSingleModeKind, validateAllModeKind
) where
import Data.Binary
import Data.Hashable (Hashable)
import qualified Data.IntMap.Strict as IM
import Data.Text (Text)
import qualified Data.Text as T
import GHC.Generics (Generic)
import qualified NLP.Miniutter.English as MU ()
import Game.LambdaHack.Common.Ability
import Game.LambdaHack.Common.Misc
import Game.LambdaHack.Common.Msg
data ModeKind = ModeKind
{ msymbol :: !Char
, mname :: !Text
, mfreq :: !Freqs
, mroster :: !Roster
, mcaves :: !Caves
, mdesc :: !Text
}
deriving Show
type Caves = IM.IntMap (GroupName, Maybe Bool)
data Roster = Roster
{ rosterList :: ![Player]
, rosterEnemy :: ![(Text, Text)]
, rosterAlly :: ![(Text, Text)]
}
deriving (Show, Eq)
data Player = Player
{ fname :: !Text
, fgroup :: !GroupName
, fskillsOther :: !Skills
, fcanEscape :: !Bool
, fneverEmpty :: !Bool
, fhasNumbers :: !Bool
, fhasGender :: !Bool
, ftactic :: !Tactic
, fentryLevel :: !Int
, finitialActors :: !Int
, fleaderMode :: !LeaderMode
, fhasUI :: !Bool
}
deriving (Show, Eq, Generic)
instance Binary Player
data Tactic =
TBlock
| TFollow
| TExplore
| TRoam
| TPatrol
deriving (Eq, Ord, Enum, Bounded, Generic)
instance Show Tactic where
show TBlock = "block and wait"
show TFollow = "follow leader's target or position"
show TExplore = "explore unknown, chase targets"
show TRoam = "roam freely, chase targets"
show TPatrol = "find and patrol an area (TODO)"
instance Binary Tactic
instance Hashable Tactic
data LeaderMode =
LeaderNull
| LeaderAI AutoLeader
| LeaderUI AutoLeader
deriving (Show, Eq, Generic)
instance Binary LeaderMode
data AutoLeader = AutoLeader
{ autoDungeon :: !Bool
, autoLevel :: !Bool
}
deriving (Show, Eq, Generic)
instance Binary AutoLeader
validateSingleModeKind :: ModeKind -> [Text]
validateSingleModeKind ModeKind{..} =
[ "mname longer than 20" | T.length mname > 20 ]
++ validateSingleRoster mcaves mroster
validateSingleRoster :: Caves -> Roster -> [Text]
validateSingleRoster caves Roster{..} =
[ "no player keeps the dungeon alive" | all (not . fneverEmpty) rosterList ]
++ concatMap (validateSinglePlayer caves) rosterList
++ let checkPl field pl =
[ pl <+> "is not a player name in" <+> field
| all ((/= pl) . fname) rosterList ]
checkDipl field (pl1, pl2) =
[ "self-diplomacy in" <+> field | pl1 == pl2 ]
++ checkPl field pl1
++ checkPl field pl2
in concatMap (checkDipl "rosterEnemy") rosterEnemy
++ concatMap (checkDipl "rosterAlly") rosterAlly
validateSinglePlayer :: Caves -> Player -> [Text]
validateSinglePlayer caves Player{..} =
[ "fname empty:" <+> fname | T.null fname ]
++ [ "first word of fname longer than 15:" <+> fname
| T.length (head $ T.words fname) > 15 ]
++ [ "no UI client, but UI leader:" <+> fname
| not fhasUI && case fleaderMode of
LeaderUI _ -> True
_ -> False ]
++ [ "fentryLevel not among caves:" <+> fname
| fentryLevel `notElem` IM.keys caves ]
validateAllModeKind :: [ModeKind] -> [Text]
validateAllModeKind _ = []