-- | The type of cave layout kinds.
module Game.LambdaHack.Content.CaveKind
  ( CaveKind(..), cvalidate
  ) where

import qualified Data.List as L
import Data.Text (Text)
import qualified Data.Text as T

import Game.LambdaHack.Common.Misc
import Game.LambdaHack.Common.PointXY
import Game.LambdaHack.Common.Random

-- | Parameters for the generation of dungeon levels.
data CaveKind = CaveKind
  { csymbol         :: !Char        -- ^ a symbol
  , cname           :: !Text        -- ^ short description
  , cfreq           :: !Freqs       -- ^ frequency within groups
  , cxsize          :: !X           -- ^ X size of the whole cave
  , cysize          :: !Y           -- ^ Y size of the whole cave
  , cgrid           :: !RollDiceXY  -- ^ the dimensions of the grid of places
  , cminPlaceSize   :: !RollDiceXY  -- ^ minimal size of places
  , cmaxPlaceSize   :: !RollDiceXY  -- ^ maximal size of places
  , cdarkChance     :: !RollDeep    -- ^ the chance a place is dark
  , cnightChance    :: !RollDeep    -- ^ the chance the cave is dark
  , cauxConnects    :: !Rational    -- ^ a proportion of extra connections
  , cmaxVoid        :: !Rational    -- ^ at most this proportion of rooms void
  , cminStairDist   :: !Int         -- ^ minimal distance between stairs
  , cdoorChance     :: !Chance      -- ^ the chance of a door in an opening
  , copenChance     :: !Chance      -- ^ if there's a door, is it open?
  , chidden         :: !Int         -- ^ if not open, hidden one in n times
  , citemNum        :: !RollDice    -- ^ the number of items in the cave
  , citemFreq       :: ![(Int, Text)]  -- ^ item groups to consider
  , cdefTile        :: !Text        -- ^ the default cave tile group name
  , cdarkCorTile    :: !Text        -- ^ the dark cave corridor tile group name
  , clitCorTile     :: !Text        -- ^ the dark cave corridor tile group name
  , cfillerTile     :: !Text        -- ^ the filler wall group name
  , cdarkLegendTile :: !Text        -- ^ the dark place plan legend ground name
  , clitLegendTile  :: !Text        -- ^ the lit place plan legend ground name
  }
  deriving Show  -- No Eq and Ord to make extending it logically sound, see #53

-- TODO: check many things, e.g., if all items and actors fit in the dungeon.
-- | Filter a list of kinds, passing through only the incorrect ones, if any.
--
-- Catch caves with not enough space for all the places. Check the size
-- of the cave descriptions to make sure they fit on screen.
cvalidate :: [CaveKind] -> [CaveKind]
cvalidate = L.filter (\ CaveKind{ cgrid
                                , cminPlaceSize
                                , cmaxPlaceSize
                                , ..
                                } ->
  let (maxGridX, maxGridY) = maxDiceXY cgrid
      (minMinSizeX, minMinSizeY) = minDiceXY cminPlaceSize
      (maxMinSizeX, maxMinSizeY) = maxDiceXY cminPlaceSize
      (minMaxSizeX, minMaxSizeY) = minDiceXY cmaxPlaceSize
      xborder = if maxGridX == 1 then 3 else 1
      yborder = if maxGridX == 1 then 3 else 1
  in T.length cname > 25
     || cxsize < 7
     || cysize < 7
     || minMinSizeX < 1
     || minMinSizeY < 1
     || minMaxSizeX < maxMinSizeX
     || minMaxSizeY < maxMinSizeY
     || maxGridX * (maxMinSizeX + xborder) >= cxsize
     || maxGridY * (maxMinSizeY + yborder) >= cysize)