-- | Representation and computation of visiblity of atomic commands
-- by clients.
--
-- See
-- <https://github.com/LambdaHack/LambdaHack/wiki/Client-server-architecture>.
module Game.LambdaHack.Atomic.PosAtomicRead
  ( PosAtomic(..), posUpdAtomic, posSfxAtomic
  , breakUpdAtomic, seenAtomicCli, seenAtomicSer
#ifdef EXPOSE_INTERNAL
    -- * Internal operations
  , posProjBody, singleAid, doubleAid, singleContainer
#endif
  ) where

import Prelude ()

import Game.LambdaHack.Core.Prelude

import qualified Data.EnumMap.Strict as EM
import qualified Data.EnumSet as ES

import Game.LambdaHack.Atomic.CmdAtomic
import Game.LambdaHack.Common.Actor
import Game.LambdaHack.Common.ActorState
import Game.LambdaHack.Common.Faction
import Game.LambdaHack.Common.MonadStateRead
import Game.LambdaHack.Common.Perception
import Game.LambdaHack.Common.Point
import Game.LambdaHack.Common.State
import Game.LambdaHack.Common.Types
import Game.LambdaHack.Definition.Defs

-- All functions here that take an atomic action are executed
-- in the state just before the action is executed.

-- | The type representing visibility of atomic commands to factions,
-- based on the position of the command, etc. Note that the server
-- sees and smells all positions. Also note that hearing is not covered
-- because it gives very restricted information, so hearing doesn't equal
-- seeing (and we assume smelling actors get lots of data from smells).
data PosAtomic =
    PosSight LevelId [Point]    -- ^ whomever sees all the positions, notices
  | PosFidAndSight [FactionId] LevelId [Point]
                                -- ^ observers and the faction notice
  | PosSmell LevelId [Point]    -- ^ whomever smells all the positions, notices
  | PosFid FactionId            -- ^ only the faction notices, server doesn't
  | PosFidAndSer (Maybe LevelId) FactionId
                                -- ^ faction and server notices
  | PosSer                      -- ^ only the server notices
  | PosAll                      -- ^ everybody notices
  | PosNone                     -- ^ never broadcasted, but sent manually
  deriving (Int -> PosAtomic -> ShowS
[PosAtomic] -> ShowS
PosAtomic -> String
(Int -> PosAtomic -> ShowS)
-> (PosAtomic -> String)
-> ([PosAtomic] -> ShowS)
-> Show PosAtomic
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PosAtomic] -> ShowS
$cshowList :: [PosAtomic] -> ShowS
show :: PosAtomic -> String
$cshow :: PosAtomic -> String
showsPrec :: Int -> PosAtomic -> ShowS
$cshowsPrec :: Int -> PosAtomic -> ShowS
Show, PosAtomic -> PosAtomic -> Bool
(PosAtomic -> PosAtomic -> Bool)
-> (PosAtomic -> PosAtomic -> Bool) -> Eq PosAtomic
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PosAtomic -> PosAtomic -> Bool
$c/= :: PosAtomic -> PosAtomic -> Bool
== :: PosAtomic -> PosAtomic -> Bool
$c== :: PosAtomic -> PosAtomic -> Bool
Eq)

-- | Produce the positions where the atomic update takes place or, more
-- generally, the conditions under which the update can be noticed by
-- a client.
--
-- The goal of this mechanics is to ensure that atomic commands involving
-- some positions visible by a client convey similar information as the client
-- would get by directly observing the changes
-- of the portion of server state limited to the visible positions.
-- Consequently, when the visible commands are later applied
-- to the client's state, the state stays consistent
-- --- in sync with the server state and correctly limited by visiblity.
-- There is some wiggle room both in what "in sync" and
-- "visible" means and how they propagate through time.
--
-- E.g., @UpdDisplaceActor@ in a black room between two enemy actors,
-- with only one actor carrying a 0-radius light would not be
-- distinguishable by looking at the state (or the screen) from @UpdMoveActor@
-- of the illuminated actor, hence such @UpdDisplaceActor@ should not be
-- observable, but @UpdMoveActor@ in similar cotext would be
-- (or the former should be perceived as the latter).
-- However, to simplify, we assign as strict visibility
-- requirements to @UpdMoveActor@ as to @UpdDisplaceActor@ and fall back
-- to @UpdSpotActor@ (which provides minimal information that does not
-- contradict state) if the visibility is lower.
posUpdAtomic :: MonadStateRead m => UpdAtomic -> m PosAtomic
posUpdAtomic :: UpdAtomic -> m PosAtomic
posUpdAtomic cmd :: UpdAtomic
cmd = case UpdAtomic
cmd of
  UpdCreateActor _ body :: Actor
body _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! Actor -> PosAtomic
posProjBody Actor
body
  UpdDestroyActor _ body :: Actor
body _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! Actor -> PosAtomic
posProjBody Actor
body
  UpdCreateItem _ _ _ c :: Container
c -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdDestroyItem _ _ _ c :: Container
c -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdSpotActor _ body :: Actor
body _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! Actor -> PosAtomic
posProjBody Actor
body
  UpdLoseActor _ body :: Actor
body _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! Actor -> PosAtomic
posProjBody Actor
body
  UpdSpotItem _ _ _ _ c :: Container
c -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdLoseItem _ _ _ _ c :: Container
c -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdSpotItemBag c :: Container
c _ _ -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdLoseItemBag c :: Container
c _ _ -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdMoveActor aid :: ActorId
aid fromP :: Point
fromP toP :: Point
toP -> do
    Actor
b <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
aid
    -- Non-projectile actors are never totally isolated from envirnoment;
    -- they hear, feel air movement, etc.
    PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! if Actor -> Bool
bproj Actor
b
              then LevelId -> [Point] -> PosAtomic
PosSight (Actor -> LevelId
blid Actor
b) [Point
fromP, Point
toP]
              else [FactionId] -> LevelId -> [Point] -> PosAtomic
PosFidAndSight [Actor -> FactionId
bfid Actor
b] (Actor -> LevelId
blid Actor
b) [Point
fromP, Point
toP]
  UpdWaitActor aid :: ActorId
aid _ _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
aid
  UpdDisplaceActor source :: ActorId
source target :: ActorId
target -> ActorId -> ActorId -> m PosAtomic
forall (m :: * -> *).
MonadStateRead m =>
ActorId -> ActorId -> m PosAtomic
doubleAid ActorId
source ActorId
target
  UpdMoveItem _ _ _ _ CSha ->
    String -> m PosAtomic
forall a. HasCallStack => String -> a
error (String -> m PosAtomic) -> String -> m PosAtomic
forall a b. (a -> b) -> a -> b
$ "" String -> UpdAtomic -> String
forall v. Show v => String -> v -> String
`showFailure` UpdAtomic
cmd  -- shared stash is private
  UpdMoveItem _ _ _ CSha _ -> String -> m PosAtomic
forall a. HasCallStack => String -> a
error (String -> m PosAtomic) -> String -> m PosAtomic
forall a b. (a -> b) -> a -> b
$ "" String -> UpdAtomic -> String
forall v. Show v => String -> v -> String
`showFailure` UpdAtomic
cmd
  UpdMoveItem _ _ aid :: ActorId
aid _ _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
aid
  UpdRefillHP aid :: ActorId
aid _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
aid
  UpdRefillCalm aid :: ActorId
aid _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
aid
  UpdTrajectory aid :: ActorId
aid _ _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
aid
  UpdQuitFaction{} -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosAll
  UpdLeadFaction fid :: FactionId
fid _ _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$ Maybe LevelId -> FactionId -> PosAtomic
PosFidAndSer Maybe LevelId
forall a. Maybe a
Nothing FactionId
fid
  UpdDiplFaction{} -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosAll
  UpdTacticFaction fid :: FactionId
fid _ _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! Maybe LevelId -> FactionId -> PosAtomic
PosFidAndSer Maybe LevelId
forall a. Maybe a
Nothing FactionId
fid
  UpdAutoFaction{} -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosAll
  UpdRecordKill aid :: ActorId
aid _ _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
aid
  UpdAlterTile lid :: LevelId
lid p :: Point
p _ _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSight LevelId
lid [Point
p]
  UpdAlterExplorable{} -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosAll
    -- Can't have @PosSight@, because we'd end up with many accessible
    -- unknown tiles, but the game reporting 'all seen'.
  UpdAlterGold{} -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosAll
  UpdSearchTile aid :: ActorId
aid p :: Point
p _ -> do
    Actor
b <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
aid
    PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! [FactionId] -> LevelId -> [Point] -> PosAtomic
PosFidAndSight [Actor -> FactionId
bfid Actor
b] (Actor -> LevelId
blid Actor
b) [Actor -> Point
bpos Actor
b, Point
p]
  UpdHideTile aid :: ActorId
aid p :: Point
p _ -> do
    Actor
b <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
aid
    PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! [FactionId] -> LevelId -> [Point] -> PosAtomic
PosFidAndSight [Actor -> FactionId
bfid Actor
b] (Actor -> LevelId
blid Actor
b) [Actor -> Point
bpos Actor
b, Point
p]
  UpdSpotTile lid :: LevelId
lid ts :: [(Point, ContentId TileKind)]
ts -> do
    let ps :: [Point]
ps = ((Point, ContentId TileKind) -> Point)
-> [(Point, ContentId TileKind)] -> [Point]
forall a b. (a -> b) -> [a] -> [b]
map (Point, ContentId TileKind) -> Point
forall a b. (a, b) -> a
fst [(Point, ContentId TileKind)]
ts
    PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSight LevelId
lid [Point]
ps
  UpdLoseTile lid :: LevelId
lid ts :: [(Point, ContentId TileKind)]
ts -> do
    let ps :: [Point]
ps = ((Point, ContentId TileKind) -> Point)
-> [(Point, ContentId TileKind)] -> [Point]
forall a b. (a -> b) -> [a] -> [b]
map (Point, ContentId TileKind) -> Point
forall a b. (a, b) -> a
fst [(Point, ContentId TileKind)]
ts
    PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSight LevelId
lid [Point]
ps
  UpdSpotEntry lid :: LevelId
lid ts :: [(Point, PlaceEntry)]
ts -> do
    let ps :: [Point]
ps = ((Point, PlaceEntry) -> Point) -> [(Point, PlaceEntry)] -> [Point]
forall a b. (a -> b) -> [a] -> [b]
map (Point, PlaceEntry) -> Point
forall a b. (a, b) -> a
fst [(Point, PlaceEntry)]
ts
    PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSight LevelId
lid [Point]
ps
  UpdLoseEntry lid :: LevelId
lid ts :: [(Point, PlaceEntry)]
ts -> do
    let ps :: [Point]
ps = ((Point, PlaceEntry) -> Point) -> [(Point, PlaceEntry)] -> [Point]
forall a b. (a -> b) -> [a] -> [b]
map (Point, PlaceEntry) -> Point
forall a b. (a, b) -> a
fst [(Point, PlaceEntry)]
ts
    PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSight LevelId
lid [Point]
ps
  UpdAlterSmell lid :: LevelId
lid p :: Point
p _ _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSmell LevelId
lid [Point
p]
  UpdSpotSmell lid :: LevelId
lid sms :: [(Point, Time)]
sms -> do
    let ps :: [Point]
ps = ((Point, Time) -> Point) -> [(Point, Time)] -> [Point]
forall a b. (a -> b) -> [a] -> [b]
map (Point, Time) -> Point
forall a b. (a, b) -> a
fst [(Point, Time)]
sms
    PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSmell LevelId
lid [Point]
ps
  UpdLoseSmell lid :: LevelId
lid sms :: [(Point, Time)]
sms -> do
    let ps :: [Point]
ps = ((Point, Time) -> Point) -> [(Point, Time)] -> [Point]
forall a b. (a -> b) -> [a] -> [b]
map (Point, Time) -> Point
forall a b. (a, b) -> a
fst [(Point, Time)]
sms
    PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSmell LevelId
lid [Point]
ps
  UpdTimeItem _ c :: Container
c _ _ -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdAgeGame _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosAll
  UpdUnAgeGame _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosAll
  UpdDiscover c :: Container
c _ _ _ -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdCover c :: Container
c _ _ _ -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdDiscoverKind c :: Container
c _ _ -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdCoverKind c :: Container
c _ _ -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdDiscoverAspect c :: Container
c _ _ -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdCoverAspect c :: Container
c _ _ -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer Container
c
  UpdDiscoverServer{} -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosSer
  UpdCoverServer{} -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosSer
  UpdPerception{} -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosNone
  UpdRestart fid :: FactionId
fid _ _ _ _ _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! FactionId -> PosAtomic
PosFid FactionId
fid
  UpdRestartServer _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosSer
  UpdResume _ _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosNone
  UpdResumeServer _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosSer
  UpdKillExit fid :: FactionId
fid -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! FactionId -> PosAtomic
PosFid FactionId
fid
  UpdWriteSave -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosAll
  UpdHearFid fid :: FactionId
fid _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! FactionId -> PosAtomic
PosFid FactionId
fid

-- | Produce the positions where the atomic special effect takes place.
posSfxAtomic :: MonadStateRead m => SfxAtomic -> m PosAtomic
posSfxAtomic :: SfxAtomic -> m PosAtomic
posSfxAtomic cmd :: SfxAtomic
cmd = case SfxAtomic
cmd of
  SfxStrike _ _ _ CSha -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosNone  -- shared stash is private
  SfxStrike _ target :: ActorId
target _ _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
target
  SfxRecoil _ _ _ CSha -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosNone  -- shared stash is private
  SfxRecoil _ target :: ActorId
target _ _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
target
  SfxSteal _ _ _ CSha -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosNone  -- shared stash is private
  SfxSteal _ target :: ActorId
target _ _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
target
  SfxRelease _ _ _ CSha -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosNone  -- shared stash is private
  SfxRelease _ target :: ActorId
target _ _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
target
  SfxProject aid :: ActorId
aid _ cstore :: CStore
cstore -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer (Container -> m PosAtomic) -> Container -> m PosAtomic
forall a b. (a -> b) -> a -> b
$ ActorId -> CStore -> Container
CActor ActorId
aid CStore
cstore
  SfxReceive aid :: ActorId
aid _ cstore :: CStore
cstore -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer (Container -> m PosAtomic) -> Container -> m PosAtomic
forall a b. (a -> b) -> a -> b
$ ActorId -> CStore -> Container
CActor ActorId
aid CStore
cstore
  SfxApply aid :: ActorId
aid _ cstore :: CStore
cstore -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer (Container -> m PosAtomic) -> Container -> m PosAtomic
forall a b. (a -> b) -> a -> b
$ ActorId -> CStore -> Container
CActor ActorId
aid CStore
cstore
  SfxCheck aid :: ActorId
aid _ cstore :: CStore
cstore -> Container -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => Container -> m PosAtomic
singleContainer (Container -> m PosAtomic) -> Container -> m PosAtomic
forall a b. (a -> b) -> a -> b
$ ActorId -> CStore -> Container
CActor ActorId
aid CStore
cstore
  SfxTrigger aid :: ActorId
aid p :: Point
p -> do
    Actor
body <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
aid
    if Actor -> Bool
bproj Actor
body
    then PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSight (Actor -> LevelId
blid Actor
body) [Actor -> Point
bpos Actor
body, Point
p]
    else PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! [FactionId] -> LevelId -> [Point] -> PosAtomic
PosFidAndSight [Actor -> FactionId
bfid Actor
body] (Actor -> LevelId
blid Actor
body) [Actor -> Point
bpos Actor
body, Point
p]
  SfxShun aid :: ActorId
aid p :: Point
p -> do
    Actor
body <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
aid
    if Actor -> Bool
bproj Actor
body
    then PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSight (Actor -> LevelId
blid Actor
body) [Actor -> Point
bpos Actor
body, Point
p]
    else PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! [FactionId] -> LevelId -> [Point] -> PosAtomic
PosFidAndSight [Actor -> FactionId
bfid Actor
body] (Actor -> LevelId
blid Actor
body) [Actor -> Point
bpos Actor
body, Point
p]
  SfxEffect _ aid :: ActorId
aid _ _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
aid  -- sometimes we don't see source, OK
  SfxMsgFid fid :: FactionId
fid _ -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! FactionId -> PosAtomic
PosFid FactionId
fid
  SfxRestart -> PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return PosAtomic
PosAll
  SfxCollideTile aid :: ActorId
aid _ -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
aid
  SfxTaunt _ aid :: ActorId
aid -> ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
aid

posProjBody :: Actor -> PosAtomic
posProjBody :: Actor -> PosAtomic
posProjBody body :: Actor
body =
  if Actor -> Bool
bproj Actor
body
  then LevelId -> [Point] -> PosAtomic
PosSight (Actor -> LevelId
blid Actor
body) [Actor -> Point
bpos Actor
body]
  else [FactionId] -> LevelId -> [Point] -> PosAtomic
PosFidAndSight [Actor -> FactionId
bfid Actor
body] (Actor -> LevelId
blid Actor
body) [Actor -> Point
bpos Actor
body]

singleAid :: MonadStateRead m => ActorId -> m PosAtomic
singleAid :: ActorId -> m PosAtomic
singleAid aid :: ActorId
aid = do
  Actor
body <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
aid
  PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! Actor -> PosAtomic
posProjBody Actor
body

doubleAid :: MonadStateRead m => ActorId -> ActorId -> m PosAtomic
doubleAid :: ActorId -> ActorId -> m PosAtomic
doubleAid source :: ActorId
source target :: ActorId
target = do
  Actor
sb <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
source
  Actor
tb <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
target
  -- No @PosFidAndSight@ instead of @PosSight@, because both positions
  -- need to be seen to have the enemy actor in client's state.
  PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! Bool -> PosAtomic -> PosAtomic
forall a. HasCallStack => Bool -> a -> a
assert (Actor -> LevelId
blid Actor
sb LevelId -> LevelId -> Bool
forall a. Eq a => a -> a -> Bool
== Actor -> LevelId
blid Actor
tb) (PosAtomic -> PosAtomic) -> PosAtomic -> PosAtomic
forall a b. (a -> b) -> a -> b
$ LevelId -> [Point] -> PosAtomic
PosSight (Actor -> LevelId
blid Actor
sb) [Actor -> Point
bpos Actor
sb, Actor -> Point
bpos Actor
tb]

singleContainer :: MonadStateRead m => Container -> m PosAtomic
singleContainer :: Container -> m PosAtomic
singleContainer (CFloor lid :: LevelId
lid p :: Point
p) = PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSight LevelId
lid [Point
p]
singleContainer (CEmbed lid :: LevelId
lid p :: Point
p) = PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! LevelId -> [Point] -> PosAtomic
PosSight LevelId
lid [Point
p]
singleContainer (CActor aid :: ActorId
aid CSha) = do  -- shared stash is private
  Actor
b <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
aid
  PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! Maybe LevelId -> FactionId -> PosAtomic
PosFidAndSer (LevelId -> Maybe LevelId
forall a. a -> Maybe a
Just (LevelId -> Maybe LevelId) -> LevelId -> Maybe LevelId
forall a b. (a -> b) -> a -> b
$ Actor -> LevelId
blid Actor
b) (Actor -> FactionId
bfid Actor
b)
singleContainer (CActor aid :: ActorId
aid _) = ActorId -> m PosAtomic
forall (m :: * -> *). MonadStateRead m => ActorId -> m PosAtomic
singleAid ActorId
aid
singleContainer (CTrunk fid :: FactionId
fid lid :: LevelId
lid p :: Point
p) =
  PosAtomic -> m PosAtomic
forall (m :: * -> *) a. Monad m => a -> m a
return (PosAtomic -> m PosAtomic) -> PosAtomic -> m PosAtomic
forall a b. (a -> b) -> a -> b
$! [FactionId] -> LevelId -> [Point] -> PosAtomic
PosFidAndSight [FactionId
fid] LevelId
lid [Point
p]

-- | Decompose an atomic action that is outside a client's visiblity.
-- The decomposed actions give less information that the original command,
-- but some of them may fall within the visibility range of the client.
-- The original action may give more information than even the total sum
-- of all actions it's broken into. E.g., @UpdMoveActor@
-- informs about the continued existence of the actor between
-- moves vs popping out of existence and then back in.
--
-- This is computed in server's @State@ from before performing the command.
breakUpdAtomic :: MonadStateRead m => UpdAtomic -> m [UpdAtomic]
breakUpdAtomic :: UpdAtomic -> m [UpdAtomic]
breakUpdAtomic cmd :: UpdAtomic
cmd = case UpdAtomic
cmd of
  UpdMoveActor aid :: ActorId
aid fromP :: Point
fromP toP :: Point
toP -> do
    -- We assume other factions don't see leaders and we know the actor's
    -- faction always sees the atomic command and no other commands
    -- may be inserted between the two below, so the leader doesn't
    -- need to be updated, even when aid is the leader.
    Actor
b <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
aid
    [(ItemId, Item)]
ais <- (State -> [(ItemId, Item)]) -> m [(ItemId, Item)]
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> [(ItemId, Item)]) -> m [(ItemId, Item)])
-> (State -> [(ItemId, Item)]) -> m [(ItemId, Item)]
forall a b. (a -> b) -> a -> b
$ Actor -> State -> [(ItemId, Item)]
getCarriedAssocsAndTrunk Actor
b
    [UpdAtomic] -> m [UpdAtomic]
forall (m :: * -> *) a. Monad m => a -> m a
return [ ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic
UpdLoseActor ActorId
aid Actor
b [(ItemId, Item)]
ais
           , ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic
UpdSpotActor ActorId
aid Actor
b {bpos :: Point
bpos = Point
toP, boldpos :: Maybe Point
boldpos = Point -> Maybe Point
forall a. a -> Maybe a
Just Point
fromP} [(ItemId, Item)]
ais ]
  UpdDisplaceActor source :: ActorId
source target :: ActorId
target -> do
    Actor
sb <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
source
    [(ItemId, Item)]
sais <- (State -> [(ItemId, Item)]) -> m [(ItemId, Item)]
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> [(ItemId, Item)]) -> m [(ItemId, Item)])
-> (State -> [(ItemId, Item)]) -> m [(ItemId, Item)]
forall a b. (a -> b) -> a -> b
$ Actor -> State -> [(ItemId, Item)]
getCarriedAssocsAndTrunk Actor
sb
    Actor
tb <- (State -> Actor) -> m Actor
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Actor) -> m Actor) -> (State -> Actor) -> m Actor
forall a b. (a -> b) -> a -> b
$ ActorId -> State -> Actor
getActorBody ActorId
target
    [(ItemId, Item)]
tais <- (State -> [(ItemId, Item)]) -> m [(ItemId, Item)]
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> [(ItemId, Item)]) -> m [(ItemId, Item)])
-> (State -> [(ItemId, Item)]) -> m [(ItemId, Item)]
forall a b. (a -> b) -> a -> b
$ Actor -> State -> [(ItemId, Item)]
getCarriedAssocsAndTrunk Actor
tb
    -- The order ensures the invariant that no two big actors occupy the same
    -- position is maintained. The actions about leadership are required
    -- to keep faction data (identify of the leader) consistent with actor
    -- data (the actor that is the leader exists). Here, for speed
    -- and simplicity we violate the property that in a faction
    -- that has leaders, if any eligible actor is alive,
    -- the leader is set, because for a moment there may be no leader,
    -- even though other actors of the faction may exist.
    Maybe ActorId
msleader <- (State -> Maybe ActorId) -> m (Maybe ActorId)
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Maybe ActorId) -> m (Maybe ActorId))
-> (State -> Maybe ActorId) -> m (Maybe ActorId)
forall a b. (a -> b) -> a -> b
$ Faction -> Maybe ActorId
gleader (Faction -> Maybe ActorId)
-> (State -> Faction) -> State -> Maybe ActorId
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (EnumMap FactionId Faction -> FactionId -> Faction
forall k a. Enum k => EnumMap k a -> k -> a
EM.! Actor -> FactionId
bfid Actor
sb) (EnumMap FactionId Faction -> Faction)
-> (State -> EnumMap FactionId Faction) -> State -> Faction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> EnumMap FactionId Faction
sfactionD
    Maybe ActorId
mtleader <- (State -> Maybe ActorId) -> m (Maybe ActorId)
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState ((State -> Maybe ActorId) -> m (Maybe ActorId))
-> (State -> Maybe ActorId) -> m (Maybe ActorId)
forall a b. (a -> b) -> a -> b
$ Faction -> Maybe ActorId
gleader (Faction -> Maybe ActorId)
-> (State -> Faction) -> State -> Maybe ActorId
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (EnumMap FactionId Faction -> FactionId -> Faction
forall k a. Enum k => EnumMap k a -> k -> a
EM.! Actor -> FactionId
bfid Actor
tb) (EnumMap FactionId Faction -> Faction)
-> (State -> EnumMap FactionId Faction) -> State -> Faction
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State -> EnumMap FactionId Faction
sfactionD
    [UpdAtomic] -> m [UpdAtomic]
forall (m :: * -> *) a. Monad m => a -> m a
return ([UpdAtomic] -> m [UpdAtomic]) -> [UpdAtomic] -> m [UpdAtomic]
forall a b. (a -> b) -> a -> b
$ [ FactionId -> Maybe ActorId -> Maybe ActorId -> UpdAtomic
UpdLeadFaction (Actor -> FactionId
bfid Actor
sb) Maybe ActorId
msleader Maybe ActorId
forall a. Maybe a
Nothing
             | ActorId -> Maybe ActorId
forall a. a -> Maybe a
Just ActorId
source Maybe ActorId -> Maybe ActorId -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe ActorId
msleader ]
             [UpdAtomic] -> [UpdAtomic] -> [UpdAtomic]
forall a. [a] -> [a] -> [a]
++ [ FactionId -> Maybe ActorId -> Maybe ActorId -> UpdAtomic
UpdLeadFaction (Actor -> FactionId
bfid Actor
tb) Maybe ActorId
mtleader Maybe ActorId
forall a. Maybe a
Nothing
                | ActorId -> Maybe ActorId
forall a. a -> Maybe a
Just ActorId
target Maybe ActorId -> Maybe ActorId -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe ActorId
mtleader ]
             [UpdAtomic] -> [UpdAtomic] -> [UpdAtomic]
forall a. [a] -> [a] -> [a]
++ [ ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic
UpdLoseActor ActorId
source Actor
sb [(ItemId, Item)]
sais
                , ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic
UpdLoseActor ActorId
target Actor
tb [(ItemId, Item)]
tais
                , ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic
UpdSpotActor ActorId
source Actor
sb { bpos :: Point
bpos = Actor -> Point
bpos Actor
tb
                                         , boldpos :: Maybe Point
boldpos = Point -> Maybe Point
forall a. a -> Maybe a
Just (Point -> Maybe Point) -> Point -> Maybe Point
forall a b. (a -> b) -> a -> b
$ Actor -> Point
bpos Actor
sb } [(ItemId, Item)]
sais
                , ActorId -> Actor -> [(ItemId, Item)] -> UpdAtomic
UpdSpotActor ActorId
target Actor
tb { bpos :: Point
bpos = Actor -> Point
bpos Actor
sb
                                         , boldpos :: Maybe Point
boldpos = Point -> Maybe Point
forall a. a -> Maybe a
Just (Point -> Maybe Point) -> Point -> Maybe Point
forall a b. (a -> b) -> a -> b
$ Actor -> Point
bpos Actor
tb } [(ItemId, Item)]
tais
                ]
             [UpdAtomic] -> [UpdAtomic] -> [UpdAtomic]
forall a. [a] -> [a] -> [a]
++ [ FactionId -> Maybe ActorId -> Maybe ActorId -> UpdAtomic
UpdLeadFaction (Actor -> FactionId
bfid Actor
sb) Maybe ActorId
forall a. Maybe a
Nothing Maybe ActorId
msleader
                | ActorId -> Maybe ActorId
forall a. a -> Maybe a
Just ActorId
source Maybe ActorId -> Maybe ActorId -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe ActorId
msleader ]
             [UpdAtomic] -> [UpdAtomic] -> [UpdAtomic]
forall a. [a] -> [a] -> [a]
++ [ FactionId -> Maybe ActorId -> Maybe ActorId -> UpdAtomic
UpdLeadFaction (Actor -> FactionId
bfid Actor
tb) Maybe ActorId
forall a. Maybe a
Nothing Maybe ActorId
mtleader
                | ActorId -> Maybe ActorId
forall a. a -> Maybe a
Just ActorId
target Maybe ActorId -> Maybe ActorId -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe ActorId
mtleader ]
  _ -> [UpdAtomic] -> m [UpdAtomic]
forall (m :: * -> *) a. Monad m => a -> m a
return []

-- | Given the client, its perception and an atomic command, determine
-- if the client notices the command.
seenAtomicCli :: Bool -> FactionId -> Perception -> PosAtomic -> Bool
seenAtomicCli :: Bool -> FactionId -> Perception -> PosAtomic -> Bool
seenAtomicCli knowEvents :: Bool
knowEvents fid :: FactionId
fid per :: Perception
per posAtomic :: PosAtomic
posAtomic =
  case PosAtomic
posAtomic of
    PosSight _ ps :: [Point]
ps -> (Point -> Bool) -> [Point] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Point -> EnumSet Point -> Bool
forall k. Enum k => k -> EnumSet k -> Bool
`ES.member` Perception -> EnumSet Point
totalVisible Perception
per) [Point]
ps Bool -> Bool -> Bool
|| Bool
knowEvents
    PosFidAndSight fids :: [FactionId]
fids _ ps :: [Point]
ps ->
      FactionId
fid FactionId -> [FactionId] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FactionId]
fids Bool -> Bool -> Bool
|| (Point -> Bool) -> [Point] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Point -> EnumSet Point -> Bool
forall k. Enum k => k -> EnumSet k -> Bool
`ES.member` Perception -> EnumSet Point
totalVisible Perception
per) [Point]
ps Bool -> Bool -> Bool
|| Bool
knowEvents
    PosSmell _ ps :: [Point]
ps -> (Point -> Bool) -> [Point] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Point -> EnumSet Point -> Bool
forall k. Enum k => k -> EnumSet k -> Bool
`ES.member` Perception -> EnumSet Point
totalSmelled Perception
per) [Point]
ps Bool -> Bool -> Bool
|| Bool
knowEvents
    PosFid fid2 :: FactionId
fid2 -> FactionId
fid FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
fid2
    PosFidAndSer _ fid2 :: FactionId
fid2 -> FactionId
fid FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
fid2
    PosSer -> Bool
False
    PosAll -> Bool
True
    PosNone -> String -> Bool
forall a. HasCallStack => String -> a
error (String -> Bool) -> String -> Bool
forall a b. (a -> b) -> a -> b
$ "no position possible" String -> FactionId -> String
forall v. Show v => String -> v -> String
`showFailure` FactionId
fid

-- | Determine whether the server would see a command that has
-- the given visibilty conditions.
seenAtomicSer :: PosAtomic -> Bool
seenAtomicSer :: PosAtomic -> Bool
seenAtomicSer posAtomic :: PosAtomic
posAtomic =
  case PosAtomic
posAtomic of
    PosFid _ -> Bool
False
    PosNone -> String -> Bool
forall a. HasCallStack => String -> a
error (String -> Bool) -> String -> Bool
forall a b. (a -> b) -> a -> b
$ "no position possible" String -> PosAtomic -> String
forall v. Show v => String -> v -> String
`showFailure` PosAtomic
posAtomic
    _ -> Bool
True