{-# LANGUAGE DeriveGeneric, GeneralizedNewtypeDeriving #-} -- | Actors perceiving other actors and the dungeon level. -- -- Visibility works according to KISS. Everything that player sees is real. -- There are no unmarked hidden tiles and only solid tiles can be marked, -- so there are no invisible walls and to pass through an illusory wall, -- you have use a turn bumping into it first. Only tiles marked with Suspect -- can turn out to be another tile. (So, if all tiles are marked with -- Suspect, the player knows nothing for sure, but this should be avoided, -- because searching becomes too time-consuming.) -- Each actor sees adjacent tiles, even when blind, so adjacent tiles are -- known, so the actor can decide accurately whether to pass thorugh -- or alter, etc. -- -- Items are always real and visible. Actors are real, but can be invisible. -- Invisible actors in walls can't be hit, but are hinted at when altering -- the tile, so the player can flee or block. Invisible actors in open -- space can be hit. module Game.LambdaHack.Common.Perception ( Perception(Perception), PerceptionVisible(PerceptionVisible) , totalVisible, smellVisible , nullPer, addPer, diffPer , FactionPers, Pers ) where import Data.Binary import qualified Data.EnumMap.Strict as EM import qualified Data.EnumSet as ES import GHC.Generics (Generic) import Game.LambdaHack.Common.Faction import Game.LambdaHack.Common.Level import Game.LambdaHack.Common.Point newtype PerceptionVisible = PerceptionVisible {pvisible :: ES.EnumSet Point} deriving (Show, Eq, Binary) -- TOOD: if really needed, optimize by representing as a set of intervals -- or a set of bitmaps, like the internal representation of IntSet. -- | The type representing the perception of a faction on a level. data Perception = Perception { ptotal :: !PerceptionVisible -- ^ sum over all actors , psmell :: !PerceptionVisible -- ^ sum over actors that can smell } deriving (Show, Eq, Generic) instance Binary Perception -- | Perception of a single faction, indexed by level identifier. type FactionPers = EM.EnumMap LevelId Perception -- | Perception indexed by faction identifier. -- This can't be added to @FactionDict@, because clients can't see it. type Pers = EM.EnumMap FactionId FactionPers -- | The set of tiles visible by at least one hero. totalVisible :: Perception -> ES.EnumSet Point totalVisible = pvisible . ptotal -- | The set of tiles smelled by at least one hero. smellVisible :: Perception -> ES.EnumSet Point smellVisible = pvisible . psmell nullPer :: Perception -> Bool nullPer per = ES.null (totalVisible per) && ES.null (smellVisible per) addPer :: Perception -> Perception -> Perception addPer per1 per2 = Perception { ptotal = PerceptionVisible $ totalVisible per1 `ES.union` totalVisible per2 , psmell = PerceptionVisible $ smellVisible per1 `ES.union` smellVisible per2 } diffPer :: Perception -> Perception -> Perception diffPer per1 per2 = Perception { ptotal = PerceptionVisible $ totalVisible per1 ES.\\ totalVisible per2 , psmell = PerceptionVisible $ smellVisible per1 ES.\\ smellVisible per2 }