-- | General content types and operations.
module Game.LambdaHack.Common.Kind
  ( ContentData, COps(..)
  , emptyCOps
  , ItemSpeedup
  , emptyItemSpeedup, getKindMean, speedupItem
  , TileSpeedup(..), Tab(..)
  , emptyTileSpeedup, emptyTab
  , okind, omemberGroup, oisSingletonGroup, ouniqGroup, opick
  , ofoldlWithKey', ofoldlGroup', omapVector, oimapVector
  , olength, linearInterpolation
  ) where

import Prelude ()

import Game.LambdaHack.Core.Prelude

import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as U
import           Data.Word (Word8)

import qualified Game.LambdaHack.Common.ItemAspect as IA
import           Game.LambdaHack.Content.CaveKind
import           Game.LambdaHack.Content.ItemKind (ItemKind)
import qualified Game.LambdaHack.Content.ItemKind as IK
import           Game.LambdaHack.Content.ModeKind
import           Game.LambdaHack.Content.PlaceKind
import           Game.LambdaHack.Content.RuleKind
import           Game.LambdaHack.Content.TileKind (TileKind)
import           Game.LambdaHack.Definition.ContentData
import           Game.LambdaHack.Definition.Defs

-- | Operations for all content types, gathered together.
data COps = COps
  { COps -> ContentData CaveKind
cocave        :: ContentData CaveKind   -- server only
  , COps -> ContentData ItemKind
coitem        :: ContentData ItemKind
  , COps -> ContentData ModeKind
comode        :: ContentData ModeKind   -- server only
  , COps -> ContentData PlaceKind
coplace       :: ContentData PlaceKind  -- server only, so far
  , COps -> RuleContent
corule        :: RuleContent
  , COps -> ContentData TileKind
cotile        :: ContentData TileKind
  , COps -> ItemSpeedup
coItemSpeedup :: ItemSpeedup
  , COps -> TileSpeedup
coTileSpeedup :: TileSpeedup
  }

instance Show COps where
  show :: COps -> String
show _ = "game content"

instance Eq COps where
  == :: COps -> COps -> Bool
(==) _ _ = Bool
True

emptyCOps :: COps
emptyCOps :: COps
emptyCOps = $WCOps :: ContentData CaveKind
-> ContentData ItemKind
-> ContentData ModeKind
-> ContentData PlaceKind
-> RuleContent
-> ContentData TileKind
-> ItemSpeedup
-> TileSpeedup
-> COps
COps
  { cocave :: ContentData CaveKind
cocave  = ContentData CaveKind
forall a. ContentData a
emptyContentData
  , coitem :: ContentData ItemKind
coitem  = ContentData ItemKind
forall a. ContentData a
emptyContentData
  , comode :: ContentData ModeKind
comode  = ContentData ModeKind
forall a. ContentData a
emptyContentData
  , coplace :: ContentData PlaceKind
coplace = ContentData PlaceKind
forall a. ContentData a
emptyContentData
  , corule :: RuleContent
corule  = RuleContent
emptyRuleContent
  , cotile :: ContentData TileKind
cotile  = ContentData TileKind
forall a. ContentData a
emptyContentData
  , coItemSpeedup :: ItemSpeedup
coItemSpeedup = ItemSpeedup
emptyItemSpeedup
  , coTileSpeedup :: TileSpeedup
coTileSpeedup = TileSpeedup
emptyTileSpeedup
  }

-- | Map from an item kind identifier to the mean aspect value for the kind.
newtype ItemSpeedup = ItemSpeedup (V.Vector IA.KindMean)

emptyItemSpeedup :: ItemSpeedup
emptyItemSpeedup :: ItemSpeedup
emptyItemSpeedup = Vector KindMean -> ItemSpeedup
ItemSpeedup Vector KindMean
forall a. Vector a
V.empty

getKindMean :: ContentId IK.ItemKind -> ItemSpeedup -> IA.KindMean
getKindMean :: ContentId ItemKind -> ItemSpeedup -> KindMean
getKindMean kindId :: ContentId ItemKind
kindId (ItemSpeedup is :: Vector KindMean
is) = Vector KindMean
is Vector KindMean -> Int -> KindMean
forall a. Vector a -> Int -> a
V.! ContentId ItemKind -> Int
forall k. ContentId k -> Int
contentIdIndex ContentId ItemKind
kindId

speedupItem :: ContentData IK.ItemKind -> ItemSpeedup
speedupItem :: ContentData ItemKind -> ItemSpeedup
speedupItem coitem :: ContentData ItemKind
coitem =
  let f :: ItemKind -> KindMean
f !ItemKind
kind =
        let kmMean :: AspectRecord
kmMean = ItemKind -> AspectRecord
IA.meanAspect ItemKind
kind
            kmConst :: Bool
kmConst = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [Aspect] -> Bool
IA.aspectsRandom (ItemKind -> [Aspect]
IK.iaspects ItemKind
kind)
        in $WKindMean :: Bool -> AspectRecord -> KindMean
IA.KindMean{..}
  in Vector KindMean -> ItemSpeedup
ItemSpeedup (Vector KindMean -> ItemSpeedup) -> Vector KindMean -> ItemSpeedup
forall a b. (a -> b) -> a -> b
$ ContentData ItemKind -> (ItemKind -> KindMean) -> Vector KindMean
forall a b. ContentData a -> (a -> b) -> Vector b
omapVector ContentData ItemKind
coitem ItemKind -> KindMean
f

-- | A lot of tabulated maps from tile kind identifier to a property
-- of the tile kind.
data TileSpeedup = TileSpeedup
  { TileSpeedup -> Tab Bool
isClearTab          :: Tab Bool
  , TileSpeedup -> Tab Bool
isLitTab            :: Tab Bool
  , TileSpeedup -> Tab Bool
isHideoutTab        :: Tab Bool
  , TileSpeedup -> Tab Bool
isWalkableTab       :: Tab Bool
  , TileSpeedup -> Tab Bool
isDoorTab           :: Tab Bool
  , TileSpeedup -> Tab Bool
isOpenableTab       :: Tab Bool
  , TileSpeedup -> Tab Bool
isClosableTab       :: Tab Bool
  , TileSpeedup -> Tab Bool
isChangableTab      :: Tab Bool
  , TileSpeedup -> Tab Bool
isModifiableWithTab :: Tab Bool
  , TileSpeedup -> Tab Bool
isSuspectTab        :: Tab Bool
  , TileSpeedup -> Tab Bool
isHideAsTab         :: Tab Bool
  , TileSpeedup -> Tab Bool
consideredByAITab   :: Tab Bool
  , TileSpeedup -> Tab Bool
isVeryOftenItemTab  :: Tab Bool
  , TileSpeedup -> Tab Bool
isCommonItemTab     :: Tab Bool
  , TileSpeedup -> Tab Bool
isOftenActorTab     :: Tab Bool
  , TileSpeedup -> Tab Bool
isNoItemTab         :: Tab Bool
  , TileSpeedup -> Tab Bool
isNoActorTab        :: Tab Bool
  , TileSpeedup -> Tab Bool
isEasyOpenTab       :: Tab Bool
  , TileSpeedup -> Tab Bool
isEmbedTab          :: Tab Bool
  , TileSpeedup -> Tab Bool
isAquaticTab        :: Tab Bool
  , TileSpeedup -> Tab Word8
alterMinSkillTab    :: Tab Word8
  , TileSpeedup -> Tab Word8
alterMinWalkTab     :: Tab Word8
  }

-- Vectors of booleans can be slower than arrays, because they are not packed,
-- but with growing cache sizes they may as well turn out faster at some point.
-- The advantage of vectors are exposed internals, in particular unsafe
-- indexing. Also, in JS, bool arrays are obviously not packed.
-- An option: https://github.com/Bodigrim/bitvec
-- | A map morally indexed by @ContentId TileKind@.
newtype Tab a = Tab (U.Vector a)

emptyTileSpeedup :: TileSpeedup
emptyTileSpeedup :: TileSpeedup
emptyTileSpeedup = Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Bool
-> Tab Word8
-> Tab Word8
-> TileSpeedup
TileSpeedup Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab
                               Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab
                               Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab
                               Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab Tab Bool
forall a. Unbox a => Tab a
emptyTab
                               Tab Word8
forall a. Unbox a => Tab a
emptyTab Tab Word8
forall a. Unbox a => Tab a
emptyTab

emptyTab :: U.Unbox a => Tab a
emptyTab :: Tab a
emptyTab = Vector a -> Tab a
forall a. Vector a -> Tab a
Tab (Vector a -> Tab a) -> Vector a -> Tab a
forall a b. (a -> b) -> a -> b
$! Vector a
forall a. Unbox a => Vector a
U.empty