-- | The type of kinds of game modes.
module Game.LambdaHack.Content.ModeKind
  ( Caves, Players(..), Player(..), ModeKind(..), validateModeKind
  ) where

import Data.Binary
import qualified Data.IntMap.Strict as IM
import Data.Text (Text)
import qualified NLP.Miniutter.English as MU ()

import Game.LambdaHack.Common.Misc (Freqs)

-- | Game mode specification.
data ModeKind = ModeKind
  { msymbol  :: !Char     -- ^ a symbol (matches the keypress, if any)
  , mname    :: !Text     -- ^ short description
  , mfreq    :: !Freqs    -- ^ frequency within groups
  , mplayers :: !Players  -- ^ players taking part in the game
  , mcaves   :: !Caves    -- ^ arena of the game
  , mdesc    :: !Text     -- ^ description
  }
  deriving Show

-- | Requested cave groups for particular levels. The default is
-- the "dng" group, which means a random choice from all caves
-- that can randomly appear. The second component of the pair
-- is the @Escape@ feature on the level. @True@ means it's represented
-- by @<@, @False@, by @>@.
type Caves = IM.IntMap (Text, Maybe Bool)

-- | The specification of players for the game mode.
data Players = Players
  { playersList  :: ![Player]        -- ^ players, both human and computer
  , playersEnemy :: ![(Text, Text)]  -- ^ the initial enmity matrix
  , playersAlly  :: ![(Text, Text)]  -- ^ the initial aliance matrix
  }
  deriving (Show, Eq)

-- | Properties of a particular player.
data Player = Player
  { playerName    :: !Text     -- ^ name of the player
  , playerFaction :: !Text     -- ^ name of faction(s) the player can control
  , playerIsSpawn :: !Bool     -- ^ whether the player is a spawn (score, AI)
  , playerIsHero  :: !Bool     -- ^ whether the player is a hero (score, AI, UI)
  , playerEntry   :: !Int      -- ^ level where the initial members start
  , playerInitial :: !Int      -- ^ number of initial members
  , playerLeader  :: !Bool     -- ^ leaderless factions can't be controlled
                               --   by a human or a user-supplied AI client
  , playerAI      :: !Bool     -- ^ is the faction under AI control?
  , playerUI      :: !Bool     -- ^ does the faction have a UI client
                               --   (for control or passive observation)
  }
  deriving (Show, Eq)

-- TODO: assert every Player's playerName's first word's length <= 15
-- TODO: assert if no UI, both Ai are on and there are some non-spawners;
-- assert that playersEnemy and playersAlly mention only factions in play.
-- | No specific possible problems for the content of this kind, so far,
-- so the validation function always returns the empty list of offending kinds.
validateModeKind :: [ModeKind] -> [ModeKind]
validateModeKind _ = []

instance Binary Player where
  put Player{..} = do
    put playerName
    put playerFaction
    put playerIsSpawn
    put playerIsHero
    put playerEntry
    put playerInitial
    put playerLeader
    put playerAI
    put playerUI
  get = do
    playerName <- get
    playerFaction <- get
    playerIsSpawn <- get
    playerIsHero <- get
    playerEntry <- get
    playerInitial <- get
    playerLeader <- get
    playerAI <- get
    playerUI <- get
    return $! Player{..}