packages feed

LambdaHack 0.8.1.2 → 0.8.3.0

raw patch · 53 files changed

+714/−660 lines, 53 filesdep ~randomPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: random

API changes (from Hackage documentation)

- Game.LambdaHack.Atomic: UpdCoverSeed :: Container -> ItemId -> ItemSeed -> UpdAtomic
- Game.LambdaHack.Atomic: UpdDiscoverSeed :: Container -> ItemId -> ItemSeed -> UpdAtomic
- Game.LambdaHack.Atomic.CmdAtomic: UpdCoverSeed :: Container -> ItemId -> ItemSeed -> UpdAtomic
- Game.LambdaHack.Atomic.CmdAtomic: UpdDiscoverSeed :: Container -> ItemId -> ItemSeed -> UpdAtomic
- Game.LambdaHack.Atomic.HandleAtomicWrite: discoverSeed :: MonadStateWrite m => ItemId -> ItemSeed -> m ()
- Game.LambdaHack.Atomic.HandleAtomicWrite: updCoverSeed :: Container -> ItemId -> ItemSeed -> m ()
- Game.LambdaHack.Atomic.HandleAtomicWrite: updDiscoverSeed :: MonadStateWrite m => Container -> ItemId -> ItemSeed -> m ()
- Game.LambdaHack.Client: RequestAnyAbility :: (RequestTimed a) -> RequestAnyAbility
- Game.LambdaHack.Client: [ReqAlter] :: Point -> RequestTimed 'AbAlter
- Game.LambdaHack.Client: [ReqApply] :: ItemId -> CStore -> RequestTimed 'AbApply
- Game.LambdaHack.Client: [ReqDisplace] :: ActorId -> RequestTimed 'AbDisplace
- Game.LambdaHack.Client: [ReqMelee] :: ActorId -> ItemId -> CStore -> RequestTimed 'AbMelee
- Game.LambdaHack.Client: [ReqMoveItems] :: [(ItemId, Int, CStore, CStore)] -> RequestTimed 'AbMoveItem
- Game.LambdaHack.Client: [ReqMove] :: Vector -> RequestTimed 'AbMove
- Game.LambdaHack.Client: [ReqProject] :: Point -> Int -> ItemId -> CStore -> RequestTimed 'AbProject
- Game.LambdaHack.Client: [ReqWait10] :: RequestTimed 'AbWait
- Game.LambdaHack.Client: [ReqWait] :: RequestTimed 'AbWait
- Game.LambdaHack.Client: data RequestAnyAbility
- Game.LambdaHack.Client: sbenchmark :: ClientOptions -> Bool
- Game.LambdaHack.Client.AI.HandleAbilityM: displaceTowards :: MonadClient m => ActorId -> Point -> Bool -> m (Strategy Vector)
- Game.LambdaHack.Client.HandleAtomicM: coverSeed :: Container -> ItemId -> ItemSeed -> m ()
- Game.LambdaHack.Client.HandleAtomicM: discoverSeed :: MonadClient m => Container -> ItemId -> ItemSeed -> m ()
- Game.LambdaHack.Client.Request: RequestAnyAbility :: (RequestTimed a) -> RequestAnyAbility
- Game.LambdaHack.Client.Request: [ReqAlter] :: Point -> RequestTimed 'AbAlter
- Game.LambdaHack.Client.Request: [ReqApply] :: ItemId -> CStore -> RequestTimed 'AbApply
- Game.LambdaHack.Client.Request: [ReqDisplace] :: ActorId -> RequestTimed 'AbDisplace
- Game.LambdaHack.Client.Request: [ReqMelee] :: ActorId -> ItemId -> CStore -> RequestTimed 'AbMelee
- Game.LambdaHack.Client.Request: [ReqMoveItems] :: [(ItemId, Int, CStore, CStore)] -> RequestTimed 'AbMoveItem
- Game.LambdaHack.Client.Request: [ReqMove] :: Vector -> RequestTimed 'AbMove
- Game.LambdaHack.Client.Request: [ReqProject] :: Point -> Int -> ItemId -> CStore -> RequestTimed 'AbProject
- Game.LambdaHack.Client.Request: [ReqWait10] :: RequestTimed 'AbWait
- Game.LambdaHack.Client.Request: [ReqWait] :: RequestTimed 'AbWait
- Game.LambdaHack.Client.Request: data RequestAnyAbility
- Game.LambdaHack.Client.Request: instance GHC.Show.Show (Game.LambdaHack.Client.Request.RequestTimed a)
- Game.LambdaHack.Client.Request: instance GHC.Show.Show Game.LambdaHack.Client.Request.RequestAnyAbility
- Game.LambdaHack.Client.UI.HandleHumanM: fmapTimedToUI :: Monad m => m (RequestTimed a) -> m ReqUI
- Game.LambdaHack.Common.ItemAspect: data ItemSeed
- Game.LambdaHack.Common.ItemAspect: instance Data.Binary.Class.Binary Game.LambdaHack.Common.ItemAspect.ItemSeed
- Game.LambdaHack.Common.ItemAspect: instance Data.Hashable.Class.Hashable Game.LambdaHack.Common.ItemAspect.ItemSeed
- Game.LambdaHack.Common.ItemAspect: instance GHC.Classes.Eq Game.LambdaHack.Common.ItemAspect.ItemSeed
- Game.LambdaHack.Common.ItemAspect: instance GHC.Classes.Ord Game.LambdaHack.Common.ItemAspect.ItemSeed
- Game.LambdaHack.Common.ItemAspect: instance GHC.Enum.Enum Game.LambdaHack.Common.ItemAspect.ItemSeed
- Game.LambdaHack.Common.ItemAspect: instance GHC.Show.Show Game.LambdaHack.Common.ItemAspect.ItemSeed
- Game.LambdaHack.Common.ItemAspect: seedToAspect :: ItemSeed -> [Aspect] -> AbsDepth -> AbsDepth -> AspectRecord
- Game.LambdaHack.Server.CommonM: execFailure :: MonadServerAtomic m => ActorId -> RequestTimed a -> ReqFailure -> m ()
- Game.LambdaHack.Server.ItemRev: type ItemSeedDict = EnumMap ItemId ItemSeed
- Game.LambdaHack.Server.ProtocolM: class MonadServer m => MonadServerReadRequest m
- Game.LambdaHack.Server.State: [sitemSeedD] :: StateServer -> ItemSeedDict
+ Game.LambdaHack.Atomic: UpdCoverAspect :: Container -> ItemId -> AspectRecord -> UpdAtomic
+ Game.LambdaHack.Atomic: UpdDiscoverAspect :: Container -> ItemId -> AspectRecord -> UpdAtomic
+ Game.LambdaHack.Atomic.CmdAtomic: UpdCoverAspect :: Container -> ItemId -> AspectRecord -> UpdAtomic
+ Game.LambdaHack.Atomic.CmdAtomic: UpdDiscoverAspect :: Container -> ItemId -> AspectRecord -> UpdAtomic
+ Game.LambdaHack.Atomic.HandleAtomicWrite: discoverAspect :: MonadStateWrite m => ItemId -> AspectRecord -> m ()
+ Game.LambdaHack.Atomic.HandleAtomicWrite: updCoverAspect :: Container -> ItemId -> AspectRecord -> m ()
+ Game.LambdaHack.Atomic.HandleAtomicWrite: updDiscoverAspect :: MonadStateWrite m => Container -> ItemId -> AspectRecord -> m ()
+ Game.LambdaHack.Client: ClientOptions :: Maybe Text -> Maybe Text -> Maybe Int -> Maybe Int -> Maybe Int -> Maybe Bool -> Maybe Int -> Maybe Int -> Bool -> Maybe Bool -> Bool -> Bool -> Maybe Text -> Maybe FilePath -> String -> Bool -> Bool -> Bool -> Bool -> Maybe Int -> Maybe Int -> Bool -> ClientOptions
+ Game.LambdaHack.Client: ReqAlter :: Point -> RequestTimed
+ Game.LambdaHack.Client: ReqApply :: ItemId -> CStore -> RequestTimed
+ Game.LambdaHack.Client: ReqDisplace :: ActorId -> RequestTimed
+ Game.LambdaHack.Client: ReqMelee :: ActorId -> ItemId -> CStore -> RequestTimed
+ Game.LambdaHack.Client: ReqMove :: Vector -> RequestTimed
+ Game.LambdaHack.Client: ReqMoveItems :: [(ItemId, Int, CStore, CStore)] -> RequestTimed
+ Game.LambdaHack.Client: ReqProject :: Point -> Int -> ItemId -> CStore -> RequestTimed
+ Game.LambdaHack.Client: ReqWait :: RequestTimed
+ Game.LambdaHack.Client: ReqWait10 :: RequestTimed
+ Game.LambdaHack.Client: [sbenchmark] :: ClientOptions -> Bool
+ Game.LambdaHack.Client: [scolorIsBold] :: ClientOptions -> Maybe Bool
+ Game.LambdaHack.Client: [sdbgMsgCli] :: ClientOptions -> Bool
+ Game.LambdaHack.Client: [sdisableAutoYes] :: ClientOptions -> Bool
+ Game.LambdaHack.Client: [sdlFonSizeAdd] :: ClientOptions -> Maybe Int
+ Game.LambdaHack.Client: [sdlFontFile] :: ClientOptions -> Maybe Text
+ Game.LambdaHack.Client: [sdlTtfSizeAdd] :: ClientOptions -> Maybe Int
+ Game.LambdaHack.Client: [sfontDir] :: ClientOptions -> Maybe FilePath
+ Game.LambdaHack.Client: [sfontSize] :: ClientOptions -> Maybe Int
+ Game.LambdaHack.Client: [sfrontendLazy] :: ClientOptions -> Bool
+ Game.LambdaHack.Client: [sfrontendNull] :: ClientOptions -> Bool
+ Game.LambdaHack.Client: [sfrontendTeletype] :: ClientOptions -> Bool
+ Game.LambdaHack.Client: [sgtkFontFamily] :: ClientOptions -> Maybe Text
+ Game.LambdaHack.Client: [slogPriority] :: ClientOptions -> Maybe Int
+ Game.LambdaHack.Client: [smaxFps] :: ClientOptions -> Maybe Int
+ Game.LambdaHack.Client: [snewGameCli] :: ClientOptions -> Bool
+ Game.LambdaHack.Client: [snoAnim] :: ClientOptions -> Maybe Bool
+ Game.LambdaHack.Client: [sprintEachScreen] :: ClientOptions -> Bool
+ Game.LambdaHack.Client: [ssavePrefixCli] :: ClientOptions -> String
+ Game.LambdaHack.Client: [sstopAfterFrames] :: ClientOptions -> Maybe Int
+ Game.LambdaHack.Client: [sstopAfterSeconds] :: ClientOptions -> Maybe Int
+ Game.LambdaHack.Client: [stitle] :: ClientOptions -> Maybe Text
+ Game.LambdaHack.Client.AI.HandleAbilityM: displaceTgt :: MonadClient m => ActorId -> Point -> Bool -> m (Strategy RequestTimed)
+ Game.LambdaHack.Client.HandleAtomicM: coverAspect :: Container -> ItemId -> AspectRecord -> m ()
+ Game.LambdaHack.Client.HandleAtomicM: discoverAspect :: MonadClient m => Container -> ItemId -> AspectRecord -> m ()
+ Game.LambdaHack.Client.Request: ReqAlter :: Point -> RequestTimed
+ Game.LambdaHack.Client.Request: ReqApply :: ItemId -> CStore -> RequestTimed
+ Game.LambdaHack.Client.Request: ReqDisplace :: ActorId -> RequestTimed
+ Game.LambdaHack.Client.Request: ReqMelee :: ActorId -> ItemId -> CStore -> RequestTimed
+ Game.LambdaHack.Client.Request: ReqMove :: Vector -> RequestTimed
+ Game.LambdaHack.Client.Request: ReqMoveItems :: [(ItemId, Int, CStore, CStore)] -> RequestTimed
+ Game.LambdaHack.Client.Request: ReqProject :: Point -> Int -> ItemId -> CStore -> RequestTimed
+ Game.LambdaHack.Client.Request: ReqWait :: RequestTimed
+ Game.LambdaHack.Client.Request: ReqWait10 :: RequestTimed
+ Game.LambdaHack.Client.Request: instance GHC.Show.Show Game.LambdaHack.Client.Request.RequestTimed
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: moveOrSelectItem :: forall m. MonadClientUI m => [CStore] -> CStore -> Maybe Part -> Bool -> m (FailOrCmd RequestTimed)
+ Game.LambdaHack.Common.ItemAspect: rollAspectRecord :: [Aspect] -> AbsDepth -> AbsDepth -> Rnd AspectRecord
+ Game.LambdaHack.Common.Misc: workaroundOnMainThreadMVar :: MVar (IO ())
+ Game.LambdaHack.Common.ReqFailure: DisplaceUnskilled :: ReqFailure
+ Game.LambdaHack.Common.ReqFailure: MeleeUnskilled :: ReqFailure
+ Game.LambdaHack.Common.ReqFailure: MoveItemUnskilled :: ReqFailure
+ Game.LambdaHack.Common.ReqFailure: MoveUnskilled :: ReqFailure
+ Game.LambdaHack.Common.ReqFailure: WaitUnskilled :: ReqFailure
+ Game.LambdaHack.Server.HandleRequestM: execFailure :: MonadServerAtomic m => ActorId -> RequestTimed -> ReqFailure -> m ()
+ Game.LambdaHack.Server.HandleRequestM: reqMeleeChecked :: MonadServerAtomic m => ActorId -> ActorId -> ItemId -> CStore -> m ()
+ Game.LambdaHack.Server.ProtocolM: class MonadServer m => MonadServerComm m
- Game.LambdaHack.Atomic: UpdCover :: Container -> ItemId -> (ContentId ItemKind) -> ItemSeed -> UpdAtomic
+ Game.LambdaHack.Atomic: UpdCover :: Container -> ItemId -> (ContentId ItemKind) -> AspectRecord -> UpdAtomic
- Game.LambdaHack.Atomic: UpdDiscover :: Container -> ItemId -> (ContentId ItemKind) -> ItemSeed -> UpdAtomic
+ Game.LambdaHack.Atomic: UpdDiscover :: Container -> ItemId -> (ContentId ItemKind) -> AspectRecord -> UpdAtomic
- Game.LambdaHack.Atomic.CmdAtomic: UpdCover :: Container -> ItemId -> (ContentId ItemKind) -> ItemSeed -> UpdAtomic
+ Game.LambdaHack.Atomic.CmdAtomic: UpdCover :: Container -> ItemId -> (ContentId ItemKind) -> AspectRecord -> UpdAtomic
- Game.LambdaHack.Atomic.CmdAtomic: UpdDiscover :: Container -> ItemId -> (ContentId ItemKind) -> ItemSeed -> UpdAtomic
+ Game.LambdaHack.Atomic.CmdAtomic: UpdDiscover :: Container -> ItemId -> (ContentId ItemKind) -> AspectRecord -> UpdAtomic
- Game.LambdaHack.Atomic.HandleAtomicWrite: updCover :: Container -> ItemId -> ContentId ItemKind -> ItemSeed -> m ()
+ Game.LambdaHack.Atomic.HandleAtomicWrite: updCover :: Container -> ItemId -> ContentId ItemKind -> AspectRecord -> m ()
- Game.LambdaHack.Atomic.HandleAtomicWrite: updDiscover :: MonadStateWrite m => Container -> ItemId -> ContentId ItemKind -> ItemSeed -> m ()
+ Game.LambdaHack.Atomic.HandleAtomicWrite: updDiscover :: MonadStateWrite m => Container -> ItemId -> ContentId ItemKind -> AspectRecord -> m ()
- Game.LambdaHack.Client: ReqAITimed :: RequestAnyAbility -> ReqAI
+ Game.LambdaHack.Client: ReqAITimed :: RequestTimed -> ReqAI
- Game.LambdaHack.Client: ReqUITimed :: RequestAnyAbility -> ReqUI
+ Game.LambdaHack.Client: ReqUITimed :: RequestTimed -> ReqUI
- Game.LambdaHack.Client: data RequestTimed :: Ability -> *
+ Game.LambdaHack.Client: data RequestTimed
- Game.LambdaHack.Client.AI: pickActorAndAction :: MonadClient m => Maybe (ActorId, RequestAnyAbility) -> ActorId -> m (ActorId, RequestAnyAbility, Maybe Point)
+ Game.LambdaHack.Client.AI: pickActorAndAction :: MonadClient m => Maybe (ActorId, RequestTimed) -> ActorId -> m (ActorId, RequestTimed, Maybe Point)
- Game.LambdaHack.Client.AI.HandleAbilityM: actionStrategy :: forall m. MonadClient m => ActorId -> Bool -> m (Strategy RequestAnyAbility)
+ Game.LambdaHack.Client.AI.HandleAbilityM: actionStrategy :: forall m. MonadClient m => ActorId -> Bool -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: applyItem :: MonadClient m => ActorId -> ApplyItemGroup -> m (Strategy (RequestTimed 'AbApply))
+ Game.LambdaHack.Client.AI.HandleAbilityM: applyItem :: MonadClient m => ActorId -> ApplyItemGroup -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: chase :: MonadClient m => ActorId -> Bool -> Bool -> m (Strategy RequestAnyAbility)
+ Game.LambdaHack.Client.AI.HandleAbilityM: chase :: MonadClient m => ActorId -> Bool -> Bool -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: displaceBlocker :: MonadClient m => ActorId -> Bool -> m (Strategy RequestAnyAbility)
+ Game.LambdaHack.Client.AI.HandleAbilityM: displaceBlocker :: MonadClient m => ActorId -> Bool -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: displaceFoe :: MonadClient m => ActorId -> m (Strategy RequestAnyAbility)
+ Game.LambdaHack.Client.AI.HandleAbilityM: displaceFoe :: MonadClient m => ActorId -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: equipItems :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMoveItem))
+ Game.LambdaHack.Client.AI.HandleAbilityM: equipItems :: MonadClient m => ActorId -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: flee :: MonadClient m => ActorId -> [(Int, Point)] -> m (Strategy RequestAnyAbility)
+ Game.LambdaHack.Client.AI.HandleAbilityM: flee :: MonadClient m => ActorId -> [(Int, Point)] -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: meleeAny :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMelee))
+ Game.LambdaHack.Client.AI.HandleAbilityM: meleeAny :: MonadClient m => ActorId -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: meleeBlocker :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMelee))
+ Game.LambdaHack.Client.AI.HandleAbilityM: meleeBlocker :: MonadClient m => ActorId -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: moveOrRunAid :: MonadClient m => ActorId -> Vector -> m (Maybe RequestAnyAbility)
+ Game.LambdaHack.Client.AI.HandleAbilityM: moveOrRunAid :: MonadClient m => ActorId -> Vector -> m (Maybe RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: pickAction :: MonadClient m => ActorId -> Bool -> m RequestAnyAbility
+ Game.LambdaHack.Client.AI.HandleAbilityM: pickAction :: MonadClient m => ActorId -> Bool -> m RequestTimed
- Game.LambdaHack.Client.AI.HandleAbilityM: pickup :: MonadClient m => ActorId -> Bool -> m (Strategy (RequestTimed 'AbMoveItem))
+ Game.LambdaHack.Client.AI.HandleAbilityM: pickup :: MonadClient m => ActorId -> Bool -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: projectItem :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbProject))
+ Game.LambdaHack.Client.AI.HandleAbilityM: projectItem :: MonadClient m => ActorId -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: trigger :: MonadClient m => ActorId -> FleeViaStairsOrEscape -> m (Strategy (RequestTimed 'AbAlter))
+ Game.LambdaHack.Client.AI.HandleAbilityM: trigger :: MonadClient m => ActorId -> FleeViaStairsOrEscape -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: unEquipItems :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMoveItem))
+ Game.LambdaHack.Client.AI.HandleAbilityM: unEquipItems :: MonadClient m => ActorId -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: waitBlockNow :: MonadClient m => m (Strategy (RequestTimed 'AbWait))
+ Game.LambdaHack.Client.AI.HandleAbilityM: waitBlockNow :: MonadClient m => m (Strategy RequestTimed)
- Game.LambdaHack.Client.AI.HandleAbilityM: yieldUnneeded :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMoveItem))
+ Game.LambdaHack.Client.AI.HandleAbilityM: yieldUnneeded :: MonadClient m => ActorId -> m (Strategy RequestTimed)
- Game.LambdaHack.Client.CommonM: pickWeaponClient :: MonadClient m => ActorId -> ActorId -> m (Maybe (RequestTimed 'AbMelee))
+ Game.LambdaHack.Client.CommonM: pickWeaponClient :: MonadClient m => ActorId -> ActorId -> m (Maybe RequestTimed)
- Game.LambdaHack.Client.Request: ReqAITimed :: RequestAnyAbility -> ReqAI
+ Game.LambdaHack.Client.Request: ReqAITimed :: RequestTimed -> ReqAI
- Game.LambdaHack.Client.Request: ReqUITimed :: RequestAnyAbility -> ReqUI
+ Game.LambdaHack.Client.Request: ReqUITimed :: RequestTimed -> ReqUI
- Game.LambdaHack.Client.Request: data RequestTimed :: Ability -> *
+ Game.LambdaHack.Client.Request: data RequestTimed
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: alterDirHuman :: MonadClientUI m => [TriggerTile] -> m (FailOrCmd (RequestTimed 'AbAlter))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: alterDirHuman :: MonadClientUI m => [TriggerTile] -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: alterTile :: MonadClientUI m => [TriggerTile] -> Vector -> m (FailOrCmd (RequestTimed 'AbAlter))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: alterTile :: MonadClientUI m => [TriggerTile] -> Vector -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: alterTileAtPos :: MonadClientUI m => [TriggerTile] -> Point -> Text -> m (FailOrCmd (RequestTimed 'AbAlter))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: alterTileAtPos :: MonadClientUI m => [TriggerTile] -> Point -> Text -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: alterWithPointerHuman :: MonadClientUI m => [TriggerTile] -> m (FailOrCmd (RequestTimed 'AbAlter))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: alterWithPointerHuman :: MonadClientUI m => [TriggerTile] -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: applyHuman :: MonadClientUI m => m (FailOrCmd (RequestTimed 'AbApply))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: applyHuman :: MonadClientUI m => m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: applyItem :: MonadClientUI m => (CStore, (ItemId, ItemFullKit)) -> m (FailOrCmd (RequestTimed 'AbApply))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: applyItem :: MonadClientUI m => (CStore, (ItemId, ItemFullKit)) -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: continueToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestAnyAbility)
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: continueToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: displaceAid :: MonadClientUI m => ActorId -> m (FailOrCmd (RequestTimed 'AbDisplace))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: displaceAid :: MonadClientUI m => ActorId -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: goToXhair :: MonadClientUI m => Bool -> Bool -> m (FailOrCmd RequestAnyAbility)
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: goToXhair :: MonadClientUI m => Bool -> Bool -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: meleeAid :: MonadClientUI m => ActorId -> m (FailOrCmd (RequestTimed 'AbMelee))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: meleeAid :: MonadClientUI m => ActorId -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: moveItemHuman :: forall m. MonadClientUI m => [CStore] -> CStore -> Maybe Part -> Bool -> m (FailOrCmd (RequestTimed 'AbMoveItem))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: moveItemHuman :: forall m. MonadClientUI m => [CStore] -> CStore -> Maybe Part -> Bool -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: moveItems :: forall m. MonadClientUI m => [CStore] -> (CStore, [(ItemId, ItemFullKit)]) -> CStore -> m (FailOrCmd (RequestTimed 'AbMoveItem))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: moveItems :: forall m. MonadClientUI m => [CStore] -> (CStore, [(ItemId, ItemFullKit)]) -> CStore -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: moveOnceToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestAnyAbility)
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: moveOnceToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: moveRunHuman :: MonadClientUI m => Bool -> Bool -> Bool -> Bool -> Vector -> m (FailOrCmd RequestAnyAbility)
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: moveRunHuman :: MonadClientUI m => Bool -> Bool -> Bool -> Bool -> Vector -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: moveSearchAlter :: MonadClientUI m => Vector -> m (FailOrCmd RequestAnyAbility)
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: moveSearchAlter :: MonadClientUI m => Vector -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: projectHuman :: MonadClientUI m => m (FailOrCmd (RequestTimed 'AbProject))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: projectHuman :: MonadClientUI m => m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: projectItem :: MonadClientUI m => (CStore, (ItemId, ItemFull)) -> m (FailOrCmd (RequestTimed 'AbProject))
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: projectItem :: MonadClientUI m => (CStore, (ItemId, ItemFull)) -> m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: runOnceAheadHuman :: MonadClientUI m => m (Either MError ReqUI)
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: runOnceAheadHuman :: MonadClientUI m => m (Either MError RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: runOnceToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestAnyAbility)
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: runOnceToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: waitHuman :: MonadClientUI m => m (RequestTimed 'AbWait)
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: waitHuman :: MonadClientUI m => m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.HandleHumanGlobalM: waitHuman10 :: MonadClientUI m => m (RequestTimed 'AbWait)
+ Game.LambdaHack.Client.UI.HandleHumanGlobalM: waitHuman10 :: MonadClientUI m => m (FailOrCmd RequestTimed)
- Game.LambdaHack.Client.UI.RunM: continueRun :: MonadClientUI m => LevelId -> RunParams -> m (Either Text RequestAnyAbility)
+ Game.LambdaHack.Client.UI.RunM: continueRun :: MonadClientUI m => LevelId -> RunParams -> m (Either Text RequestTimed)
- Game.LambdaHack.Server: loopSer :: (MonadServerAtomic m, MonadServerReadRequest m) => ServerOptions -> (Bool -> FactionId -> ChanServer -> IO ()) -> m ()
+ Game.LambdaHack.Server: loopSer :: (MonadServerAtomic m, MonadServerComm m) => ServerOptions -> (Bool -> FactionId -> ChanServer -> IO ()) -> m ()
- Game.LambdaHack.Server.BroadcastAtomic: handleAndBroadcast :: (MonadServerAtomic m, MonadServerReadRequest m) => PosAtomic -> [UpdAtomic] -> CmdAtomic -> m ()
+ Game.LambdaHack.Server.BroadcastAtomic: handleAndBroadcast :: (MonadServerAtomic m, MonadServerComm m) => PosAtomic -> [UpdAtomic] -> CmdAtomic -> m ()
- Game.LambdaHack.Server.BroadcastAtomic: sendPer :: (MonadServerAtomic m, MonadServerReadRequest m) => FactionId -> LevelId -> Perception -> Perception -> Perception -> m ()
+ Game.LambdaHack.Server.BroadcastAtomic: sendPer :: (MonadServerAtomic m, MonadServerComm m) => FactionId -> LevelId -> Perception -> Perception -> Perception -> m ()
- Game.LambdaHack.Server.CommonM: registerActor :: MonadServerAtomic m => Bool -> ItemKnown -> ItemFullKit -> ItemSeed -> FactionId -> Point -> LevelId -> Time -> m ActorId
+ Game.LambdaHack.Server.CommonM: registerActor :: MonadServerAtomic m => Bool -> ItemKnown -> ItemFullKit -> FactionId -> Point -> LevelId -> Time -> m ActorId
- Game.LambdaHack.Server.EndM: endOrLoop :: (MonadServerAtomic m, MonadServerReadRequest m) => m () -> (Maybe (GroupName ModeKind) -> m ()) -> m ()
+ Game.LambdaHack.Server.EndM: endOrLoop :: (MonadServerAtomic m, MonadServerComm m) => m () -> (Maybe (GroupName ModeKind) -> m ()) -> m ()
- Game.LambdaHack.Server.EndM: gameExit :: (MonadServerAtomic m, MonadServerReadRequest m) => m ()
+ Game.LambdaHack.Server.EndM: gameExit :: (MonadServerAtomic m, MonadServerComm m) => m ()
- Game.LambdaHack.Server.HandleRequestM: handleRequestAI :: MonadServerAtomic m => ReqAI -> m (Maybe RequestAnyAbility)
+ Game.LambdaHack.Server.HandleRequestM: handleRequestAI :: MonadServerAtomic m => ReqAI -> m (Maybe RequestTimed)
- Game.LambdaHack.Server.HandleRequestM: handleRequestTimed :: MonadServerAtomic m => FactionId -> ActorId -> RequestTimed a -> m Bool
+ Game.LambdaHack.Server.HandleRequestM: handleRequestTimed :: MonadServerAtomic m => FactionId -> ActorId -> RequestTimed -> m Bool
- Game.LambdaHack.Server.HandleRequestM: handleRequestTimedCases :: MonadServerAtomic m => ActorId -> RequestTimed a -> m ()
+ Game.LambdaHack.Server.HandleRequestM: handleRequestTimedCases :: MonadServerAtomic m => ActorId -> RequestTimed -> m ()
- Game.LambdaHack.Server.HandleRequestM: handleRequestUI :: MonadServerAtomic m => FactionId -> ActorId -> ReqUI -> m (Maybe RequestAnyAbility)
+ Game.LambdaHack.Server.HandleRequestM: handleRequestUI :: MonadServerAtomic m => FactionId -> ActorId -> ReqUI -> m (Maybe RequestTimed)
- Game.LambdaHack.Server.HandleRequestM: setBWait :: MonadServerAtomic m => RequestTimed a -> ActorId -> Actor -> m (Maybe Bool)
+ Game.LambdaHack.Server.HandleRequestM: setBWait :: MonadServerAtomic m => RequestTimed -> ActorId -> Actor -> m (Maybe Bool)
- Game.LambdaHack.Server.ItemM: onlyRegisterItem :: MonadServerAtomic m => ItemKnown -> ItemSeed -> m ItemId
+ Game.LambdaHack.Server.ItemM: onlyRegisterItem :: MonadServerAtomic m => ItemKnown -> m ItemId
- Game.LambdaHack.Server.ItemM: registerItem :: MonadServerAtomic m => ItemFullKit -> ItemKnown -> ItemSeed -> Container -> Bool -> m ItemId
+ Game.LambdaHack.Server.ItemM: registerItem :: MonadServerAtomic m => ItemFullKit -> ItemKnown -> Container -> Bool -> m ItemId
- Game.LambdaHack.Server.ItemM: rollItem :: MonadServerAtomic m => Int -> LevelId -> Freqs ItemKind -> m (Maybe (ItemKnown, ItemFullKit, ItemSeed, GroupName ItemKind))
+ Game.LambdaHack.Server.ItemM: rollItem :: MonadServerAtomic m => Int -> LevelId -> Freqs ItemKind -> m (Maybe (ItemKnown, ItemFullKit, GroupName ItemKind))
- Game.LambdaHack.Server.ItemRev: newItem :: COps -> FlavourMap -> DiscoveryKindRev -> UniqueSet -> Freqs ItemKind -> Int -> LevelId -> AbsDepth -> AbsDepth -> Rnd (Maybe (ItemKnown, ItemFullKit, ItemSeed, GroupName ItemKind))
+ Game.LambdaHack.Server.ItemRev: newItem :: COps -> FlavourMap -> DiscoveryKindRev -> UniqueSet -> Freqs ItemKind -> Int -> LevelId -> AbsDepth -> AbsDepth -> Rnd (Maybe (ItemKnown, ItemFullKit, GroupName ItemKind))
- Game.LambdaHack.Server.LoopM: hActors :: forall m. (MonadServerAtomic m, MonadServerReadRequest m) => [ActorId] -> m Bool
+ Game.LambdaHack.Server.LoopM: hActors :: forall m. (MonadServerAtomic m, MonadServerComm m) => [ActorId] -> m Bool
- Game.LambdaHack.Server.LoopM: handleActors :: (MonadServerAtomic m, MonadServerReadRequest m) => LevelId -> FactionId -> m Bool
+ Game.LambdaHack.Server.LoopM: handleActors :: (MonadServerAtomic m, MonadServerComm m) => LevelId -> FactionId -> m Bool
- Game.LambdaHack.Server.LoopM: handleFidUpd :: (MonadServerAtomic m, MonadServerReadRequest m) => (FactionId -> m ()) -> FactionId -> Faction -> m ()
+ Game.LambdaHack.Server.LoopM: handleFidUpd :: (MonadServerAtomic m, MonadServerComm m) => (FactionId -> m ()) -> FactionId -> Faction -> m ()
- Game.LambdaHack.Server.LoopM: loopSer :: (MonadServerAtomic m, MonadServerReadRequest m) => ServerOptions -> (Bool -> FactionId -> ChanServer -> IO ()) -> m ()
+ Game.LambdaHack.Server.LoopM: loopSer :: (MonadServerAtomic m, MonadServerComm m) => ServerOptions -> (Bool -> FactionId -> ChanServer -> IO ()) -> m ()
- Game.LambdaHack.Server.LoopM: loopUpd :: forall m. (MonadServerAtomic m, MonadServerReadRequest m) => m () -> m ()
+ Game.LambdaHack.Server.LoopM: loopUpd :: forall m. (MonadServerAtomic m, MonadServerComm m) => m () -> m ()
- Game.LambdaHack.Server.ProtocolM: getsDict :: MonadServerReadRequest m => (ConnServerDict -> a) -> m a
+ Game.LambdaHack.Server.ProtocolM: getsDict :: MonadServerComm m => (ConnServerDict -> a) -> m a
- Game.LambdaHack.Server.ProtocolM: killAllClients :: (MonadServerAtomic m, MonadServerReadRequest m) => m ()
+ Game.LambdaHack.Server.ProtocolM: killAllClients :: (MonadServerAtomic m, MonadServerComm m) => m ()
- Game.LambdaHack.Server.ProtocolM: liftIO :: MonadServerReadRequest m => IO a -> m a
+ Game.LambdaHack.Server.ProtocolM: liftIO :: MonadServerComm m => IO a -> m a
- Game.LambdaHack.Server.ProtocolM: modifyDict :: MonadServerReadRequest m => (ConnServerDict -> ConnServerDict) -> m ()
+ Game.LambdaHack.Server.ProtocolM: modifyDict :: MonadServerComm m => (ConnServerDict -> ConnServerDict) -> m ()
- Game.LambdaHack.Server.ProtocolM: putDict :: MonadServerReadRequest m => ConnServerDict -> m ()
+ Game.LambdaHack.Server.ProtocolM: putDict :: MonadServerComm m => ConnServerDict -> m ()
- Game.LambdaHack.Server.ProtocolM: readQueueAI :: MonadServerReadRequest m => CliSerQueue RequestAI -> m RequestAI
+ Game.LambdaHack.Server.ProtocolM: readQueueAI :: MonadServerComm m => CliSerQueue RequestAI -> m RequestAI
- Game.LambdaHack.Server.ProtocolM: readQueueUI :: MonadServerReadRequest m => CliSerQueue RequestUI -> m RequestUI
+ Game.LambdaHack.Server.ProtocolM: readQueueUI :: MonadServerComm m => CliSerQueue RequestUI -> m RequestUI
- Game.LambdaHack.Server.ProtocolM: sendQueryAI :: MonadServerReadRequest m => FactionId -> ActorId -> m RequestAI
+ Game.LambdaHack.Server.ProtocolM: sendQueryAI :: MonadServerComm m => FactionId -> ActorId -> m RequestAI
- Game.LambdaHack.Server.ProtocolM: sendQueryUI :: (MonadServerAtomic m, MonadServerReadRequest m) => FactionId -> ActorId -> m RequestUI
+ Game.LambdaHack.Server.ProtocolM: sendQueryUI :: (MonadServerAtomic m, MonadServerComm m) => FactionId -> ActorId -> m RequestUI
- Game.LambdaHack.Server.ProtocolM: sendSfx :: MonadServerReadRequest m => FactionId -> SfxAtomic -> m ()
+ Game.LambdaHack.Server.ProtocolM: sendSfx :: MonadServerComm m => FactionId -> SfxAtomic -> m ()
- Game.LambdaHack.Server.ProtocolM: sendUpdNoState :: MonadServerReadRequest m => FactionId -> UpdAtomic -> m ()
+ Game.LambdaHack.Server.ProtocolM: sendUpdNoState :: MonadServerComm m => FactionId -> UpdAtomic -> m ()
- Game.LambdaHack.Server.ProtocolM: sendUpdate :: (MonadServerAtomic m, MonadServerReadRequest m) => FactionId -> UpdAtomic -> m ()
+ Game.LambdaHack.Server.ProtocolM: sendUpdate :: (MonadServerAtomic m, MonadServerComm m) => FactionId -> UpdAtomic -> m ()
- Game.LambdaHack.Server.ProtocolM: sendUpdateCheck :: (MonadServerAtomic m, MonadServerReadRequest m) => FactionId -> UpdAtomic -> m ()
+ Game.LambdaHack.Server.ProtocolM: sendUpdateCheck :: (MonadServerAtomic m, MonadServerComm m) => FactionId -> UpdAtomic -> m ()
- Game.LambdaHack.Server.ProtocolM: tryRestore :: MonadServerReadRequest m => m (Maybe (State, StateServer))
+ Game.LambdaHack.Server.ProtocolM: tryRestore :: MonadServerComm m => m (Maybe (State, StateServer))
- Game.LambdaHack.Server.ProtocolM: updateConn :: (MonadServerAtomic m, MonadServerReadRequest m) => (Bool -> FactionId -> ChanServer -> IO ()) -> m ()
+ Game.LambdaHack.Server.ProtocolM: updateConn :: (MonadServerAtomic m, MonadServerComm m) => (Bool -> FactionId -> ChanServer -> IO ()) -> m ()
- Game.LambdaHack.Server.ProtocolM: writeQueue :: MonadServerReadRequest m => Response -> CliSerQueue Response -> m ()
+ Game.LambdaHack.Server.ProtocolM: writeQueue :: MonadServerComm m => Response -> CliSerQueue Response -> m ()
- Game.LambdaHack.Server.State: StateServer :: ActorTime -> EnumSet ActorId -> DiscoveryKindRev -> UniqueSet -> ItemSeedDict -> ItemRev -> FlavourMap -> ActorId -> ItemId -> EnumMap LevelId Int -> [CmdAtomic] -> EnumMap FactionId State -> PerFid -> PerValidFid -> PerCacheFid -> FovLucidLid -> FovClearLid -> FovLitLid -> [LevelId] -> Bool -> StdGen -> RNGs -> Bool -> Bool -> Bool -> ServerOptions -> ServerOptions -> StateServer
+ Game.LambdaHack.Server.State: StateServer :: ActorTime -> EnumSet ActorId -> DiscoveryKindRev -> UniqueSet -> ItemRev -> FlavourMap -> ActorId -> ItemId -> EnumMap LevelId Int -> [CmdAtomic] -> EnumMap FactionId State -> PerFid -> PerValidFid -> PerCacheFid -> FovLucidLid -> FovClearLid -> FovLitLid -> [LevelId] -> Bool -> StdGen -> RNGs -> Bool -> Bool -> Bool -> ServerOptions -> ServerOptions -> StateServer

Files

CHANGELOG.md view
@@ -1,3 +1,12 @@+## [v0.8.3.0](https://github.com/LambdaHack/LambdaHack/compare/v0.8.1.2...v0.8.3.0)++- Add a hack to run SDL2 on the main thread, fixing the OS X crash+- Warn visually when impressed and Calm running low, risking domination+- Display actor as red when low Calm and impressed or when low HP+- Fix, complete and fine tune UI, AI and server skill and weapon checks+- Fix a bug where item aspects look different to clients than to the server+- Change the requirements for the main menu ASCII art+ ## [v0.8.1.2](https://github.com/LambdaHack/LambdaHack/compare/v0.8.1.1...v0.8.1.2)  - Fix typos detected by lintian
CREDITS view
@@ -6,6 +6,7 @@ Tuukka Turto Veronika Romashkina @Peritract+Pablo Reszczynski   Fonts 16x16x.fon, 8x8x.fon and 8x8xb.fon are are taken from
Game/LambdaHack/Atomic/CmdAtomic.hs view
@@ -104,12 +104,12 @@   | UpdTimeItem ItemId Container ItemTimer ItemTimer   | UpdAgeGame [LevelId]   | UpdUnAgeGame [LevelId]-  | UpdDiscover Container ItemId (ContentId ItemKind) IA.ItemSeed-  | UpdCover Container ItemId (ContentId ItemKind) IA.ItemSeed+  | UpdDiscover Container ItemId (ContentId ItemKind) IA.AspectRecord+  | UpdCover Container ItemId (ContentId ItemKind) IA.AspectRecord   | UpdDiscoverKind Container ItemKindIx (ContentId ItemKind)   | UpdCoverKind Container ItemKindIx (ContentId ItemKind)-  | UpdDiscoverSeed Container ItemId IA.ItemSeed-  | UpdCoverSeed Container ItemId IA.ItemSeed+  | UpdDiscoverAspect Container ItemId IA.AspectRecord+  | UpdCoverAspect Container ItemId IA.AspectRecord   | UpdDiscoverServer ItemId IA.AspectRecord   | UpdCoverServer ItemId IA.AspectRecord   | UpdPerception LevelId Perception Perception@@ -215,12 +215,14 @@   UpdTimeItem iid c fromIt toIt -> Just $ UpdTimeItem iid c toIt fromIt   UpdAgeGame lids -> Just $ UpdUnAgeGame lids   UpdUnAgeGame lids -> Just $ UpdAgeGame lids-  UpdDiscover c iid ik seed -> Just $ UpdCover c iid ik seed-  UpdCover c iid ik seed -> Just $ UpdDiscover c iid ik seed+  UpdDiscover c iid ik aspectRecord -> Just $ UpdCover c iid ik aspectRecord+  UpdCover c iid ik aspectRecord -> Just $ UpdDiscover c iid ik aspectRecord   UpdDiscoverKind c ix ik -> Just $ UpdCoverKind c ix ik   UpdCoverKind c ix ik -> Just $ UpdDiscoverKind c ix ik-  UpdDiscoverSeed c iid seed -> Just $ UpdCoverSeed c iid seed-  UpdCoverSeed c iid seed -> Just $ UpdDiscoverSeed c iid seed+  UpdDiscoverAspect c iid aspectRecord ->+    Just $ UpdCoverAspect c iid aspectRecord+  UpdCoverAspect c iid aspectRecord ->+    Just $ UpdDiscoverAspect c iid aspectRecord   UpdDiscoverServer iid aspectRecord -> Just $ UpdCoverServer iid aspectRecord   UpdCoverServer iid aspectRecord -> Just $ UpdDiscoverServer iid aspectRecord   UpdPerception lid outPer inPer -> Just $ UpdPerception lid inPer outPer
Game/LambdaHack/Atomic/HandleAtomicWrite.hs view
@@ -17,7 +17,7 @@   , updAlterSmell, updSpotSmell, updLoseSmell, updTimeItem   , updAgeGame, updUnAgeGame, ageLevel, updDiscover, updCover   , updDiscoverKind, discoverKind, updCoverKind-  , updDiscoverSeed, discoverSeed, updCoverSeed+  , updDiscoverAspect, discoverAspect, updCoverAspect   , updDiscoverServer, updCoverServer   , updRestart, updRestartServer, updResumeServer #endif@@ -107,12 +107,12 @@   UpdTimeItem iid c fromIt toIt -> updTimeItem iid c fromIt toIt   UpdAgeGame lids -> updAgeGame lids   UpdUnAgeGame lids -> updUnAgeGame lids-  UpdDiscover c iid ik seed -> updDiscover c iid ik seed-  UpdCover c iid ik seed -> updCover c iid ik seed+  UpdDiscover c iid ik aspectRecord -> updDiscover c iid ik aspectRecord+  UpdCover c iid ik aspectRecord -> updCover c iid ik aspectRecord   UpdDiscoverKind c ix ik -> updDiscoverKind c ix ik   UpdCoverKind c ix ik -> updCoverKind c ix ik-  UpdDiscoverSeed c iid seed -> updDiscoverSeed c iid seed-  UpdCoverSeed c iid seed -> updCoverSeed c iid seed+  UpdDiscoverAspect c iid aspectRecord -> updDiscoverAspect c iid aspectRecord+  UpdCoverAspect c iid aspectRecord -> updCoverAspect c iid aspectRecord   UpdDiscoverServer iid aspectRecord -> updDiscoverServer iid aspectRecord   UpdCoverServer iid aspectRecord -> updCoverServer iid aspectRecord   UpdPerception _ outPer inPer ->@@ -557,30 +557,31 @@   updateLevel lid $ \lvl -> lvl {ltime = timeShift (ltime lvl) delta}  updDiscover :: MonadStateWrite m-            => Container -> ItemId -> ContentId ItemKind -> IA.ItemSeed -> m ()-updDiscover _c iid ik seed = do+            => Container -> ItemId -> ContentId ItemKind -> IA.AspectRecord+            -> m ()+updDiscover _c iid ik aspectRecord = do   itemD <- getsState sitemD   COps{coItemSpeedup} <- getsState scops   let kmIsConst = IA.kmConst $ IK.getKindMean ik coItemSpeedup   discoKind <- getsState sdiscoKind-  let discoverAtMostSeed = do+  let discoverAtMostAspect = do         discoAspect <- getsState sdiscoAspect         if kmIsConst || iid `EM.member` discoAspect         then atomicFail "item already fully discovered"-        else discoverSeed iid seed+        else discoverAspect iid aspectRecord   case EM.lookup iid itemD of     Nothing -> atomicFail "discovered item unheard of"     Just item -> case jkind item of-      IdentityObvious _ -> discoverAtMostSeed+      IdentityObvious _ -> discoverAtMostAspect       IdentityCovered ix _ik -> case EM.lookup ix discoKind of-        Just{} -> discoverAtMostSeed+        Just{} -> discoverAtMostAspect         Nothing -> do           discoverKind ix ik-          unless kmIsConst $ discoverSeed iid seed+          unless kmIsConst $ discoverAspect iid aspectRecord   resetActorAspect -updCover :: Container -> ItemId -> ContentId ItemKind -> IA.ItemSeed -> m ()-updCover _c _iid _ik _seed = undefined+updCover :: Container -> ItemId -> ContentId ItemKind -> IA.AspectRecord -> m ()+updCover _c _iid _ik _aspectRecord = undefined  updDiscoverKind :: MonadStateWrite m                 => Container -> ItemKindIx -> ContentId ItemKind -> m ()@@ -602,9 +603,9 @@ updCoverKind :: Container -> ItemKindIx -> ContentId ItemKind -> m () updCoverKind _c _ix _ik = undefined -updDiscoverSeed :: MonadStateWrite m-                => Container -> ItemId -> IA.ItemSeed -> m ()-updDiscoverSeed _c iid seed = do+updDiscoverAspect :: MonadStateWrite m+                  => Container -> ItemId -> IA.AspectRecord -> m ()+updDiscoverAspect _c iid aspectRecord = do   COps{coItemSpeedup} <- getsState scops   itemD <- getsState sitemD   case EM.lookup iid itemD of@@ -615,27 +616,21 @@       discoAspect <- getsState sdiscoAspect       let kmIsConst = IA.kmConst $ IK.getKindMean kindId coItemSpeedup       if kmIsConst || iid `EM.member` discoAspect-      then atomicFail "item seed already discovered"+      then atomicFail "item aspectRecord already discovered"       else do-        discoverSeed iid seed+        discoverAspect iid aspectRecord         resetActorAspect -discoverSeed :: MonadStateWrite m => ItemId -> IA.ItemSeed -> m ()-discoverSeed iid seed = do-  item <- getsState $ getItemBody iid-  totalDepth <- getsState stotalDepth-  Level{ldepth} <- getLevel $ jlid item-  -- Here we know the kind information is exact, hence @getItemKindServer@.-  kind <- getsState $ getItemKindServer item-  let aspects = IA.seedToAspect seed (IK.iaspects kind) ldepth totalDepth-      f Nothing = Just aspects-      f Just{} = error $ "already discovered" `showFailure` (iid, seed)+discoverAspect :: MonadStateWrite m => ItemId -> IA.AspectRecord -> m ()+discoverAspect iid aspectRecord = do+  let f Nothing = Just aspectRecord+      f Just{} = error $ "already discovered" `showFailure` (iid, aspectRecord)   -- At this point we know the item is not @kmConst@.   modifyState $ updateDiscoAspect $ \discoAspect1 ->     EM.alter f iid discoAspect1 -updCoverSeed :: Container -> ItemId -> IA.ItemSeed -> m ()-updCoverSeed _c _iid _seed = undefined+updCoverAspect :: Container -> ItemId -> IA.AspectRecord -> m ()+updCoverAspect _c _iid _aspectRecord = undefined  updDiscoverServer :: MonadStateWrite m => ItemId -> IA.AspectRecord -> m () updDiscoverServer iid aspectRecord =
Game/LambdaHack/Atomic/PosAtomicRead.hs view
@@ -136,8 +136,8 @@   UpdCover c _ _ _ -> singleContainer c   UpdDiscoverKind c _ _ -> singleContainer c   UpdCoverKind c _ _ -> singleContainer c-  UpdDiscoverSeed c _ _ -> singleContainer c-  UpdCoverSeed c _ _ -> singleContainer c+  UpdDiscoverAspect c _ _ -> singleContainer c+  UpdCoverAspect c _ _ -> singleContainer c   UpdDiscoverServer{} -> return PosSer   UpdCoverServer{} -> return PosSer   UpdPerception{} -> return PosNone
Game/LambdaHack/Client.hs view
@@ -9,12 +9,11 @@   ( -- * Re-exported from "Game.LambdaHack.Client.LoopM"     loopCli     -- * Re-exported from "Game.LambdaHack.Client.Request"-  , RequestAI, ReqAI(..), RequestUI, ReqUI(..)-  , RequestAnyAbility(..), RequestTimed(..)+  , RequestAI, ReqAI(..), RequestUI, ReqUI(..), RequestTimed(..)     -- * Re-exported from "Game.LambdaHack.Client.Response"   , Response (..)     -- * Re-exported from "Game.LambdaHack.Client.ClientOptions"-  , ClientOptions, defClientOptions, sbenchmark+  , ClientOptions(..), defClientOptions     -- * Re-exported from "Game.LambdaHack.Client.UI"   , KeyKind   , UIOptions, applyUIOptions, uCmdline, mkUIOptions
Game/LambdaHack/Client/AI.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE GADTs #-} -- | Ways for the client to use AI to produce server requests, based on -- the client's view of the game state. module Game.LambdaHack.Client.AI@@ -41,7 +40,7 @@   (aidToMove, treq, oldFlee) <- pickActorAndAction Nothing aid   (aidToMove2, treq2) <-     case treq of-      RequestAnyAbility ReqWait | mleader == Just aid -> do+      ReqWait | mleader == Just aid -> do         -- Leader waits; a waste; try once to pick a yet different leader.         -- Undo state changes in @pickAction@:         modifyClient $ \cli -> cli@@ -58,8 +57,8 @@ -- | Pick an actor to move and an action for him to perform, given an optional -- previous candidate actor and action and the server-proposed actor. pickActorAndAction :: MonadClient m-                   => Maybe (ActorId, RequestAnyAbility) -> ActorId-                   -> m (ActorId, RequestAnyAbility, Maybe Point)+                   => Maybe (ActorId, RequestTimed) -> ActorId+                   -> m (ActorId, RequestTimed, Maybe Point) -- This inline speeds up execution by 15% and decreases allocation by 15%, -- despite probably bloating executable: {-# INLINE pickActorAndAction #-}
Game/LambdaHack/Client/AI/HandleAbilityM.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE DataKinds #-} -- | AI procedure for picking the best action for an actor. module Game.LambdaHack.Client.AI.HandleAbilityM   ( pickAction@@ -8,7 +7,7 @@   , waitBlockNow, pickup, equipItems, toShare, yieldUnneeded, unEquipItems   , groupByEqpSlot, bestByEqpSlot, harmful, meleeBlocker, meleeAny   , trigger, projectItem, ApplyItemGroup, applyItem, flee-  , displaceFoe, displaceBlocker, displaceTowards+  , displaceFoe, displaceBlocker, displaceTgt   , chase, moveTowards, moveOrRunAid #endif   ) where@@ -56,7 +55,7 @@ import           Game.LambdaHack.Content.ModeKind  -- | Pick the most desirable AI ation for the actor.-pickAction :: MonadClient m => ActorId -> Bool -> m RequestAnyAbility+pickAction :: MonadClient m => ActorId -> Bool -> m RequestTimed {-# INLINE pickAction #-} pickAction aid retry = do   side <- getsClient sside@@ -77,15 +76,10 @@   -- Run the AI: chose an action from those given by the AI strategy.   rndToAction $ frequency bestAction -type ToAny a = Strategy (RequestTimed a) -> Strategy RequestAnyAbility--toAny :: ToAny a-toAny strat = RequestAnyAbility <$> strat- -- AI strategy based on actor's sight, smell, etc. -- Never empty. actionStrategy :: forall m. MonadClient m-               => ActorId -> Bool -> m (Strategy RequestAnyAbility)+               => ActorId -> Bool -> m (Strategy RequestTimed) {-# INLINE actionStrategy #-} actionStrategy aid retry = do   body <- getsState $ getActorBody aid@@ -136,8 +130,10 @@       canFleeFromLight = not $ null $ aCanDeLightL `intersect` map snd fleeL       actorMaxSk = IA.aSkills ar       abInMaxSkill ab = EM.findWithDefault 0 ab actorMaxSk > 0-      stratToFreq :: Int -> m (Strategy RequestAnyAbility)-                  -> m (Frequency RequestAnyAbility)+      runSkills = [AbMove, AbDisplace, AbAlter]+      stratToFreq :: Int+                  -> m (Strategy RequestTimed)+                  -> m (Frequency RequestTimed)       stratToFreq scale mstrat = do         st <- mstrat         return $! if scale == 0@@ -146,13 +142,13 @@       -- Order matters within the list, because it's summed with .| after       -- filtering. Also, the results of prefix, distant and suffix       -- are summed with .| at the end.-      prefix, suffix :: [([Ability], m (Strategy RequestAnyAbility), Bool)]+      prefix, suffix :: [([Ability], m (Strategy RequestTimed), Bool)]       prefix =-        [ ( [AbApply], (toAny :: ToAny 'AbApply)-            <$> applyItem aid ApplyFirstAid+        [ ( [AbApply]+          , applyItem aid ApplyFirstAid           , not condAnyFoeAdj && condHpTooLow)-        , ( [AbAlter], (toAny :: ToAny 'AbAlter)-            <$> trigger aid ViaStairs+        , ( [AbAlter]+          , trigger aid ViaStairs               -- explore next or flee via stairs, even if to wrong level;               -- in the latter case, may return via different stairs later on           , condAdjTriggerable && not condAimEnemyPresent@@ -163,16 +159,16 @@         , ( [AbDisplace]           , displaceFoe aid  -- only swap with an enemy to expose him           , condAnyFoeAdj && condBlocksFriends)  -- later checks foe eligible-        , ( [AbMoveItem], (toAny :: ToAny 'AbMoveItem)-            <$> pickup aid True+        , ( [AbMoveItem]+          , pickup aid True           , condNoEqpWeapon  -- we assume organ weapons usually inferior             && condFloorWeapon && not condHpTooLow             && abInMaxSkill AbMelee )-        , ( [AbAlter], (toAny :: ToAny 'AbAlter)-            <$> trigger aid ViaEscape+        , ( [AbAlter]+          , trigger aid ViaEscape           , condAdjTriggerable && not condAimEnemyPresent             && not condDesirableFloorItem )  -- collect the last loot-        , ( [AbMove]+        , ( runSkills           , flee aid fleeL           , -- Flee either from melee, if our melee is bad and enemy close             -- or from missiles, if hit and enemies are only far away,@@ -200,24 +196,24 @@                     not condInMelee                     && heavilyDistressed                     && (not condCanProject || canFleeFromLight) )-        , ( [AbMelee], (toAny :: ToAny 'AbMelee)-            <$> meleeBlocker aid  -- only melee blocker+        , ( [AbMelee]+          , meleeBlocker aid  -- only melee blocker           , condAnyFoeAdj  -- if foes, don't displace, otherwise friends:             || not (abInMaxSkill AbDisplace)  -- displace friends, if possible                && condAimEnemyPresent )  -- excited                     -- So animals block each other until hero comes and then                     -- the stronger makes a show for him and kills the weaker.-        , ( [AbAlter], (toAny :: ToAny 'AbAlter)-            <$> trigger aid ViaNothing+        , ( [AbAlter]+          , trigger aid ViaNothing           , not condInMelee  -- don't incur overhead             && condAdjTriggerable && not condAimEnemyPresent )         , ( [AbDisplace]  -- prevents some looping movement           , displaceBlocker aid retry  -- fires up only when path blocked           , retry || not condDesirableFloorItem )-        , ( [AbMelee], (toAny :: ToAny 'AbMelee)-            <$> meleeAny aid+        , ( [AbMelee]+          , meleeAny aid           , condAnyFoeAdj )  -- won't flee nor displace, so let it melee-        , ( [AbMove]+        , ( runSkills           , flee aid panicFleeL  -- ultimate panic mode, displaces foes           , condAnyFoeAdj )         ]@@ -226,16 +222,15 @@       -- so if any of these can fire, it will fire. If none, @suffix@ is tried.       -- Only the best variant of @chase@ is taken, but it's almost always       -- good, and if not, the @chase@ in @suffix@ may fix that.-      distant :: [([Ability], m (Frequency RequestAnyAbility), Bool)]+      distant :: [([Ability], m (Frequency RequestTimed), Bool)]       distant =         [ ( [AbMoveItem]           , stratToFreq (if condInMelee then 2 else 20000)-            $ (toAny :: ToAny 'AbMoveItem)-            <$> yieldUnneeded aid  -- 20000 to unequip ASAP, unless is thrown+            $ yieldUnneeded aid  -- 20000 to unequip ASAP, unless is thrown           , True )         , ( [AbMoveItem]-          , stratToFreq 1 $ (toAny :: ToAny 'AbMoveItem)-            <$> equipItems aid  -- doesn't take long, very useful if safe+          , stratToFreq 1+            $ equipItems aid  -- doesn't take long, very useful if safe           , not (condInMelee                  || condDesirableFloorItem                  || condNotCalmEnough@@ -243,14 +238,13 @@         , ( [AbProject]           , stratToFreq (if condTgtNonmoving then 20 else 3)               -- not too common, to leave missiles for pre-melee dance-            $ (toAny :: ToAny 'AbProject)-            <$> projectItem aid  -- equivalent of @condCanProject@ called inside+            $ projectItem aid  -- equivalent of @condCanProject@ called inside           , condAimEnemyPresent && not condInMelee )         , ( [AbApply]-          , stratToFreq 1 $ (toAny :: ToAny 'AbApply)-            <$> applyItem aid ApplyAll  -- use any potion or scroll+          , stratToFreq 1+            $ applyItem aid ApplyAll  -- use any potion or scroll           , condAimEnemyPresent || condThreat 9 )  -- can affect enemies-        , ( [AbMove]+        , ( runSkills           , stratToFreq (if | condInMelee ->                               400  -- friends pummeled by target, go to help                             | not condAimEnemyPresent ->@@ -275,13 +269,13 @@         ]       -- Order matters again.       suffix =-        [ ( [AbMoveItem], (toAny :: ToAny 'AbMoveItem)-            <$> pickup aid False  -- e.g., to give to other party members+        [ ( [AbMoveItem]+          , pickup aid False  -- e.g., to give to other party members           , not condInMelee )-        , ( [AbMoveItem], (toAny :: ToAny 'AbMoveItem)-            <$> unEquipItems aid  -- late, because these items not bad+        , ( [AbMoveItem]+          , unEquipItems aid  -- late, because these items not bad           , not condInMelee )-        , ( [AbMove]+        , ( runSkills           , chase aid (not condInMelee                        && heavilyDistressed                        && aCanDeLight) retry@@ -289,8 +283,8 @@             else not (condThreat 2) || not condMeleeBad )         ]       fallback =-        [ ( [AbWait], (toAny :: ToAny 'AbWait)-            <$> waitBlockNow+        [ ( [AbWait]+          , waitBlockNow             -- Wait until friends sidestep; ensures strategy is never empty.           , True )         ]@@ -298,7 +292,7 @@   -- as non-leader action.   let abInSkill ab = EM.findWithDefault 0 ab actorSk > 0       checkAction :: ([Ability], m a, Bool) -> Bool-      checkAction (abts, _, cond) = all abInSkill abts && cond+      checkAction (abts, _, cond) = any abInSkill abts && cond       sumS abAction = do         let as = filter checkAction abAction         strats <- mapM (\(_, m, _) -> m) as@@ -314,11 +308,10 @@   sumFallback <- sumS fallback   return $! sumPrefix .| comDistant .| sumSuffix .| sumFallback -waitBlockNow :: MonadClient m => m (Strategy (RequestTimed 'AbWait))+waitBlockNow :: MonadClient m => m (Strategy RequestTimed) waitBlockNow = return $! returN "wait" ReqWait -pickup :: MonadClient m-       => ActorId -> Bool -> m (Strategy (RequestTimed 'AbMoveItem))+pickup :: MonadClient m => ActorId -> Bool -> m (Strategy RequestTimed) pickup aid onlyWeapon = do   benItemL <- benGroundItems aid   b <- getsState $ getActorBody aid@@ -356,8 +349,7 @@ -- and with @inEqp@ (which implies @goesIntoEqp@). -- Such items are moved between any stores, as needed. In this case, -- from inv or sha to eqp.-equipItems :: MonadClient m-           => ActorId -> m (Strategy (RequestTimed 'AbMoveItem))+equipItems :: MonadClient m => ActorId -> m (Strategy RequestTimed) equipItems aid = do   body <- getsState $ getActorBody aid   ar <- getsState $ getActorAspect aid@@ -421,8 +413,7 @@ toShare IA.EqpSlotMiscAbility = False toShare _ = True -yieldUnneeded :: MonadClient m-              => ActorId -> m (Strategy (RequestTimed 'AbMoveItem))+yieldUnneeded :: MonadClient m => ActorId -> m (Strategy RequestTimed) yieldUnneeded aid = do   body <- getsState $ getActorBody aid   ar <- getsState $ getActorAspect aid@@ -457,8 +448,7 @@ -- and with @inEqp@ (which implies @goesIntoEqp@). -- Such items are moved between any stores, as needed. In this case, -- from inv or eqp to sha.-unEquipItems :: MonadClient m-             => ActorId -> m (Strategy (RequestTimed 'AbMoveItem))+unEquipItems :: MonadClient m => ActorId -> m (Strategy RequestTimed) unEquipItems aid = do   body <- getsState $ getActorBody aid   ar <- getsState $ getActorAspect aid@@ -561,7 +551,7 @@   not $ benInEqp $ discoBenefit EM.! iid  -- Everybody melees in a pinch, even though some prefer ranged attacks.-meleeBlocker :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMelee))+meleeBlocker :: MonadClient m => ActorId -> m (Strategy RequestTimed) meleeBlocker aid = do   b <- getsState $ getActorBody aid   actorAspect <- getsState sactorAspect@@ -588,8 +578,8 @@           -- No problem if there are many projectiles at the spot. We just           -- attack the first one.           if | actorDying body2-               || bproj body2  -- displacing saves a move-                  && EM.findWithDefault 0 AbDisplace actorSk <= 0 ->+               || bproj body2  -- displacing saves a move, so don't melee+                  && EM.findWithDefault 0 AbDisplace actorSk > 0 ->                return reject              | isFoe (bfid b) fact (bfid body2)                  -- at war with us, so hit, not displace@@ -606,7 +596,7 @@  -- Everybody melees in a pinch, skills and weapons allowing, -- even though some prefer ranged attacks.-meleeAny :: MonadClient m => ActorId -> m (Strategy (RequestTimed 'AbMelee))+meleeAny :: MonadClient m => ActorId -> m (Strategy RequestTimed) meleeAny aid = do   b <- getsState $ getActorBody aid   fact <- getsState $ (EM.! bfid b) . sfactionD@@ -634,7 +624,7 @@ -- the actor doesn't target a visible enemy at this point. trigger :: MonadClient m         => ActorId -> FleeViaStairsOrEscape-        -> m (Strategy (RequestTimed 'AbAlter))+        -> m (Strategy RequestTimed) trigger aid fleeVia = do   b <- getsState $ getActorBody aid   lvl <- getLevel (blid b)@@ -647,8 +637,7 @@     [ (ceiling benefit, ReqAlter pos)     | (benefit, (pos, _)) <- efeat ] -projectItem :: MonadClient m-            => ActorId -> m (Strategy (RequestTimed 'AbProject))+projectItem :: MonadClient m => ActorId -> m (Strategy RequestTimed) projectItem aid = do   btarget <- getsClient $ getTarget aid   b <- getsState $ getActorBody aid@@ -698,7 +687,7 @@   deriving Eq  applyItem :: MonadClient m-          => ActorId -> ApplyItemGroup -> m (Strategy (RequestTimed 'AbApply))+          => ActorId -> ApplyItemGroup -> m (Strategy RequestTimed) applyItem aid applyGroup = do   actorSk <- currentSkillsClient aid   b <- getsState $ getActorBody aid@@ -796,7 +785,7 @@ -- and as far from the attackers, as possible. Usually fleeing from -- foes will lead towards friends, but we don't insist on that. flee :: MonadClient m-     => ActorId -> [(Int, Point)] -> m (Strategy RequestAnyAbility)+     => ActorId -> [(Int, Point)] -> m (Strategy RequestTimed) flee aid fleeL = do   b <- getsState $ getActorBody aid   -- Regardless if fleeing accomplished, mark the need.@@ -807,7 +796,7 @@  -- The result of all these conditions is that AI displaces rarely, -- but it can't be helped as long as the enemy is smart enough to form fronts.-displaceFoe :: MonadClient m => ActorId -> m (Strategy RequestAnyAbility)+displaceFoe :: MonadClient m => ActorId -> m (Strategy RequestTimed) displaceFoe aid = do   COps{coTileSpeedup} <- getsState scops   b <- getsState $ getActorBody aid@@ -815,11 +804,13 @@   fact <- getsState $ (EM.! bfid b) . sfactionD   friends <- getsState $ friendRegularList (bfid b) (blid b)   adjacentAssocs <- getsState $ actorAdjacentAssocs b-  let foe (_, b2) =-        not (bproj b2) && isFoe (bfid b) fact (bfid b2) && bhp b2 > 0+  let foe (_, b2) = not (bproj b2) && isFoe (bfid b) fact (bfid b2)+        -- DisplaceProjectiles       adjFoes = filter foe adjacentAssocs-      displaceable body =  -- DisplaceAccess-        Tile.isWalkable coTileSpeedup (lvl `at` bpos body)+      walkable p =  -- DisplaceAccess+        Tile.isWalkable coTileSpeedup (lvl `at` p)+      notLooping body p =  -- avoid displace loops+        boldpos body /= Just p || waitedLastTurn body       nFriends body = length $ filter (adjacent (bpos body) . bpos) friends       nFrNew = nFriends b + 1       qualifyActor (aid2, body2) = do@@ -827,40 +818,40 @@         dEnemy <- getsState $ dispEnemy aid aid2 actorMaxSk           -- DisplaceDying, DisplaceBraced, DisplaceImmobile, DisplaceSupported         let nFrOld = nFriends body2-        return $! if displaceable body2 && dEnemy && nFrOld < nFrNew-                  then Just (nFrOld * nFrOld, bpos body2 `vectorToFrom` bpos b)+        return $! if walkable (bpos body2) && dEnemy && nFrOld < nFrNew+                     && notLooping b (bpos body2)+                  then Just (nFrOld * nFrOld, ReqDisplace aid2)                   else Nothing-  vFoes <- mapM qualifyActor adjFoes-  let str = liftFrequency $ toFreq "displaceFoe" $ catMaybes vFoes-  mapStrategyM (moveOrRunAid aid) str+  foes <- mapM qualifyActor adjFoes+  return $! liftFrequency $ toFreq "displaceFoe" $ catMaybes foes -displaceBlocker :: MonadClient m-                => ActorId -> Bool -> m (Strategy RequestAnyAbility)+displaceBlocker :: MonadClient m => ActorId -> Bool -> m (Strategy RequestTimed) displaceBlocker aid retry = do   b <- getsState $ getActorBody aid   mtgtMPath <- getsClient $ EM.lookup aid . stargetD-  str <- case mtgtMPath of+  case mtgtMPath of     Just TgtAndPath{ tapTgt=TEnemy{}                    , tapPath=AndPath{pathList=q : _, pathGoal} }       | q == pathGoal && not retry ->         return reject  -- not a real blocker but goal, possibly enemy to melee     Just TgtAndPath{tapPath=AndPath{pathList=q : _}}       | adjacent (bpos b) q ->  -- not veered off target-      displaceTowards aid q retry+      displaceTgt aid q retry     _ -> return reject  -- goal reached-  mapStrategyM (moveOrRunAid aid) str -displaceTowards :: MonadClient m-                => ActorId -> Point -> Bool -> m (Strategy Vector)-displaceTowards aid target retry = do+displaceTgt :: MonadClient m+            => ActorId -> Point -> Bool -> m (Strategy RequestTimed)+displaceTgt aid target retry = do   COps{coTileSpeedup} <- getsState scops   b <- getsState $ getActorBody aid   let source = bpos b   let !_A = assert (adjacent source target) ()   lvl <- getLevel $ blid b-  if boldpos b /= Just target -- avoid trivial loops-     && Tile.isWalkable coTileSpeedup (lvl `at` target) then do-       -- DisplaceAccess+  let walkable p =  -- DisplaceAccess+        Tile.isWalkable coTileSpeedup (lvl `at` p)+      notLooping body p =  -- avoid displace loops+        boldpos body /= Just p || waitedLastTurn body+  if walkable target && notLooping b target then do     mleader <- getsClient sleader     mBlocker <- getsState $ posToAssocs target (blid b)     case mBlocker of@@ -881,20 +872,21 @@                  -- he doesn't have Enemy target and I have, so push him aside,                  -- because, for heroes, he will never be a leader, so he can't                  -- step aside himself-              return $! returN "displace friend" $ target `vectorToFrom` source+              return $! returN "displace friend" $ ReqDisplace aid2           Just _ -> return reject           Nothing -> do  -- an enemy or ally or disoriented friend --- swap             tfact <- getsState $ (EM.! bfid b2) . sfactionD             actorMaxSk <- maxActorSkillsClient aid2             dEnemy <- getsState $ dispEnemy aid aid2 actorMaxSk+              -- DisplaceDying, DisplaceBraced, DisplaceImmobile,+              -- DisplaceSupported             if not (isFoe (bfid b2) tfact (bfid b)) || dEnemy then-              return $! returN "displace other" $ target `vectorToFrom` source-            else return reject  -- DisplaceDying, etc.+              return $! returN "displace other" $ ReqDisplace aid2+            else return reject       _ -> return reject  -- DisplaceProjectiles or trying to displace leader   else return reject -chase :: MonadClient m-      => ActorId -> Bool -> Bool -> m (Strategy RequestAnyAbility)+chase :: MonadClient m => ActorId -> Bool -> Bool -> m (Strategy RequestTimed) chase aid avoidAmbient retry = do   COps{coTileSpeedup} <- getsState scops   body <- getsState $ getActorBody aid@@ -955,15 +947,17 @@ -- Actor moves or searches or alters or attacks. -- This function is very general, even though it's often used in contexts -- when only one or two of the many cases can possibly occur.-moveOrRunAid :: MonadClient m-             => ActorId -> Vector -> m (Maybe RequestAnyAbility)+moveOrRunAid :: MonadClient m => ActorId -> Vector -> m (Maybe RequestTimed) moveOrRunAid source dir = do   COps{coTileSpeedup} <- getsState scops   sb <- getsState $ getActorBody source   actorSk <- currentSkillsClient source   let lid = blid sb   lvl <- getLevel lid-  let alterSkill = EM.findWithDefault 0 AbAlter actorSk+  let walkable =  -- DisplaceAccess+        Tile.isWalkable coTileSpeedup (lvl `at` tpos)+      notLooping body p =  -- avoid displace loops+        boldpos body /= Just p || waitedLastTurn body       spos = bpos sb           -- source position       tpos = spos `shift` dir  -- target position       t = lvl `at` tpos@@ -973,44 +967,27 @@   -- (tiles can't be invisible).   tgts <- getsState $ posToAssocs tpos lid   case tgts of-    [(target, b2)] -> do+    [(target, b2)] | walkable+                     && EM.findWithDefault 0 AbDisplace actorSk > 0+                     && notLooping sb tpos -> do       -- @target@ can be a foe, as well as a friend.       tfact <- getsState $ (EM.! bfid b2) . sfactionD       actorMaxSk <- maxActorSkillsClient target       dEnemy <- getsState $ dispEnemy source target actorMaxSk-      if | boldpos sb == Just tpos && not (waitedLastTurn sb)-             -- avoid displace loops-           || not (Tile.isWalkable coTileSpeedup $ lvl `at` tpos) ->-             -- DisplaceAccess-           return Nothing-         | isFoe (bfid b2) tfact (bfid sb)-           && not dEnemy -> do  -- DisplaceDying, etc.-           -- If really can't displace, melee.-           wps <- pickWeaponClient source target-           case wps of-             Nothing -> return Nothing-             Just wp -> return $ Just $ RequestAnyAbility wp-         | otherwise ->-           return $ Just $ RequestAnyAbility $ ReqDisplace target-    (target, _) : _ -> do  -- can be a foe, as well as friend (e.g., projectile)-      -- If really can't displace, melee.-      -- No problem if there are many projectiles at the spot. We just-      -- attack the first one.-      -- Attacking does not require full access, adjacency is enough.-      wps <- pickWeaponClient source target-      case wps of-        Nothing -> return Nothing-        Just wp -> return $ Just $ RequestAnyAbility wp-    [] -- move or search or alter-       | Tile.isWalkable coTileSpeedup $ lvl `at` tpos ->-         -- Movement requires full access.-         return $ Just $ RequestAnyAbility $ ReqMove dir-         -- The potential invisible actor is hit.-       | alterSkill < Tile.alterMinWalk coTileSpeedup t ->-         error $ "AI causes AlterUnwalked" `showFailure` (source, dir)-       | EM.member tpos $ lfloor lvl ->-         -- Only possible if items allowed inside unwalkable tiles.-         error $ "AI causes AlterBlockItem" `showFailure` (source, dir)-       | otherwise ->-         -- Not walkable, but alter skill suffices, so search or alter the tile.-         return $ Just $ RequestAnyAbility $ ReqAlter tpos+        -- DisplaceDying, DisplaceBraced, DisplaceImmobile, DisplaceSupported+      if isFoe (bfid b2) tfact (bfid sb) && not dEnemy+      then return Nothing+      else return $ Just $ ReqDisplace target+    [] | walkable && EM.findWithDefault 0 AbMove actorSk > 0 ->+      -- Movement requires full access. The potential invisible actor is hit.+      return $ Just $ ReqMove dir+    [] | not walkable+         && EM.findWithDefault 0 AbAlter actorSk+              >= Tile.alterMinWalk coTileSpeedup t  -- AlterUnwalked+         -- Only possible if items allowed inside unwalkable tiles:+         && EM.notMember tpos (lfloor lvl) ->  -- AlterBlockItem+      -- Not walkable, but alter skill suffices, so search or alter the tile.+      -- We assume that unalterable unwalkable tiles are protected+      -- by high skill req. We don't alter walkable tiles (e.g., close doors).+      return $ Just $ ReqAlter tpos+    _ -> return Nothing  -- can't displace, move nor alter
Game/LambdaHack/Client/CommonM.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE DataKinds #-} -- | Common client monad operations. module Game.LambdaHack.Client.CommonM   ( getPerFid, aidTgtToPos, makeLine@@ -136,7 +135,7 @@ -- primitive and random here as well. pickWeaponClient :: MonadClient m                  => ActorId -> ActorId-                 -> m (Maybe (RequestTimed 'Ability.AbMelee))+                 -> m (Maybe RequestTimed) pickWeaponClient source target = do   eqpAssocs <- getsState $ kitAssocs source [CEqp]   bodyAssocs <- getsState $ kitAssocs source [COrgan]
Game/LambdaHack/Client/HandleAtomicM.hs view
@@ -6,7 +6,7 @@     -- * Internal operations   , wipeBfsIfItemAffectsSkills, tileChangeAffectsBfs, createActor, destroyActor   , addItemToDiscoBenefit, perception-  , discoverKind, coverKind, discoverSeed, coverSeed+  , discoverKind, coverKind, discoverAspect, coverAspect   , killExit #endif   ) where@@ -148,7 +148,7 @@   UpdLoseTile lid ts -> do     updateSalter lid ts     invalidateBfsLid lid  -- from known to unknown tiles-  UpdDiscover c iid ik seed -> do+  UpdDiscover c iid ik aspectRecord -> do     item <- getsState $ getItemBody iid     discoKind <- getsState sdiscoKind     case jkind item of@@ -156,9 +156,9 @@       IdentityCovered ix _ik | ix `EM.notMember` discoKind ->         discoverKind c ix ik       IdentityCovered _ix _ik -> return ()-    discoverSeed c iid seed-  UpdCover c iid ik seed -> do-    coverSeed c iid seed+    discoverAspect c iid aspectRecord+  UpdCover c iid ik aspectRecord -> do+    coverAspect c iid aspectRecord     item <- getsState $ getItemBody iid     discoKind <- getsState sdiscoKind     case jkind item of@@ -168,8 +168,8 @@       IdentityCovered _ix _ik -> return ()   UpdDiscoverKind c ix ik -> discoverKind c ix ik   UpdCoverKind c ix ik -> coverKind c ix ik-  UpdDiscoverSeed c iid seed -> discoverSeed c iid seed-  UpdCoverSeed c iid seed -> coverSeed c iid seed+  UpdDiscoverAspect c iid aspectRecord -> discoverAspect c iid aspectRecord+  UpdCoverAspect c iid aspectRecord -> coverAspect c iid aspectRecord   UpdPerception lid outPer inPer -> perception lid outPer inPer   UpdRestart side sfper s scurChal soptions -> do     COps{cocave, comode} <- getsState scops@@ -276,8 +276,9 @@   cops <- getsState scops   discoBenefit <- getsClient sdiscoBenefit   case EM.lookup iid discoBenefit of-    Just{} -> return ()  -- already there, with real or provisional aspects,-                         -- but we haven't learned anything new about the item+    Just{} -> return ()+      -- already there, with real or provisional aspect record,+      -- but we haven't learned anything new about the item     Nothing -> do       side <- getsClient sside       fact <- getsState $ (EM.! side) . sfactionD@@ -332,8 +333,9 @@ coverKind :: Container -> ItemKindIx -> ContentId ItemKind -> m () coverKind _c _ix _ik = undefined -discoverSeed :: MonadClient m => Container -> ItemId -> IA.ItemSeed -> m ()-discoverSeed _c iid _seed = do+discoverAspect :: MonadClient m+               => Container -> ItemId -> IA.AspectRecord -> m ()+discoverAspect _c iid _aspectRecord = do   cops <- getsState scops   -- Wipe out BFS, because the player could potentially learn that his items   -- affect his actors' skills relevant to BFS.@@ -346,8 +348,8 @@   modifyClient $ \cli ->     cli {sdiscoBenefit = EM.insert iid benefit (sdiscoBenefit cli)} -coverSeed :: Container -> ItemId -> IA.ItemSeed -> m ()-coverSeed _c _iid _seed = undefined+coverAspect :: Container -> ItemId -> IA.AspectRecord -> m ()+coverAspect _c _iid _aspectRecord = undefined  killExit :: MonadClient m => m () killExit = do
Game/LambdaHack/Client/Request.hs view
@@ -1,18 +1,15 @@-{-# LANGUAGE DataKinds, GADTs, KindSignatures, StandaloneDeriving #-} -- | Abstract syntax of requests. -- -- See -- <https://github.com/LambdaHack/LambdaHack/wiki/Client-server-architecture>. module Game.LambdaHack.Client.Request-  ( RequestAI, ReqAI(..), RequestUI, ReqUI(..)-  , RequestAnyAbility(..), RequestTimed(..)+  ( RequestAI, ReqAI(..), RequestUI, ReqUI(..), RequestTimed(..)   ) where  import Prelude ()  import Game.LambdaHack.Common.Prelude -import Game.LambdaHack.Common.Ability import Game.LambdaHack.Common.Actor import Game.LambdaHack.Common.Faction import Game.LambdaHack.Common.Item@@ -28,7 +25,7 @@ -- | Possible forms of requests sent by AI clients. data ReqAI =     ReqAINop-  | ReqAITimed RequestAnyAbility+  | ReqAITimed RequestTimed   deriving Show  -- | Requests sent by UI clients to the server. If faction leader is to be@@ -38,7 +35,7 @@ -- | Possible forms of requests sent by UI clients. data ReqUI =     ReqUINop-  | ReqUITimed RequestAnyAbility+  | ReqUITimed RequestTimed   | ReqUIGameRestart (GroupName ModeKind) Challenge   | ReqUIGameDropAndExit   | ReqUIGameSaveAndExit@@ -47,22 +44,16 @@   | ReqUIAutomate   deriving Show --- | Basic form of requests, sent by both AI and UI clients to the server.-data RequestAnyAbility = forall a. RequestAnyAbility (RequestTimed a)--deriving instance Show RequestAnyAbility- -- | Requests that take game time, indexed by actor ability -- that is needed for performing the corresponding actions.-data RequestTimed :: Ability -> * where-  ReqMove :: Vector -> RequestTimed 'AbMove-  ReqMelee :: ActorId -> ItemId -> CStore -> RequestTimed 'AbMelee-  ReqDisplace :: ActorId -> RequestTimed 'AbDisplace-  ReqAlter :: Point -> RequestTimed 'AbAlter-  ReqWait :: RequestTimed 'AbWait-  ReqWait10 :: RequestTimed 'AbWait-  ReqMoveItems :: [(ItemId, Int, CStore, CStore)] -> RequestTimed 'AbMoveItem-  ReqProject :: Point -> Int -> ItemId -> CStore -> RequestTimed 'AbProject-  ReqApply :: ItemId -> CStore -> RequestTimed 'AbApply--deriving instance Show (RequestTimed a)+data RequestTimed =+    ReqMove Vector+  | ReqMelee ActorId ItemId CStore+  | ReqDisplace ActorId+  | ReqAlter Point+  | ReqWait+  | ReqWait10+  | ReqMoveItems [(ItemId, Int, CStore, CStore)]+  | ReqProject Point Int ItemId CStore+  | ReqApply ItemId CStore+  deriving Show
Game/LambdaHack/Client/UI/DisplayAtomicM.hs view
@@ -296,8 +296,8 @@   UpdCover{} -> return ()  -- don't spam when doing undo   UpdDiscoverKind{} -> return ()  -- don't spam when server tweaks stuff   UpdCoverKind{} -> return ()  -- don't spam when doing undo-  UpdDiscoverSeed{} -> return ()  -- don't spam when server tweaks stuff-  UpdCoverSeed{} -> return ()  -- don't spam when doing undo+  UpdDiscoverAspect{} -> return ()  -- don't spam when server tweaks stuff+  UpdCoverAspect{} -> return ()  -- don't spam when doing undo   UpdDiscoverServer{} -> error "server command leaked to client"   UpdCoverServer{} -> error "server command leaked to client"   UpdPerception{} -> return ()
Game/LambdaHack/Client/UI/DrawM.hs view
@@ -270,12 +270,11 @@  drawFrameActor :: forall m. MonadClientUI m => LevelId -> m FrameForall drawFrameActor drawnLevelId = do-  SessionUI{sselected} <- getSession+  SessionUI{sactorUI, sselected, sUIOptions} <- getSession   Level{lxsize, lactor} <- getLevel drawnLevelId   side <- getsClient sside   mleader <- getsClient sleader   s <- getState-  sactorUI <- getsSession sactorUI   let {-# INLINE viewActor #-}       viewActor _ as = case as of         aid : _ ->@@ -292,8 +291,14 @@                                        then Color.HighlightWhite                                        else Color.HighlightMagenta                         | otherwise -> Color.HighlightNone-          in Color.attrCharToW32-             $ Color.AttrChar Color.Attr{fg=bcolor, bg} symbol+              fg | bfid /= side || bproj || bhp <= 0 = bcolor+                 | otherwise =+                let (hpCheckWarning, calmCheckWarning) =+                      checkWarnings sUIOptions aid s+                in if hpCheckWarning || calmCheckWarning+                   then Color.Red+                   else bcolor+         in Color.attrCharToW32 $ Color.AttrChar Color.Attr{..} symbol         [] -> error $ "lactor not sparse" `showFailure` ()       mapVAL :: forall a s. (Point -> a -> Color.AttrCharW32) -> [(Point, a)]              -> FrameST s@@ -501,29 +506,36 @@               $ T.take 29 (lvlN <+> T.justifyLeft 26 ' ' (cname ck))                 <+> seenStatus +checkWarnings :: UIOptions -> ActorId -> State -> (Bool, Bool)+checkWarnings UIOptions{uhpWarningPercent} leader s =+  let b = getActorBody leader s+      ar = getActorAspect leader s+      isImpression iid =+        maybe False (> 0) $ lookup "impressed" $ IK.ifreq $ getIidKind iid s+      isImpressed = any isImpression $ EM.keys $ borgan b+      hpCheckWarning = bhp b <= xM (uhpWarningPercent * IA.aMaxHP ar `div` 100)+      calmCheckWarning =+        bcalm b <= xM (uhpWarningPercent * IA.aMaxCalm ar `div` 100)+        && isImpressed+  in (hpCheckWarning, calmCheckWarning)+ drawLeaderStatus :: MonadClientUI m => Int -> m AttrLine drawLeaderStatus waitT = do   let calmHeaderText = "Calm"       hpHeaderText = "HP"-  UIOptions{uhpWarningPercent} <- getsSession sUIOptions+  sUIOptions <- getsSession sUIOptions   mleader <- getsClient sleader   case mleader of     Just leader -> do+      b <- getsState $ getActorBody leader       ar <- getsState $ getActorAspect leader-      s <- getState+      (hpCheckWarning, calmCheckWarning)+        <- getsState $ checkWarnings sUIOptions leader+      bdark <- getsState $ \s -> not (actorInAmbient b s)       let showTrunc x = let t = show x                         in if length t > 3                            then if x > 0 then "***" else "---"                            else t-          (bhpM, darkL, bracedL, hpDelta, calmDelta,-           ahpS, bhpS, acalmS, bcalmS) =-            let b@Actor{bhp, bcalm} = getActorBody leader s-            in ( bhp, not (actorInAmbient b s)-               , braced b, bhpDelta b, bcalmDelta b-               , showTrunc $ max 0 $ IA.aMaxHP ar-               , showTrunc (bhp `divUp` oneM)-               , showTrunc $ max 0 $ IA.aMaxCalm ar-               , showTrunc (bcalm `divUp` oneM))           -- This is a valuable feedback for the otherwise hard to observe           -- 'wait' command.           slashes = ["/", "|", "\\", "|"]@@ -535,30 +547,33 @@             | snd resCurrentTurn > 0 || snd resPreviousTurn > 0               = addColor Color.BrGreen             | otherwise = stringToAL  -- only if nothing at all noteworthy-          checkWarning =-            if bhpM <= xM (uhpWarningPercent * IA.aMaxHP ar `div` 100)-            then addColor Color.Red-            else stringToAL-          calmAddAttr = checkDelta calmDelta+          calmAddAttr = checkDelta $ bcalmDelta b           -- We only show ambient light, because in fact client can't tell           -- if a tile is lit, because it it's seen it may be due to ambient           -- or dynamic light or due to infravision.-          darkPick | darkL   = "."+          darkPick | bdark = "."                    | otherwise = ":"           calmHeader = calmAddAttr $ calmHeaderText <> darkPick-          calmText = bcalmS <> (if darkL || not bracedL-                                then slashPick-                                else "/") <> acalmS-          bracePick | bracedL   = "}"+          calmText = showTrunc (bcalm b `divUp` oneM)+                     <> (if bdark || not (braced b)+                         then slashPick+                         else "/")+                     <> showTrunc (max 0 $ IA.aMaxCalm ar)+          bracePick | braced b  = "}"                     | otherwise = ":"-          hpAddAttr = checkDelta hpDelta+          hpAddAttr = checkDelta $ bhpDelta b           hpHeader = hpAddAttr $ hpHeaderText <> bracePick-          hpText = bhpS <> (if bracedL || not darkL-                            then slashPick-                            else "/") <> ahpS+          hpText = showTrunc (bhp b `divUp` oneM)+                   <> (if braced b || not bdark+                       then slashPick+                       else "/")+                   <> showTrunc (max 0 $ IA.aMaxHP ar)           justifyRight n t = replicate (n - length t) ' ' ++ t-      return $! calmHeader <> stringToAL (justifyRight 7 calmText)-                <+:> hpHeader <> checkWarning (justifyRight 7 hpText)+          colorWarning w = if w then addColor Color.Red else stringToAL+      return $! calmHeader+                <> colorWarning calmCheckWarning (justifyRight 7 calmText)+                <+:> hpHeader+                <> colorWarning hpCheckWarning (justifyRight 7 hpText)     Nothing -> return $! stringToAL (calmHeaderText ++ ":  --/--")                          <+:> stringToAL (hpHeaderText <> ":  --/--") 
Game/LambdaHack/Client/UI/Frontend/Common.hs view
@@ -10,12 +10,12 @@ import Game.LambdaHack.Common.Prelude  import           Control.Concurrent-import           Control.Concurrent.Async import qualified Control.Concurrent.STM as STM  import           Game.LambdaHack.Client.UI.Frame import           Game.LambdaHack.Client.UI.Key (KMP (..)) import qualified Game.LambdaHack.Client.UI.Key as K+import           Game.LambdaHack.Common.Misc import           Game.LambdaHack.Common.Point  -- | Raw frontend definition. The minimal closed set of values that need@@ -28,11 +28,26 @@   , fprintScreen :: IO ()   } +-- | Start up a frontend on a bound thread.+--+-- In fact, it is started on the very main thread, via a hack, because+-- apparently some SDL backends are not thread-safe+-- (<https://wiki.libsdl.org/FAQDevelopment>;+-- "this should only be run in the thread that initialized the video subsystem,+-- and for extra safety, you should consider only doing those things+-- on the main thread in any case")+-- and at least the newer OS X obtusely requires the main thread, see+-- https://github.com/AllureOfTheStars/Allure/issues/79+-- In case any other exotic architecture requires the main thread,+-- we make the hack the default for all (on frontends that require a bound+-- thread, e.g., SLD2 or GTK). startupBound :: (MVar RawFrontend -> IO ()) -> IO RawFrontend startupBound k = do   rfMVar <- newEmptyMVar-  a <- asyncBound $ k rfMVar-  link a+  putMVar workaroundOnMainThreadMVar $ k rfMVar+  -- The following would run frontend on a bound thread, but it's not enough:+  -- a <- asyncBound $ k rfMVar+  -- link a   takeMVar rfMVar  createRawFrontend :: (SingleFrame -> IO ()) -> IO () -> IO RawFrontend
Game/LambdaHack/Client/UI/Frontend/Sdl.hs view
@@ -71,14 +71,8 @@  -- | Set up and start the main loop providing input and output. ----- Apparently some SDL backends are not thread-safe--- (<https://wiki.libsdl.org/FAQDevelopment>;--- "this should only be run in the thread that initialized the video subsystem,--- and for extra safety, you should consider only doing those things--- on the main thread in any case")--- so we stick to a single bound thread (but not to the main thread;--- enough is enough and at least in the case of OpenGL all bound threads--- are supposed to be as good as the main thread).+-- Because of Windows and OS X, SDL2 needs to be on a bound thread,+-- so we can't avoid the communication overhead of bound threads. startup :: ClientOptions -> IO RawFrontend startup soptions = startupBound $ startupFun soptions 
Game/LambdaHack/Client/UI/HandleHumanGlobalM.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE DataKinds, GADTs #-} -- | Semantics of "Game.LambdaHack.Client.UI.HumanCmd" -- client commands that return server requests. -- A couple of them do not take time, the rest does.@@ -25,8 +24,8 @@ #ifdef EXPOSE_INTERNAL     -- * Internal operations   , areaToRectangles, meleeAid, displaceAid, moveSearchAlter, goToXhair-  , multiActorGoTo, selectItemsToMove, moveItems, projectItem, applyItem-  , alterTile, alterTileAtPos, verifyAlters, verifyEscape, guessAlter+  , multiActorGoTo, moveOrSelectItem, selectItemsToMove, moveItems, projectItem+  , applyItem, alterTile, alterTileAtPos, verifyAlters, verifyEscape, guessAlter   , artWithVersion, generateMenu, nxtGameMode #endif   ) where@@ -230,25 +229,32 @@ -- * Wait  -- | Leader waits a turn (and blocks, etc.).-waitHuman :: MonadClientUI m => m (RequestTimed 'AbWait)+waitHuman :: MonadClientUI m => m (FailOrCmd RequestTimed) waitHuman = do-  modifySession $ \sess -> sess {swaitTimes = abs (swaitTimes sess) + 1}-  return ReqWait+  actorSk <- leaderSkillsClientUI+  if EM.findWithDefault 0 AbWait actorSk > 0 then do+    modifySession $ \sess -> sess {swaitTimes = abs (swaitTimes sess) + 1}+    return $ Right ReqWait+  else failSer WaitUnskilled  -- * Wait10  -- | Leader waits a 1/10th of a turn (and doesn't block, etc.).-waitHuman10 :: MonadClientUI m => m (RequestTimed 'AbWait)+waitHuman10 :: MonadClientUI m => m (FailOrCmd RequestTimed) waitHuman10 = do-  modifySession $ \sess -> sess {swaitTimes = abs (swaitTimes sess) + 1}-  return ReqWait10+  actorSk <- leaderSkillsClientUI+  if EM.findWithDefault 0 AbWait actorSk > 0 then do+    modifySession $ \sess -> sess {swaitTimes = abs (swaitTimes sess) + 1}+    return $ Right ReqWait10+  else failSer WaitUnskilled  -- * MoveDir and RunDir  moveRunHuman :: MonadClientUI m              => Bool -> Bool -> Bool -> Bool -> Vector-             -> m (FailOrCmd RequestAnyAbility)+             -> m (FailOrCmd RequestTimed) moveRunHuman initialStep finalGoal run runAhead dir = do+  actorSk <- leaderSkillsClientUI   arena <- getArenaUI   leader <- getLeaderUI   sb <- getsState $ getActorBody leader@@ -292,32 +298,40 @@           -- Don't check @initialStep@ and @finalGoal@           -- and don't stop going to target: door opening is mundane enough.           return $ Right runCmd-    [(target, _)] | run && initialStep ->+    [(target, _)] | run+                    && initialStep+                    && EM.findWithDefault 0 AbDisplace actorSk > 0 ->       -- No @stopPlayBack@: initial displace is benign enough.       -- Displacing requires accessibility, but it's checked later on.-      RequestAnyAbility <$$> displaceAid target-    _ : _ : _ | run && initialStep -> do+      displaceAid target+    _ : _ : _ | run+                && initialStep+                && EM.findWithDefault 0 AbDisplace actorSk > 0 -> do       let !_A = assert (all (bproj . snd) tgts) ()       failSer DisplaceProjectiles-    (target, tb) : _ | initialStep && finalGoal -> do+    (target, tb) : _ | not run+                       && initialStep && finalGoal+                       && bfid tb == bfid sb && not (bproj tb) -> do+      stopPlayBack  -- don't ever auto-repeat leader choice+      -- We always see actors from our own faction.+      -- Select one of adjacent actors by bumping into him. Takes no time.+      success <- pickLeader True target+      let !_A = assert (success `blame` "bump self"+                                `swith` (leader, target, tb)) ()+      failWith "by bumping"+    (target, tb) : _ | not run+                       && initialStep && finalGoal+                       && (bfid tb /= bfid sb || bproj tb)+                       && EM.findWithDefault 0 AbMelee actorSk > 0 -> do       stopPlayBack  -- don't ever auto-repeat melee       -- No problem if there are many projectiles at the spot. We just       -- attack the first one.-      -- We always see actors from our own faction.-      if bfid tb == bfid sb && not (bproj tb) then do-        -- Select adjacent actor by bumping into him. Takes no time.-        success <- pickLeader True target-        let !_A = assert (success `blame` "bump self"-                                  `swith` (leader, target, tb)) ()-        failWith "by bumping"-      else-        -- Attacking does not require full access, adjacency is enough.-        RequestAnyAbility <$$> meleeAid target+      meleeAid target     _ : _ -> failWith "actor in the way"  -- | Actor attacks an enemy actor or his own projectile. meleeAid :: MonadClientUI m-         => ActorId -> m (FailOrCmd (RequestTimed 'AbMelee))+         => ActorId -> m (FailOrCmd RequestTimed) meleeAid target = do   leader <- getLeaderUI   sb <- getsState $ getActorBody leader@@ -352,7 +366,7 @@  -- | Actor swaps position with another. displaceAid :: MonadClientUI m-            => ActorId -> m (FailOrCmd (RequestTimed 'AbDisplace))+            => ActorId -> m (FailOrCmd RequestTimed) displaceAid target = do   COps{coTileSpeedup} <- getsState scops   leader <- getLeaderUI@@ -389,14 +403,15 @@        else failSer DisplaceAccess  -- | Leader moves or searches or alters. No visible actor at the position.-moveSearchAlter :: MonadClientUI m => Vector -> m (FailOrCmd RequestAnyAbility)+moveSearchAlter :: MonadClientUI m => Vector -> m (FailOrCmd RequestTimed) moveSearchAlter dir = do   COps{coTileSpeedup} <- getsState scops+  actorSk <- leaderSkillsClientUI   leader <- getLeaderUI   sb <- getsState $ getActorBody leader   ar <- getsState $ getActorAspect leader-  actorSk <- leaderSkillsClientUI   let calmE = calmEnough sb ar+      moveSkill = EM.findWithDefault 0 AbMove actorSk       alterSkill = EM.findWithDefault 0 AbAlter actorSk       applySkill = EM.findWithDefault 0 AbApply actorSk       spos = bpos sb           -- source position@@ -418,12 +433,13 @@                    || Tile.isSuspect coTileSpeedup t   runStopOrCmd <-     -- Movement requires full access.-    if | Tile.isWalkable coTileSpeedup t ->+    if | Tile.isWalkable coTileSpeedup t && moveSkill > 0 ->          -- A potential invisible actor is hit. War started without asking.-         return $ Right $ RequestAnyAbility $ ReqMove dir-       -- No free access, so search and/or alter the tile.+         return $ Right $ ReqMove dir+       -- No free access or skill, so search and/or alter the tile.        | not (modifiable || canApplyEmbeds) ->-           failWith "never mind"  -- misclick? related to AlterNothing+           failWith "never mind"+             -- misclick? walkable but no move skill? related to AlterNothing        | alterSkill <= 1 -> failSer AlterUnskilled        | not (Tile.isSuspect coTileSpeedup t)          && alterSkill < alterMinSkill -> failSer AlterUnwalked@@ -432,7 +448,7 @@        | otherwise -> do  -- promising             verAlters <- verifyAlters (blid sb) tpos             case verAlters of-              Right() -> return $ Right $ RequestAnyAbility $ ReqAlter tpos+              Right() -> return $ Right $ ReqAlter tpos               Left err -> return $ Left err             -- We don't use ReqMove, because we don't hit invisible actors,             -- e.g., hidden in a wall. If server performed an attack for free@@ -448,7 +464,7 @@  -- * RunOnceAhead -runOnceAheadHuman :: MonadClientUI m => m (Either MError ReqUI)+runOnceAheadHuman :: MonadClientUI m => m (Either MError RequestTimed) runOnceAheadHuman = do   side <- getsClient sside   fact <- getsState $ (EM.! side) . sfactionD@@ -483,14 +499,14 @@           then weaveJust <$> failWith ("run stop:" <+> stopMsg)           else return $ Left Nothing         Right runCmd ->-          return $ Right $ ReqUITimed runCmd+          return $ Right runCmd  -- * MoveOnceToXhair -moveOnceToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestAnyAbility)+moveOnceToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestTimed) moveOnceToXhairHuman = goToXhair True False -goToXhair :: MonadClientUI m => Bool -> Bool -> m (FailOrCmd RequestAnyAbility)+goToXhair :: MonadClientUI m => Bool -> Bool -> m (FailOrCmd RequestTimed) goToXhair initialStep run = do   aimMode <- getsSession saimMode   -- Movement is legal only outside aiming mode.@@ -501,9 +517,10 @@     xhairPos <- xhairToPos     case xhairPos of       Nothing -> failWith "crosshair position invalid"-      Just c | c == bpos b ->-        if initialStep-        then return $ Right $ RequestAnyAbility ReqWait+      Just c | c == bpos b -> do+        actorSk <- leaderSkillsClientUI+        if initialStep && EM.findWithDefault 0 AbWait actorSk > 0+        then return $ Right $ ReqWait         else failWith "position reached"       Just c -> do         running <- getsSession srunning@@ -574,24 +591,33 @@  -- * RunOnceToXhair -runOnceToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestAnyAbility)+runOnceToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestTimed) runOnceToXhairHuman = goToXhair True True  -- * ContinueToXhair -continueToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestAnyAbility)+continueToXhairHuman :: MonadClientUI m => m (FailOrCmd RequestTimed) continueToXhairHuman = goToXhair False False{-irrelevant-}  -- * MoveItem --- This cannot be structured as projecting or applying, with @ByItemMode@--- and @ChooseItemToMove@, because at least in case of grabbing items,--- more than one item is chosen, which doesn't fit @sitemSel@. Separating--- grabbing of multiple items as a distinct command is too high a proce. moveItemHuman :: forall m. MonadClientUI m               => [CStore] -> CStore -> Maybe MU.Part -> Bool-              -> m (FailOrCmd (RequestTimed 'AbMoveItem))+              -> m (FailOrCmd RequestTimed) moveItemHuman cLegalRaw destCStore mverb auto = do+  actorSk <- leaderSkillsClientUI+  if EM.findWithDefault 0 AbMoveItem actorSk > 0 then+    moveOrSelectItem cLegalRaw destCStore mverb auto+  else failSer MoveItemUnskilled++-- This cannot be structured as projecting or applying, with @ByItemMode@+-- and @ChooseItemToMove@, because at least in case of grabbing items,+-- more than one item is chosen, which doesn't fit @sitemSel@. Separating+-- grabbing of multiple items as a distinct command is too high a price.+moveOrSelectItem :: forall m. MonadClientUI m+                 => [CStore] -> CStore -> Maybe MU.Part -> Bool+                 -> m (FailOrCmd RequestTimed)+moveOrSelectItem cLegalRaw destCStore mverb auto = do   itemSel <- getsSession sitemSel   modifySession $ \sess -> sess {sitemSel = Nothing}  -- prevent surprise   case itemSel of@@ -680,7 +706,7 @@  moveItems :: forall m. MonadClientUI m           => [CStore] -> (CStore, [(ItemId, ItemFullKit)]) -> CStore-          -> m (FailOrCmd (RequestTimed 'AbMoveItem))+          -> m (FailOrCmd RequestTimed) moveItems cLegalRaw (fromCStore, l) destCStore = do   leader <- getLeaderUI   b <- getsState $ getActorBody leader@@ -736,25 +762,29 @@  -- * Project -projectHuman :: MonadClientUI m => m (FailOrCmd (RequestTimed 'AbProject))+projectHuman :: MonadClientUI m => m (FailOrCmd RequestTimed) projectHuman = do-  itemSel <- getsSession sitemSel-  case itemSel of-    Just (iid, fromCStore, _) -> do-      leader <- getLeaderUI-      b <- getsState $ getActorBody leader-      bag <- getsState $ getBodyStoreBag b fromCStore-      case iid `EM.lookup` bag of-        Nothing -> failWith "no item to fling"-        Just _kit -> do-          itemFull <- getsState $ itemToFull iid-          let i = (fromCStore, (iid, itemFull))-          projectItem i-    Nothing -> failWith "no item to fling"+  actorSk <- leaderSkillsClientUI+  if EM.findWithDefault 0 AbProject actorSk <= 0 then  -- detailed check later+    failSer ProjectUnskilled+  else do+    itemSel <- getsSession sitemSel+    case itemSel of+      Just (iid, fromCStore, _) -> do+        leader <- getLeaderUI+        b <- getsState $ getActorBody leader+        bag <- getsState $ getBodyStoreBag b fromCStore+        case iid `EM.lookup` bag of+          Nothing -> failWith "no item to fling"+          Just _kit -> do+            itemFull <- getsState $ itemToFull iid+            let i = (fromCStore, (iid, itemFull))+            projectItem i+      Nothing -> failWith "no item to fling"  projectItem :: MonadClientUI m             => (CStore, (ItemId, ItemFull))-            -> m (FailOrCmd (RequestTimed 'AbProject))+            -> m (FailOrCmd RequestTimed) projectItem (fromCStore, (iid, itemFull)) = do   leader <- getLeaderUI   b <- getsState $ getActorBody leader@@ -780,24 +810,28 @@  -- * Apply -applyHuman :: MonadClientUI m => m (FailOrCmd (RequestTimed 'AbApply))+applyHuman :: MonadClientUI m => m (FailOrCmd RequestTimed) applyHuman = do-  itemSel <- getsSession sitemSel-  case itemSel of-    Just (iid, fromCStore, _) -> do-      leader <- getLeaderUI-      b <- getsState $ getActorBody leader-      bag <- getsState $ getBodyStoreBag b fromCStore-      case iid `EM.lookup` bag of-        Nothing -> failWith "no item to apply"-        Just kit -> do-          itemFull <- getsState $ itemToFull iid-          applyItem (fromCStore, (iid, (itemFull, kit)))-    Nothing -> failWith "no item to apply"+  actorSk <- leaderSkillsClientUI+  if EM.findWithDefault 0 AbApply actorSk <= 0 then  -- detailed check later+    failSer ApplyUnskilled+  else do+    itemSel <- getsSession sitemSel+    case itemSel of+      Just (iid, fromCStore, _) -> do+        leader <- getLeaderUI+        b <- getsState $ getActorBody leader+        bag <- getsState $ getBodyStoreBag b fromCStore+        case iid `EM.lookup` bag of+          Nothing -> failWith "no item to apply"+          Just kit -> do+            itemFull <- getsState $ itemToFull iid+            applyItem (fromCStore, (iid, (itemFull, kit)))+      Nothing -> failWith "no item to apply"  applyItem :: MonadClientUI m           => (CStore, (ItemId, ItemFullKit))-          -> m (FailOrCmd (RequestTimed 'AbApply))+          -> m (FailOrCmd RequestTimed) applyItem (fromCStore, (iid, (itemFull, kit))) = do   leader <- getLeaderUI   b <- getsState $ getActorBody leader@@ -814,7 +848,7 @@  -- | Ask for a direction and alter a tile in the specified way, if possible. alterDirHuman :: MonadClientUI m-              => [TriggerTile] -> m (FailOrCmd (RequestTimed 'AbAlter))+              => [TriggerTile] -> m (FailOrCmd RequestTimed) alterDirHuman ts = do   UIOptions{uVi, uLaptop} <- getsSession sUIOptions   let verb1 = case ts of@@ -844,7 +878,7 @@  -- | Try to alter a tile using a feature in the given direction. alterTile :: MonadClientUI m-          => [TriggerTile] -> Vector -> m (FailOrCmd (RequestTimed 'AbAlter))+          => [TriggerTile] -> Vector -> m (FailOrCmd RequestTimed) alterTile ts dir = do   leader <- getLeaderUI   b <- getsState $ getActorBody leader@@ -860,7 +894,7 @@ -- the time will be wasted and the server will describe the failure in detail. alterTileAtPos :: MonadClientUI m                => [TriggerTile] -> Point -> Text-               -> m (FailOrCmd (RequestTimed 'AbAlter))+               -> m (FailOrCmd RequestTimed) alterTileAtPos ts tpos pText = do   cops@COps{cotile, coTileSpeedup} <- getsState scops   leader <- getLeaderUI@@ -956,7 +990,7 @@  -- | Try to alter a tile using a feature under the pointer. alterWithPointerHuman :: MonadClientUI m-                      => [TriggerTile] -> m (FailOrCmd (RequestTimed 'AbAlter))+                      => [TriggerTile] -> m (FailOrCmd RequestTimed) alterWithPointerHuman ts = do   COps{cotile} <- getsState scops   lidV <- viewedLevelUI@@ -1174,8 +1208,8 @@   let stdRuleset = getStdRuleset cops       lxsize = fst normalLevelBound + 1       lysize = snd normalLevelBound + 4-      xoffset = (110 - lxsize) `div` 2-      yoffset = (60 - lysize) `div` 2+      xoffset = (80 - lxsize) `div` 2+      yoffset = (45 - lysize) `div` 2       tlines = T.lines $ rmainMenuArt stdRuleset       f = T.take lxsize . T.drop xoffset   return $! map f $ take lysize $ drop yoffset tlines
Game/LambdaHack/Client/UI/HandleHumanM.hs view
@@ -3,7 +3,7 @@   ( cmdHumanSem #ifdef EXPOSE_INTERNAL     -- * Internal operations-  , noRemoteHumanCmd, cmdAction, addNoError, fmapTimedToUI+  , noRemoteHumanCmd, cmdAction, addNoError #endif   ) where @@ -69,23 +69,23 @@   LoopOnNothing cmd1 -> loopOnNothingHuman (cmdAction cmd1)   ExecuteIfClear cmd1 -> executeIfClearHuman (cmdAction cmd1) -  Wait -> weaveJust <$> Right <$> fmapTimedToUI waitHuman-  Wait10 -> weaveJust <$> Right <$> fmapTimedToUI waitHuman10+  Wait -> weaveJust <$> (ReqUITimed <$$> waitHuman)+  Wait10 -> weaveJust <$> (ReqUITimed <$$> waitHuman10)   MoveDir v ->     weaveJust <$> (ReqUITimed <$$> moveRunHuman True True False False v)   RunDir v -> weaveJust <$> (ReqUITimed <$$> moveRunHuman True True True True v)-  RunOnceAhead -> runOnceAheadHuman+  RunOnceAhead -> ReqUITimed <$$> runOnceAheadHuman   MoveOnceToXhair -> weaveJust <$> (ReqUITimed <$$> moveOnceToXhairHuman)   RunOnceToXhair  -> weaveJust <$> (ReqUITimed <$$> runOnceToXhairHuman)   ContinueToXhair -> weaveJust <$> (ReqUITimed <$$> continueToXhairHuman)   MoveItem cLegalRaw toCStore mverb auto ->     weaveJust-    <$> (fmapTimedToUI <$> moveItemHuman cLegalRaw toCStore mverb auto)-  Project -> weaveJust <$> (fmapTimedToUI <$> projectHuman)-  Apply -> weaveJust <$> (fmapTimedToUI <$> applyHuman)-  AlterDir ts -> weaveJust <$> (fmapTimedToUI <$> alterDirHuman ts)+    <$> (ReqUITimed <$$> moveItemHuman cLegalRaw toCStore mverb auto)+  Project -> weaveJust <$> (ReqUITimed <$$> projectHuman)+  Apply -> weaveJust <$> (ReqUITimed <$$> applyHuman)+  AlterDir ts -> weaveJust <$> (ReqUITimed <$$> alterDirHuman ts)   AlterWithPointer ts -> weaveJust-                         <$> (fmapTimedToUI <$> alterWithPointerHuman ts)+                         <$> (ReqUITimed <$$> alterWithPointerHuman ts)   Help -> helpHuman cmdAction   Hint -> hintHuman cmdAction   ItemMenu -> itemMenuHuman cmdAction@@ -145,6 +145,3 @@  addNoError :: Monad m => m () -> m (Either MError ReqUI) addNoError cmdCli = cmdCli >> return (Left Nothing)--fmapTimedToUI :: Monad m => m (RequestTimed a) -> m ReqUI-fmapTimedToUI mr = ReqUITimed . RequestAnyAbility <$> mr
Game/LambdaHack/Client/UI/InventoryM.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE DataKinds #-} -- | UI of inventory management. module Game.LambdaHack.Client.UI.InventoryM   ( Suitability(..)
Game/LambdaHack/Client/UI/RunM.hs view
@@ -46,7 +46,7 @@ -- | Continue running in the given direction. continueRun :: MonadClientUI m             => LevelId -> RunParams-            -> m (Either Text RequestAnyAbility)+            -> m (Either Text RequestTimed) continueRun arena paramOld = case paramOld of   RunParams{ runMembers = []            , runStopMsg = Just stopMsg } -> return $ Left stopMsg@@ -88,7 +88,7 @@              s <- getState              modifyClient $ updateLeader r s              modifySession $ \sess -> sess {srunning = Just paramNew}-             return $ Right $ RequestAnyAbility $ ReqMove dir+             return $ Right $ ReqMove dir          -- The potential invisible actor is hit. War is started without asking.  -- | This function implements the actual logic of running. It checks if we
Game/LambdaHack/Common/Actor.hs view
@@ -99,7 +99,7 @@ actorCanMelee actorAspect aid b =   let ar = actorAspect EM.! aid       actorMaxSk = IA.aSkills ar-      condUsableWeapon = bweapon b >= 0+      condUsableWeapon = bweapon b > 0       canMelee = EM.findWithDefault 0 Ability.AbMelee actorMaxSk > 0   in condUsableWeapon && canMelee 
Game/LambdaHack/Common/Item.hs view
@@ -45,9 +45,9 @@ -- Then they are presented as having a template kind that is really -- not their own, though usually close. Full kind information about -- item's kind is available through the @ItemKindIx@ index once the item--- is identified and full information about the value of item's aspects+-- is identified and full information about the value of item's aspect record -- is available elsewhere (both @IdentityObvious@ and @IdentityCovered@--- items may or may not need identification of their aspects).+-- items may or may not need identification of their aspect record). data Item = Item   { jkind    :: ItemIdentity  -- ^ the kind of the item, or an indiretion   , jlid     :: LevelId       -- ^ lowest level the item was created at@@ -74,7 +74,8 @@  instance Binary ItemIdentity --- | The map of item ids to item aspects. The full map is known by the server.+-- | The map of item ids to item aspect reocrd. The full map is known+-- by the server. type DiscoveryAspect = EM.EnumMap ItemId IA.AspectRecord  -- | An index of the kind identifier of an item. Clients have partial knowledge@@ -84,7 +85,7 @@   deriving (Show, Eq, Ord, Enum, Ix.Ix, Hashable, Binary)  -- | The secret part of the information about an item. If a faction--- knows the aspects of the item (the @kmConst@ flag is set or+-- knows the aspect record of the item (the @kmConst@ flag is set or -- the @itemAspect@ field is @Left@), this is a complete secret information. -- Items that don't need second identification may be identified or not and both -- cases are OK (their display flavour will differ and that may be the point).@@ -166,7 +167,7 @@       itemKind = okind coitem itemKindId       km = IK.getKindMean itemKindId coItemSpeedup       -- If the kind is not identified, we know nothing about the real-      -- aspects, so we at least assume they are variable.+      -- aspect record, so we at least assume they are variable.       itemAspectMean | itemSuspect = km {IA.kmConst = False}                      | otherwise = km       itemDisco = case EM.lookup iid discoAspect of
Game/LambdaHack/Common/ItemAspect.hs view
@@ -1,9 +1,9 @@ {-# LANGUAGE DeriveGeneric, GeneralizedNewtypeDeriving #-} -- | The type of item aspects and its operations. module Game.LambdaHack.Common.ItemAspect-  ( Aspect(..), AspectRecord(..), KindMean(..), ItemSeed, EqpSlot(..)+  ( Aspect(..), AspectRecord(..), KindMean(..), EqpSlot(..)   , emptyAspectRecord, addMeanAspect, castAspect, aspectsRandom-  , sumAspectRecord, aspectRecordToList, seedToAspect, prEqpSlot+  , sumAspectRecord, aspectRecordToList, rollAspectRecord, prEqpSlot #ifdef EXPOSE_INTERNAL     -- * Internal operations   , ceilingMeanDice@@ -65,20 +65,14 @@  -- | Partial information about an item, deduced from its item kind. -- These are assigned to each 'ItemKind'. The @kmConst@ flag says whether--- the item's aspects are constant rather than random or dependent+-- the item's aspect record is constant rather than random or dependent -- on item creation dungeon level. data KindMean = KindMean   { kmConst :: Bool  -- ^ whether the item doesn't need second identification-  , kmMean  :: AspectRecord  -- ^ mean value of item's possible aspects+  , kmMean  :: AspectRecord  -- ^ mean value of item's possible aspect records   }   deriving (Show, Eq, Ord, Generic) --- | A seed for rolling aspects of an item--- Clients have partial knowledge of how item ids map to the seeds.--- They gain knowledge by identifying items.-newtype ItemSeed = ItemSeed Int-  deriving (Show, Eq, Ord, Enum, Hashable, Binary)- -- | AI and UI hints about the role of the item. data EqpSlot =     EqpSlotMiscBonus@@ -272,11 +266,10 @@   ++ [AddAggression $ Dice.intToDice aAggression | aAggression /= 0]   ++ [AddAbility ab $ Dice.intToDice n | (ab, n) <- EM.assocs aSkills, n /= 0] -seedToAspect :: ItemSeed -> [Aspect] -> Dice.AbsDepth -> Dice.AbsDepth-             -> AspectRecord-seedToAspect (ItemSeed itemSeed) ass ldepth totalDepth =-  let rollM = foldlM' (castAspect ldepth totalDepth) emptyAspectRecord ass-  in St.evalState rollM (R.mkStdGen itemSeed)+rollAspectRecord :: [Aspect] -> Dice.AbsDepth -> Dice.AbsDepth+                 -> Rnd AspectRecord+rollAspectRecord ass ldepth totalDepth =+  foldlM' (castAspect ldepth totalDepth) emptyAspectRecord ass  prEqpSlot :: EqpSlot -> AspectRecord -> Int prEqpSlot eqpSlot ar@AspectRecord{..} =
Game/LambdaHack/Common/Misc.hs view
@@ -11,12 +11,14 @@   , toGroupName, describeTactic   , makePhrase, makeSentence, squashedWWandW, normalLevelBound   , appDataDir, xM, xD, minusM, minusM1, oneM, tenthM+  , workaroundOnMainThreadMVar   ) where  import Prelude ()  import Game.LambdaHack.Common.Prelude +import           Control.Concurrent import           Control.DeepSeq import           Data.Binary import qualified Data.Char as Char@@ -34,6 +36,7 @@ import qualified NLP.Miniutter.English as MU import           System.Directory (getAppUserDataDirectory) import           System.Environment (getProgName)+import           System.IO.Unsafe (unsafePerformIO)  import Game.LambdaHack.Common.Point @@ -205,6 +208,11 @@ minusM1 = xM (-1) - 1 oneM = xM 1 tenthM = 100000++-- Global variable for passing the action to run on main thread, if any.+workaroundOnMainThreadMVar :: MVar (IO ())+{-# NOINLINE workaroundOnMainThreadMVar #-}+workaroundOnMainThreadMVar = unsafePerformIO newEmptyMVar  -- Data.Binary orphan instances 
Game/LambdaHack/Common/ReqFailure.hs view
@@ -23,9 +23,12 @@  -- | Possible causes of failure of request. data ReqFailure =-    MoveNothing+    MoveUnskilled+  | MoveNothing+  | MeleeUnskilled   | MeleeSelf   | MeleeDistant+  | DisplaceUnskilled   | DisplaceDistant   | DisplaceAccess   | DisplaceProjectiles@@ -39,6 +42,8 @@   | AlterBlockActor   | AlterBlockItem   | AlterNothing+  | WaitUnskilled+  | MoveItemUnskilled   | EqpOverfull   | EqpStackFull   | ApplyUnskilled@@ -63,9 +68,12 @@  impossibleReqFailure :: ReqFailure -> Bool impossibleReqFailure reqFailure = case reqFailure of+  MoveUnskilled -> False  -- unidentified skill items   MoveNothing -> True+  MeleeUnskilled -> False  -- unidentified skill items   MeleeSelf -> True   MeleeDistant -> True+  DisplaceUnskilled -> False  -- unidentified skill items   DisplaceDistant -> True   DisplaceAccess -> True   DisplaceProjectiles -> True@@ -79,12 +87,14 @@   AlterBlockActor -> True  -- adjacent actor always visible   AlterBlockItem -> True  -- adjacent item always visible   AlterNothing -> True+  WaitUnskilled -> False  -- unidentified skill items+  MoveItemUnskilled -> False  -- unidentified skill items   EqpOverfull -> True   EqpStackFull -> True   ApplyUnskilled -> False  -- unidentified skill items   ApplyRead -> False  -- unidentified skill items   ApplyOutOfReach -> True-  ApplyCharging -> False  -- if aspects unknown, charging unknown+  ApplyCharging -> False  -- if aspect record unknown, charging unknown   ApplyNoEffects -> False  -- if effects unknown, can't prevent it   ItemNothing -> True   ItemNotCalm -> False  -- unidentified skill items@@ -100,9 +110,12 @@  showReqFailure :: ReqFailure -> Text showReqFailure reqFailure = case reqFailure of+  MoveUnskilled -> "unskilled actors cannot move"   MoveNothing -> "wasting time on moving into obstacle"+  MeleeUnskilled -> "unskilled actors cannot melee"   MeleeSelf -> "trying to melee oneself"   MeleeDistant -> "trying to melee a distant foe"+  DisplaceUnskilled -> "unskilled actors cannot displace"   DisplaceDistant -> "trying to displace a distant actor"   DisplaceAccess -> "switching places without access"   DisplaceProjectiles -> "trying to displace multiple projectiles"@@ -116,6 +129,8 @@   AlterBlockActor -> "blocked by an actor"   AlterBlockItem -> "jammed by an item"   AlterNothing -> "wasting time on altering nothing"+  WaitUnskilled -> "unskilled actors cannot wait"+  MoveItemUnskilled -> "unskilled actors cannot move items"   EqpOverfull -> "cannot equip any more items"   EqpStackFull -> "cannot equip the whole item stack"   ApplyUnskilled -> "unskilled actors cannot apply items"
Game/LambdaHack/Common/State.hs view
@@ -65,7 +65,7 @@   , _sgameModeId  :: ContentId ModeKind   -- ^ current game mode   , _sdiscoKind   :: DiscoveryKind    -- ^ item kind discoveries data   , _sdiscoAspect :: DiscoveryAspect  -- ^ item aspect data; could be recomputed-  , _sactorAspect :: ActorAspect      -- ^ actor aspects; is recomputed+  , _sactorAspect :: ActorAspect      -- ^ actor aspect records; is recomputed   }   deriving (Show, Eq) @@ -275,7 +275,7 @@ getItemBody :: ItemId -> State -> Item getItemBody iid s = sitemD s EM.! iid --- This is best guess, including mean aspects, so we can take into+-- This is best guess, including mean aspect record, so we can take into -- consideration even the kind the item hides under. aspectRecordFromItem :: ItemId -> Item -> State -> IA.AspectRecord aspectRecordFromItem iid item s =
Game/LambdaHack/Content/RuleKind.hs view
@@ -21,7 +21,7 @@  -- | The type of game rule sets and assorted game data. ----- In principle, it'se possible to have many rule sets+-- In principle, it's possible to have many rule sets -- and switch between them during a game session or even a single game. data RuleKind = RuleKind   { rsymbol         :: Char      -- ^ a symbol@@ -54,12 +54,12 @@ validateSingle :: RuleKind -> [Text] validateSingle RuleKind{rmainMenuArt} =   let ts = T.lines rmainMenuArt-      tsNot110 = filter ((/= 110) . T.length) ts-  in case tsNot110 of-     [] -> [ "rmainMenuArt doesn't have 60 lines, but " <> tshow (length ts)-           | length ts /= 60]-     tNot110 : _ ->-       ["rmainMenuArt has a line with length other than 110:" <> tNot110]+      tsNot80 = filter ((/= 80) . T.length) ts+  in case tsNot80 of+     [] -> [ "rmainMenuArt doesn't have 45 lines, but " <> tshow (length ts)+           | length ts /= 45]+     tNot80 : _ ->+       ["rmainMenuArt has a line with length other than 80:" <> tNot80]  -- | Since we have only one rule kind, the set of rule kinds is always valid. validateAll :: [RuleKind] -> ContentData RuleKind -> [Text]
Game/LambdaHack/Server/BroadcastAtomic.hs view
@@ -53,7 +53,7 @@   return (ps, atomicBroken, executedOnServer)  -- | Send an atomic action to all clients that can see it.-handleAndBroadcast :: (MonadServerAtomic m, MonadServerReadRequest m)+handleAndBroadcast :: (MonadServerAtomic m, MonadServerComm m)                    => PosAtomic -> [UpdAtomic] -> CmdAtomic -> m () handleAndBroadcast ps atomicBroken atomic = do   -- This is calculated in the server State before action (simulating@@ -148,7 +148,7 @@       return $ Just $ SfxLoudSummon (bproj b) grp p     _ -> return Nothing -sendPer :: (MonadServerAtomic m, MonadServerReadRequest m)+sendPer :: (MonadServerAtomic m, MonadServerComm m)         => FactionId -> LevelId -> Perception -> Perception -> Perception         -> m () {-# INLINE sendPer #-}
Game/LambdaHack/Server/Commandline.hs view
@@ -24,7 +24,7 @@ -- remaining commandline should be passed and parsed by the client to extract -- client and ui options from and singnal an error if anything was left. -import Game.LambdaHack.Client.ClientOptions+import Game.LambdaHack.Client (ClientOptions (..)) import Game.LambdaHack.Common.Faction import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ModeKind
Game/LambdaHack/Server/CommonM.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE TupleSections #-} -- | Server operations common to many modules. module Game.LambdaHack.Server.CommonM-  ( execFailure, revealItems, moveStores, generalMoveItem+  ( revealItems, moveStores, generalMoveItem   , deduceQuits, deduceKilled, electLeader, supplantLeader   , updatePer, recomputeCachePer, projectFail   , addActorFromGroup, registerActor, discoverIfMinorEffects@@ -18,11 +18,8 @@ import Game.LambdaHack.Common.Prelude  import qualified Data.EnumMap.Strict as EM-import qualified Data.Text as T-import qualified Text.Show.Pretty as Show.Pretty  import           Game.LambdaHack.Atomic-import           Game.LambdaHack.Client import qualified Game.LambdaHack.Common.Ability as Ability import           Game.LambdaHack.Common.Actor import           Game.LambdaHack.Common.ActorState@@ -51,26 +48,6 @@ import           Game.LambdaHack.Server.ServerOptions import           Game.LambdaHack.Server.State -execFailure :: MonadServerAtomic m-            => ActorId -> RequestTimed a -> ReqFailure -> m ()-execFailure aid req failureSer = do-  -- Clients should rarely do that (only in case of invisible actors)-  -- so we report it to the client, but do not crash-  -- (server should work OK with stupid clients, too).-  body <- getsState $ getActorBody aid-  let fid = bfid body-      msg = showReqFailure failureSer-      impossible = impossibleReqFailure failureSer-      debugShow :: Show a => a -> Text-      debugShow = T.pack . Show.Pretty.ppShow-      possiblyAlarm = if impossible-                      then debugPossiblyPrintAndExit-                      else debugPossiblyPrint-  possiblyAlarm $-    "execFailure:" <+> msg <> "\n"-    <> debugShow body <> "\n" <> debugShow req <> "\n" <> debugShow failureSer-  execSfxAtomic $ SfxMsgFid fid $ SfxUnexpected failureSer- revealItems :: MonadServerAtomic m => Maybe FactionId -> m () revealItems mfid = do   COps{coitem} <- getsState scops@@ -79,8 +56,8 @@         let itemKind = okind coitem itemKindId             c = CActor aid store         unless (IK.isHumanTrinket itemKind) $ do  -- a hack-          seed <- getsServer $ (EM.! iid) . sitemSeedD-          execUpdAtomic $ UpdDiscover c iid itemKindId seed+          discoAspect <- getsState sdiscoAspect+          execUpdAtomic $ UpdDiscover c iid itemKindId $ discoAspect EM.! iid       f aid = do         b <- getsState $ getActorBody aid         let ourSide = maybe True (== bfid b) mfid@@ -377,23 +354,22 @@   -- We bootstrap the actor by first creating the trunk of the actor's body   -- that contains the constant properties.   let trunkFreq = [(actorGroup, 1)]-  m4 <- rollItem 0 lid trunkFreq-  case m4 of+  m3 <- rollItem 0 lid trunkFreq+  case m3 of     Nothing -> return Nothing-    Just (itemKnown, itemFullKit, seed, _) ->-      Just <$> registerActor False itemKnown itemFullKit seed bfid pos lid time+    Just (itemKnown, itemFullKit, _) ->+      Just <$> registerActor False itemKnown itemFullKit bfid pos lid time  registerActor :: MonadServerAtomic m-              => Bool -> ItemKnown -> ItemFullKit -> IA.ItemSeed+              => Bool -> ItemKnown -> ItemFullKit               -> FactionId -> Point -> LevelId -> Time               -> m ActorId-registerActor summoned (kindIx, ar, _) (itemFullRaw, kit)-              seed bfid pos lid time = do+registerActor summoned (kindIx, ar, _) (itemFullRaw, kit) bfid pos lid time = do   let container = CTrunk bfid lid pos       jfid = Just bfid       itemKnown = (kindIx, ar, jfid)       itemFull = itemFullRaw {itemBase = (itemBase itemFullRaw) {jfid}}-  trunkId <- registerItem (itemFull, kit) itemKnown seed container False+  trunkId <- registerItem (itemFull, kit) itemKnown container False   addNonProjectile summoned trunkId (itemFull, kit) bfid pos lid time  addProjectile :: MonadServerAtomic m@@ -488,8 +464,8 @@   let itemKind = okind coitem itemKindId   if IK.onlyMinorEffects itemKind   then do-    seed <- getsServer $ (EM.! iid) . sitemSeedD-    execUpdAtomic $ UpdDiscover c iid itemKindId seed+    discoAspect <- getsState sdiscoAspect+    execUpdAtomic $ UpdDiscover c iid itemKindId $ discoAspect EM.! iid   else return ()  -- discover by use when item's effects get activated later on  pickWeaponServer :: MonadServer m => ActorId -> m (Maybe (ItemId, CStore))
Game/LambdaHack/Server/DebugM.hs view
@@ -18,7 +18,7 @@ import qualified Text.Show.Pretty as Show.Pretty  import Game.LambdaHack.Atomic-import Game.LambdaHack.Client+import Game.LambdaHack.Client (Response (..)) import Game.LambdaHack.Common.Actor import Game.LambdaHack.Common.ActorState import Game.LambdaHack.Common.Faction
Game/LambdaHack/Server/EndM.hs view
@@ -14,7 +14,7 @@ import qualified Data.EnumMap.Strict as EM  import Game.LambdaHack.Atomic-import Game.LambdaHack.Client+import Game.LambdaHack.Client (sbenchmark) import Game.LambdaHack.Common.Actor import Game.LambdaHack.Common.ActorState import Game.LambdaHack.Common.Faction@@ -32,7 +32,7 @@ import Game.LambdaHack.Server.State  -- | Continue or exit or restart the game.-endOrLoop :: (MonadServerAtomic m, MonadServerReadRequest m)+endOrLoop :: (MonadServerAtomic m, MonadServerComm m)           => m () -> (Maybe (GroupName ModeKind) -> m ())           -> m () endOrLoop loop restart = do@@ -62,7 +62,7 @@      | not $ null campers -> gameExit  -- and @loop@ is not called      | otherwise -> loop  -- continue current game -gameExit :: (MonadServerAtomic m, MonadServerReadRequest m) => m ()+gameExit :: (MonadServerAtomic m, MonadServerComm m) => m () gameExit = do --  debugPossiblyPrint "Verifying all perceptions."   -- Verify that the possibly not saved caches are equal to future
Game/LambdaHack/Server/HandleEffectM.hs view
@@ -34,7 +34,6 @@ import qualified Data.Ord as Ord  import           Game.LambdaHack.Atomic-import           Game.LambdaHack.Client import           Game.LambdaHack.Common.Actor import           Game.LambdaHack.Common.ActorState import qualified Game.LambdaHack.Common.Dice as Dice@@ -125,6 +124,18 @@         [] -> return ()         aid : _ -> execUpdAtomic $ UpdLeadFaction (bfid tb) mleader $ Just aid +cutCalm :: MonadServerAtomic m => ActorId -> m ()+cutCalm target = do+  tb <- getsState $ getActorBody target+  ar <- getsState $ getActorAspect target+  let upperBound = if hpTooLow tb ar+                   then 2  -- to trigger domination on next attack, etc.+                   else xM $ IA.aMaxCalm ar+      deltaCalm = min minusM1 (upperBound - bcalm tb)+  -- HP loss decreases Calm by at least @minusM1@ to avoid "hears something",+  -- which is emitted when decreasing Calm by @minusM@.+  udpateCalm target deltaCalm+ -- Here melee damage is applied. This is necessary so that the same -- AI benefit calculation may be used for flinging and for applying items. meleeEffectAndDestroy :: MonadServerAtomic m@@ -256,8 +267,8 @@   -- Note: @UseId@ suffices for identification, @UseUp@ is not necessary.   when (ur >= UseId && not (IK.onlyMinorEffects itemKind)) $ do     kindId <- getsState $ getIidKindIdServer iid-    seed <- getsServer $ (EM.! iid) . sitemSeedD-    execUpdAtomic $ UpdDiscover c iid kindId seed+    discoAspect <- getsState sdiscoAspect+    execUpdAtomic $ UpdDiscover c iid kindId $ discoAspect EM.! iid   return ur  -- | The source actor affects the target actor, with a given effect and power.@@ -389,14 +400,14 @@               ++ [zip (repeat True)                   $ take 8 (drop ((k100 + fuzz) `mod` 8) $ cycle psFuzz)]         forM_ ps $ \(centerRaw, tpxy) -> do-          let req = ReqProject tpxy veryrandom iid COrgan-              center = centerRaw && itemK >= 8  -- if few, keep them regular+          let center = centerRaw && itemK >= 8  -- if few, keep them regular           mfail <- projectFail target tpxy veryrandom center iid COrgan True           case mfail of             Nothing -> return ()             Just ProjectBlockTerrain -> return ()             Just ProjectBlockActor | not $ bproj tb -> return ()-            Just failMsg -> execFailure target req failMsg+            Just failMsg ->+              execSfxAtomic $ SfxMsgFid (bfid tb) $ SfxUnexpected failMsg       tryFlying 0 = return ()       tryFlying k100 = do         -- Explosion particles are placed among organs of the victim:@@ -439,18 +450,6 @@        refillHP source target deltaHP        return UseUp -cutCalm :: MonadServerAtomic m => ActorId -> m ()-cutCalm target = do-  tb <- getsState $ getActorBody target-  ar <- getsState $ getActorAspect target-  let upperBound = if hpTooLow tb ar-                   then 0  -- to trigger domination, etc.-                   else xM $ IA.aMaxCalm ar-      deltaCalm = min minusM1 (upperBound - bcalm tb)-  -- HP loss decreases Calm by at least @minusM1@ to avoid "hears something",-  -- which is emitted when decreasing Calm by @minusM@.-  udpateCalm target deltaCalm- -- ** RefillCalm  effectRefillCalm :: MonadServerAtomic m@@ -974,9 +973,9 @@   bagBefore <- getsState $ getBodyStoreBag tb store   let litemFreq = [(grp, 1)]   -- Power depth of new items unaffected by number of spawned actors.-  m4 <- rollItem 0 (blid tb) litemFreq-  let (itemKnownRaw, (itemFullRaw, kitRaw), seed, _) =-        fromMaybe (error $ "" `showFailure` (blid tb, litemFreq, c)) m4+  m3 <- rollItem 0 (blid tb) litemFreq+  let (itemKnownRaw, (itemFullRaw, kitRaw), _) =+        fromMaybe (error $ "" `showFailure` (blid tb, litemFreq, c)) m3       -- Avoid too many different item identifiers (one for each faction)       -- for blasts or common item generating tiles. Temporary organs are       -- allowed to be duplicated, because they provide really useful info@@ -1019,7 +1018,7 @@       -- No such items or some items, but void delta, so create items.       -- If it's, e.g., a periodic poison, the new items will stack with any       -- already existing items.-      iid <- registerItem (itemFull, kitNew) itemKnown seed c True+      iid <- registerItem (itemFull, kitNew) itemKnown c True       -- If created not on the ground, ID it, because it won't be on pickup.       when (store /= CGround) $         discoverIfMinorEffects c iid (itemKindId itemFull)@@ -1178,8 +1177,8 @@ identifyIid :: MonadServerAtomic m             => ItemId -> Container -> ContentId ItemKind -> m () identifyIid iid c itemKindId = do-  seed <- getsServer $ (EM.! iid) . sitemSeedD-  execUpdAtomic $ UpdDiscover c iid itemKindId seed+  discoAspect <- getsState sdiscoAspect+  execUpdAtomic $ UpdDiscover c iid itemKindId $ discoAspect EM.! iid  -- ** Detect 
Game/LambdaHack/Server/HandleRequestM.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE GADTs #-} -- | Semantics of requests -- . -- A couple of them do not take time, the rest does.@@ -13,9 +12,9 @@   , reqMove, reqDisplace, reqAlterFail, reqGameDropAndExit, reqGameSaveAndExit #ifdef EXPOSE_INTERNAL     -- * Internal operations-  , setBWait, managePerRequest, handleRequestTimedCases-  , affectSmell, reqMelee, reqAlter, reqWait-  , reqMoveItems, reqMoveItem, computeRndTimeout, reqProject, reqApply+  , execFailure, setBWait, managePerRequest, handleRequestTimedCases+  , affectSmell, reqMelee, reqMeleeChecked, reqAlter+  , reqWait, reqMoveItems, reqMoveItem, computeRndTimeout, reqProject, reqApply   , reqGameRestart, reqGameSave, reqTactic, reqAutomate #endif   ) where@@ -25,9 +24,12 @@ import Game.LambdaHack.Common.Prelude  import qualified Data.EnumMap.Strict as EM+import qualified Data.Text as T+import qualified Text.Show.Pretty as Show.Pretty  import           Game.LambdaHack.Atomic-import           Game.LambdaHack.Client+import           Game.LambdaHack.Client (ReqAI (..), ReqUI (..),+                                         RequestTimed (..)) import qualified Game.LambdaHack.Common.Ability as Ability import           Game.LambdaHack.Common.Actor import           Game.LambdaHack.Common.ActorState@@ -56,11 +58,31 @@ import           Game.LambdaHack.Server.ServerOptions import           Game.LambdaHack.Server.State +execFailure :: MonadServerAtomic m+            => ActorId -> RequestTimed -> ReqFailure -> m ()+execFailure aid req failureSer = do+  -- Clients should rarely do that (only in case of invisible actors)+  -- so we report it to the client, but do not crash+  -- (server should work OK with stupid clients, too).+  body <- getsState $ getActorBody aid+  let fid = bfid body+      msg = showReqFailure failureSer+      impossible = impossibleReqFailure failureSer+      debugShow :: Show a => a -> Text+      debugShow = T.pack . Show.Pretty.ppShow+      possiblyAlarm = if impossible+                      then debugPossiblyPrintAndExit+                      else debugPossiblyPrint+  possiblyAlarm $+    "execFailure:" <+> msg <> "\n"+    <> debugShow body <> "\n" <> debugShow req <> "\n" <> debugShow failureSer+  execSfxAtomic $ SfxMsgFid fid $ SfxUnexpected failureSer+ -- | The semantics of server commands. -- AI always takes time and so doesn't loop. handleRequestAI :: MonadServerAtomic m                 => ReqAI-                -> m (Maybe RequestAnyAbility)+                -> m (Maybe RequestTimed) handleRequestAI cmd = case cmd of   ReqAITimed cmdT -> return $ Just cmdT   ReqAINop -> return Nothing@@ -68,7 +90,7 @@ -- | The semantics of server commands. Only the first two cases affect time. handleRequestUI :: MonadServerAtomic m                 => FactionId -> ActorId -> ReqUI-                -> m (Maybe RequestAnyAbility)+                -> m (Maybe RequestTimed) handleRequestUI fid aid cmd = case cmd of   ReqUITimed cmdT -> return $ Just cmdT   ReqUIGameRestart t d -> reqGameRestart aid t d >> return Nothing@@ -83,7 +105,7 @@ -- and unsetting in all other requests, we call this once before -- executing a request. setBWait :: MonadServerAtomic m-         => RequestTimed a -> ActorId -> Actor -> m (Maybe Bool)+         => RequestTimed -> ActorId -> Actor -> m (Maybe Bool) {-# INLINE setBWait #-} setBWait cmd aid b = do   let mwait = case cmd of@@ -95,7 +117,7 @@   return mwait  handleRequestTimed :: MonadServerAtomic m-                   => FactionId -> ActorId -> RequestTimed a -> m Bool+                   => FactionId -> ActorId -> RequestTimed -> m Bool handleRequestTimed fid aid cmd = do   b <- getsState $ getActorBody aid   mwait <- setBWait cmd aid b@@ -123,7 +145,7 @@     execUpdAtomic $ UpdRefillHP aid clearMark  handleRequestTimedCases :: MonadServerAtomic m-                        => ActorId -> RequestTimed a -> m ()+                        => ActorId -> RequestTimed -> m () handleRequestTimedCases aid cmd = case cmd of   ReqMove target -> reqMove aid target   ReqMelee target iid cstore -> reqMelee aid target iid cstore@@ -206,8 +228,11 @@ reqMove :: MonadServerAtomic m => ActorId -> Vector -> m () reqMove source dir = do   COps{coTileSpeedup} <- getsState scops+  actorSk <- currentSkillsServer source   sb <- getsState $ getActorBody source-  let lid = blid sb+  let abInSkill ab = isJust (btrajectory sb)+                     || EM.findWithDefault 0 ab actorSk > 0+      lid = blid sb   lvl <- getLevel lid   let spos = bpos sb           -- source position       tpos = spos `shift` dir  -- target position@@ -250,15 +275,20 @@       -- Below the only weapon (the only item) of projectiles is picked.       mweapon <- pickWeaponServer source       case mweapon of-        Nothing -> reqWait source-        Just (wp, cstore) -> reqMelee source target wp cstore-    _ | Tile.isWalkable coTileSpeedup $ lvl `at` tpos -> do-          -- Movement requires full access.+        Just (wp, cstore) | abInSkill Ability.AbMelee ->+          reqMeleeChecked source target wp cstore+        _ -> return ()  -- waiting, even if no @AbWait@ ability+    _ -> do+      -- Either the position is empty, or all involved actors are proj.+      -- Movement requires full access and skill.+      if Tile.isWalkable coTileSpeedup $ lvl `at` tpos then+        if abInSkill Ability.AbMove then do           execUpdAtomic $ UpdMoveActor source spos tpos           affectSmell source-      | otherwise ->-          -- Client foolishly tries to move into blocked, boring tile.-          execFailure source (ReqMove dir) MoveNothing+        else execFailure source (ReqMove dir) MoveUnskilled+      else+        -- Client foolishly tries to move into unwalkable tile.+        execFailure source (ReqMove dir) MoveNothing  -- * ReqMelee @@ -272,6 +302,14 @@ reqMelee :: MonadServerAtomic m          => ActorId -> ActorId -> ItemId -> CStore -> m () reqMelee source target iid cstore = do+  actorSk <- currentSkillsServer source+  if EM.findWithDefault 0 Ability.AbMelee actorSk > 0 then+    reqMeleeChecked source target iid cstore+  else execFailure source (ReqMelee target iid cstore) MeleeUnskilled++reqMeleeChecked :: MonadServerAtomic m+                => ActorId -> ActorId -> ItemId -> CStore -> m ()+reqMeleeChecked source target iid cstore = do   sb <- getsState $ getActorBody source   tb <- getsState $ getActorBody target   let req = ReqMelee target iid cstore@@ -371,7 +409,10 @@ reqDisplace :: MonadServerAtomic m => ActorId -> ActorId -> m () reqDisplace source target = do   COps{coTileSpeedup} <- getsState scops+  actorSk <- currentSkillsServer source   sb <- getsState $ getActorBody source+  let abInSkill ab = isJust (btrajectory sb)+                     || EM.findWithDefault 0 ab actorSk > 0   tb <- getsState $ getActorBody target   tfact <- getsState $ (EM.! bfid tb) . sfactionD   let tpos = bpos tb@@ -379,7 +420,9 @@       req = ReqDisplace target   ar <- getsState $ getActorAspect target   dEnemy <- getsState $ dispEnemy source target $ IA.aSkills ar-  if | not (checkAdjacent sb tb) -> execFailure source req DisplaceDistant+  if | not (abInSkill Ability.AbDisplace) ->+         execFailure source req DisplaceUnskilled+     | not (checkAdjacent sb tb) -> execFailure source req DisplaceDistant      | atWar && not dEnemy -> do  -- if not at war, can displace always        -- We don't fail with DisplaceImmobile and DisplaceSupported.        -- because it's quite common they can't be determined by the attacker,@@ -389,8 +432,9 @@        -- verify here that they don't occur, for simplicity.        mweapon <- pickWeaponServer source        case mweapon of-         Nothing -> reqWait source-         Just (wp, cstore) -> reqMelee source target wp cstore+         Just (wp, cstore) | abInSkill Ability.AbMelee ->+           reqMeleeChecked source target wp cstore+         _ -> return ()  -- waiting, even if no @AbWait@ ability      | otherwise -> do        let lid = blid sb        lvl <- getLevel lid@@ -573,19 +617,25 @@ -- Something is sometimes done in 'setBWait'. reqWait :: MonadServerAtomic m => ActorId -> m () {-# INLINE reqWait #-}-reqWait _ = return ()+reqWait source = do+  actorSk <- currentSkillsServer source+  unless (EM.findWithDefault 0 Ability.AbWait actorSk > 0) $+    execFailure source ReqWait WaitUnskilled  -- * ReqMoveItems  reqMoveItems :: MonadServerAtomic m              => ActorId -> [(ItemId, Int, CStore, CStore)] -> m ()-reqMoveItems aid l = do-  b <- getsState $ getActorBody aid-  ar <- getsState $ getActorAspect aid-  -- Server accepts item movement based on calm at the start, not end-  -- or in the middle, to avoid interrupted or partially ignored commands.-  let calmE = calmEnough b ar-  mapM_ (reqMoveItem aid calmE) l+reqMoveItems source l = do+  actorSk <- currentSkillsServer source+  if EM.findWithDefault 0 Ability.AbMoveItem actorSk > 0 then do+    b <- getsState $ getActorBody source+    ar <- getsState $ getActorAspect source+    -- Server accepts item movement based on calm at the start, not end+    -- or in the middle, to avoid interrupted or partially ignored commands.+    let calmE = calmEnough b ar+    mapM_ (reqMoveItem source calmE) l+  else execFailure source (ReqMoveItems l) MoveItemUnskilled  reqMoveItem :: MonadServerAtomic m             => ActorId -> Bool -> (ItemId, Int, CStore, CStore) -> m ()
Game/LambdaHack/Server/ItemM.hs view
@@ -23,7 +23,6 @@ import           Game.LambdaHack.Common.ActorState import           Game.LambdaHack.Common.ContentData import           Game.LambdaHack.Common.Item-import qualified Game.LambdaHack.Common.ItemAspect as IA import           Game.LambdaHack.Common.Kind import           Game.LambdaHack.Common.Level import           Game.LambdaHack.Common.Misc@@ -42,8 +41,8 @@ import           Game.LambdaHack.Server.ServerOptions import           Game.LambdaHack.Server.State -onlyRegisterItem :: MonadServerAtomic m => ItemKnown -> IA.ItemSeed -> m ItemId-onlyRegisterItem itemKnown@(_, aspectRecord, _) seed = do+onlyRegisterItem :: MonadServerAtomic m => ItemKnown -> m ItemId+onlyRegisterItem itemKnown@(_, aspectRecord, _) = do   itemRev <- getsServer sitemRev   case HM.lookup itemKnown itemRev of     Just iid -> return iid@@ -53,17 +52,16 @@         execUpdAtomicSer $ UpdDiscoverServer icounter aspectRecord       let !_A = assert executedOnServer ()       modifyServer $ \ser ->-        ser { sitemSeedD = EM.insert icounter seed (sitemSeedD ser)-            , sitemRev = HM.insert itemKnown icounter (sitemRev ser)+        ser { sitemRev = HM.insert itemKnown icounter (sitemRev ser)             , sicounter = succ icounter }       return $! icounter  registerItem :: MonadServerAtomic m-             => ItemFullKit -> ItemKnown -> IA.ItemSeed -> Container -> Bool+             => ItemFullKit -> ItemKnown -> Container -> Bool              -> m ItemId registerItem (ItemFull{itemBase, itemKindId, itemKind}, kit)-             itemKnown seed container verbose = do-  iid <- onlyRegisterItem itemKnown seed+             itemKnown@(_, aspectRecord, _) container verbose = do+  iid <- onlyRegisterItem itemKnown   let cmd = if verbose then UpdCreateItem else UpdSpotItem False   execUpdAtomic $ cmd iid itemBase kit container   let worth = itemPrice (fst kit) itemKind@@ -71,7 +69,7 @@   knowItems <- getsServer $ sknowItems . soptions   when knowItems $ case container of     CTrunk{} -> return ()-    _ -> execUpdAtomic $ UpdDiscover container iid itemKindId seed+    _ -> execUpdAtomic $ UpdDiscover container iid itemKindId aspectRecord   return iid  createLevelItem :: MonadServerAtomic m => Point -> LevelId -> m ()@@ -93,7 +91,7 @@  rollItem :: MonadServerAtomic m          => Int -> LevelId -> Freqs ItemKind-         -> m (Maybe (ItemKnown, ItemFullKit, IA.ItemSeed, GroupName ItemKind))+         -> m (Maybe (ItemKnown, ItemFullKit, GroupName ItemKind)) rollItem lvlSpawned lid itemFreq = do   cops <- getsState scops   flavour <- getsServer sflavour@@ -101,15 +99,15 @@   uniqueSet <- getsServer suniqueSet   totalDepth <- getsState stotalDepth   Level{ldepth} <- getLevel lid-  m4 <- rndToAction $ newItem cops flavour discoRev uniqueSet+  m3 <- rndToAction $ newItem cops flavour discoRev uniqueSet                               itemFreq lvlSpawned lid ldepth totalDepth-  case m4 of-    Just (_, (ItemFull{itemKindId, itemKind}, _), _, _) ->+  case m3 of+    Just (_, (ItemFull{itemKindId, itemKind}, _), _) ->       when (IK.Unique `elem` IK.ifeature itemKind) $         modifyServer $ \ser ->           ser {suniqueSet = ES.insert itemKindId (suniqueSet ser)}     _ -> return ()-  return m4+  return m3  rollAndRegisterItem :: MonadServerAtomic m                     => LevelId -> Freqs ItemKind -> Container -> Bool@@ -117,12 +115,12 @@                     -> m (Maybe (ItemId, (ItemFullKit, GroupName ItemKind))) rollAndRegisterItem lid itemFreq container verbose mk = do   -- Power depth of new items unaffected by number of spawned actors.-  m4 <- rollItem 0 lid itemFreq-  case m4 of+  m3 <- rollItem 0 lid itemFreq+  case m3 of     Nothing -> return Nothing-    Just (itemKnown, (itemFull, kit), seed, itemGroup) -> do+    Just (itemKnown, (itemFull, kit), itemGroup) -> do       let kit2 = (fromMaybe (fst kit) mk, snd kit)-      iid <- registerItem (itemFull, kit2) itemKnown seed container verbose+      iid <- registerItem (itemFull, kit2) itemKnown container verbose       return $ Just (iid, ((itemFull, kit2), itemGroup))  placeItemsInDungeon :: forall m. MonadServerAtomic m
Game/LambdaHack/Server/ItemRev.hs view
@@ -4,7 +4,7 @@ module Game.LambdaHack.Server.ItemRev   ( ItemKnown, ItemRev, UniqueSet, buildItem, newItem     -- * Item discovery types-  , DiscoveryKindRev, ItemSeedDict, emptyDiscoveryKindRev, serverDiscos+  , DiscoveryKindRev, emptyDiscoveryKindRev, serverDiscos     -- * The @FlavourMap@ type   , FlavourMap, emptyFlavourMap, dungeonFlavourMap   ) where@@ -42,7 +42,7 @@ -- However, the first item generated by the server wins, which in case -- of normal items (not organs), is most of the time the lower absolute -- @jlid@ (shallower depth) item, which makes sense for the client.--- Note 2: @ItemSeed@ instead of @AspectRecord@ is not enough,+-- Note 2: item seed instead of @AspectRecord@ is not enough, -- becaused different seeds may result in the same @AspectRecord@ -- and we don't want such items to be distinct in UI and elsewhere. type ItemKnown = (ItemIdentity, IA.AspectRecord, Maybe FactionId)@@ -73,7 +73,7 @@ -- | Generate an item based on level. newItem :: COps -> FlavourMap -> DiscoveryKindRev -> UniqueSet         -> Freqs ItemKind -> Int -> LevelId -> Dice.AbsDepth -> Dice.AbsDepth-        -> Rnd (Maybe (ItemKnown, ItemFullKit, IA.ItemSeed, GroupName ItemKind))+        -> Rnd (Maybe (ItemKnown, ItemFullKit, GroupName ItemKind)) newItem cops@COps{coitem} flavourMap discoRev uniqueSet         itemFreq lvlSpawned lid         ldepth@(Dice.AbsDepth ldAbs) totalDepth@(Dice.AbsDepth depth) = do@@ -110,21 +110,18 @@     ((itemKindId, itemKind), itemGroup) <- frequency freq     -- Number of new items/actors unaffected by number of spawned actors.     itemN <- castDice ldepth totalDepth (IK.icount itemKind)-    seed <- toEnum <$> random     let itemBase = buildItem cops flavourMap discoRev itemKindId itemKind lid         itemIdentity = jkind itemBase         itemK = max 1 itemN         itemTimer = [timeZero | IK.Periodic `elem` IK.ifeature itemKind]                       -- delay first discharge of single organs         itemSuspect = False-        itemDisco = ItemDiscoFull {..}         -- Bonuses on items/actors unaffected by number of spawned actors.-        itemAspect =-          IA.seedToAspect seed (IK.iaspects itemKind) ldepth totalDepth+    itemAspect <- IA.rollAspectRecord (IK.iaspects itemKind) ldepth totalDepth+    let itemDisco = ItemDiscoFull {..}         itemFull = ItemFull {..}     return $ Just ( (itemIdentity, itemAspect, jfid itemBase)                   , (itemFull, (itemK, itemTimer))-                  , seed                   , itemGroup )  -- | The reverse map to @DiscoveryKind@, needed for item creation.@@ -132,9 +129,6 @@ -- Morally, it's indexed by @ContentId ItemKind@ and elements are @ItemKindIx@. newtype DiscoveryKindRev = DiscoveryKindRev (U.Vector Word16)   deriving (Show, Binary)---- | The map of item ids to item seeds, needed for item creation.-type ItemSeedDict = EM.EnumMap ItemId IA.ItemSeed  emptyDiscoveryKindRev :: DiscoveryKindRev emptyDiscoveryKindRev = DiscoveryKindRev U.empty
Game/LambdaHack/Server/LoopM.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE GADTs #-} -- | The main loop of the server, processing human and computer player -- moves turn by turn. module Game.LambdaHack.Server.LoopM@@ -21,7 +20,7 @@ import qualified Data.Ord as Ord  import           Game.LambdaHack.Atomic-import           Game.LambdaHack.Client+import           Game.LambdaHack.Client (ReqUI (..)) import           Game.LambdaHack.Common.Actor import           Game.LambdaHack.Common.ActorState import           Game.LambdaHack.Common.Faction@@ -53,7 +52,7 @@ -- communicating with the clients. -- -- The loop is started in server state that is empty, see 'emptyStateServer'.-loopSer :: (MonadServerAtomic m, MonadServerReadRequest m)+loopSer :: (MonadServerAtomic m, MonadServerComm m)         => ServerOptions              -- ^ player-supplied server options         -> (Bool -> FactionId -> ChanServer -> IO ())@@ -129,7 +128,7 @@                     `swith` factionD) ()   return $! arenas -handleFidUpd :: (MonadServerAtomic m, MonadServerReadRequest m)+handleFidUpd :: (MonadServerAtomic m, MonadServerComm m)              => (FactionId -> m ()) -> FactionId -> Faction -> m () {-# INLINE handleFidUpd #-} handleFidUpd updatePerFid fid fact = do@@ -159,7 +158,7 @@ -- | Handle a clip (the smallest fraction of a game turn for which a frame may -- potentially be generated). Run the leader and other actors moves. -- Eventually advance the time and repeat.-loopUpd :: forall m. (MonadServerAtomic m, MonadServerReadRequest m)+loopUpd :: forall m. (MonadServerAtomic m, MonadServerComm m)         => m () -> m () loopUpd updConn = do   let updatePerFid :: FactionId -> m ()@@ -436,7 +435,7 @@       $ execUpdAtomic $ UpdTrajectory aid (btrajectory b) Nothing     _ -> error $ "Nothing trajectory" `showFailure` (aid, b) -handleActors :: (MonadServerAtomic m, MonadServerReadRequest m)+handleActors :: (MonadServerAtomic m, MonadServerComm m)              => LevelId -> FactionId -> m Bool handleActors lid fid = do   localTime <- getsState $ getLocalTime lid@@ -460,7 +459,7 @@     Just aid | aid `elem` l -> aid : delete aid l     _ -> l -hActors :: forall m. (MonadServerAtomic m, MonadServerReadRequest m)+hActors :: forall m. (MonadServerAtomic m, MonadServerComm m)         => [ActorId] -> m Bool hActors [] = return False hActors as@(aid : rest) = do@@ -506,7 +505,7 @@         mtimed <- handleRequestUI side aidNew cmd         return (aidNew, mtimed)     case mtimed of-      Just (RequestAnyAbility timed) -> do+      Just timed -> do         nonWaitMove <- handleRequestTimed side aidNew timed         -- Even if the actor got a free turn of time via a scroll,         -- he will not act again this clip, only next clip.
Game/LambdaHack/Server/MonadServer.hs view
@@ -33,7 +33,7 @@ import qualified System.Random as R  import           Game.LambdaHack.Atomic-import           Game.LambdaHack.Client+import           Game.LambdaHack.Client (sbenchmark) import           Game.LambdaHack.Common.ActorState import           Game.LambdaHack.Common.Faction import           Game.LambdaHack.Common.File
Game/LambdaHack/Server/PeriodicM.hs view
@@ -83,10 +83,10 @@   lvl <- getLevel lid   factionD <- getsState sfactionD   lvlSpawned <- getsServer $ fromMaybe 0 . EM.lookup lid . snumSpawned-  m4 <- rollItem lvlSpawned lid actorFreq-  case m4 of+  m3 <- rollItem lvlSpawned lid actorFreq+  case m3 of     Nothing -> return Nothing-    Just (itemKnownRaw, (itemFullRaw, kit), seed, _) -> do+    Just (itemKnownRaw, (itemFullRaw, kit), _) -> do       let freqNames = map fst $ IK.ifreq $ itemKind itemFullRaw           f fact = fgroups (gplayer fact)           factGroups = concatMap f $ EM.elems factionD@@ -110,7 +110,7 @@           rollPos <- getsState $ rollSpawnPos cops allPers mobile lid lvl fid           rndToAction rollPos       Just <$> registerActor summoned itemKnownRaw (itemFullRaw, kit)-                             seed fid pos lid time+                             fid pos lid time  rollSpawnPos :: COps -> ES.EnumSet Point              -> Bool -> LevelId -> Level -> FactionId -> State
Game/LambdaHack/Server/ProtocolM.hs view
@@ -3,7 +3,7 @@   ( -- * The communication channels     CliSerQueue, ConnServerDict, ChanServer(..)     -- * The server-client communication monad-  , MonadServerReadRequest+  , MonadServerComm       ( getsDict  -- exposed only to be implemented, not used       , modifyDict  -- exposed only to be implemented, not used       , liftIO  -- exposed only to be implemented, not used@@ -31,7 +31,8 @@ import           System.IO.Unsafe (unsafePerformIO)  import           Game.LambdaHack.Atomic-import           Game.LambdaHack.Client+import           Game.LambdaHack.Client (RequestAI, RequestUI, Response (..),+                                         sbenchmark) import           Game.LambdaHack.Common.Actor import           Game.LambdaHack.Common.Faction import           Game.LambdaHack.Common.File@@ -48,17 +49,17 @@ import           Game.LambdaHack.Server.ServerOptions import           Game.LambdaHack.Server.State -writeQueue :: MonadServerReadRequest m+writeQueue :: MonadServerComm m            => Response -> CliSerQueue Response -> m () {-# INLINE writeQueue #-} writeQueue cmd responseS = liftIO $ putMVar responseS cmd -readQueueAI :: MonadServerReadRequest m+readQueueAI :: MonadServerComm m             => CliSerQueue RequestAI -> m RequestAI {-# INLINE readQueueAI #-} readQueueAI requestS = liftIO $ takeMVar requestS -readQueueUI :: MonadServerReadRequest m+readQueueUI :: MonadServerComm m             => CliSerQueue RequestUI -> m RequestUI {-# INLINE readQueueUI #-} readQueueUI requestS = liftIO $ takeMVar requestS@@ -79,20 +80,20 @@   }  -- | The server monad with the ability to communicate with clients.-class MonadServer m => MonadServerReadRequest m where+class MonadServer m => MonadServerComm m where   getsDict     :: (ConnServerDict -> a) -> m a   modifyDict   :: (ConnServerDict -> ConnServerDict) -> m ()   liftIO       :: IO a -> m a -getDict :: MonadServerReadRequest m => m ConnServerDict+getDict :: MonadServerComm m => m ConnServerDict getDict = getsDict id -putDict :: MonadServerReadRequest m => ConnServerDict -> m ()+putDict :: MonadServerComm m => ConnServerDict -> m () putDict s = modifyDict (const s)  -- | If the @AtomicFail@ conditions hold, send a command to client, -- otherwise do nothing.-sendUpdate :: (MonadServerAtomic m, MonadServerReadRequest m)+sendUpdate :: (MonadServerAtomic m, MonadServerComm m)            => FactionId -> UpdAtomic -> m () sendUpdate !fid !cmd = do   succeeded <- execUpdAtomicFidCatch fid cmd@@ -100,13 +101,13 @@  -- | Send a command to client, crashing if the @AtomicFail@ conditions -- don't hold when executed on the client's state.-sendUpdateCheck :: (MonadServerAtomic m, MonadServerReadRequest m)+sendUpdateCheck :: (MonadServerAtomic m, MonadServerComm m)                 => FactionId -> UpdAtomic -> m () sendUpdateCheck !fid !cmd = do   execUpdAtomicFid fid cmd   sendUpd fid cmd -sendUpd :: MonadServerReadRequest m => FactionId -> UpdAtomic -> m ()+sendUpd :: MonadServerComm m => FactionId -> UpdAtomic -> m () sendUpd !fid !cmd = do   chan <- getsDict (EM.! fid)   s <- getsServer $ (EM.! fid) . sclientStates@@ -115,7 +116,7 @@   when debug $ debugResponse fid resp   writeQueue resp $ responseS chan -sendUpdNoState :: MonadServerReadRequest m => FactionId -> UpdAtomic -> m ()+sendUpdNoState :: MonadServerComm m => FactionId -> UpdAtomic -> m () sendUpdNoState !fid !cmd = do   chan <- getsDict (EM.! fid)   let resp = RespUpdAtomicNoState cmd@@ -123,7 +124,7 @@   when debug $ debugResponse fid resp   writeQueue resp $ responseS chan -sendSfx :: MonadServerReadRequest m => FactionId -> SfxAtomic -> m ()+sendSfx :: MonadServerComm m => FactionId -> SfxAtomic -> m () sendSfx !fid !sfx = do   let resp = RespSfxAtomic sfx   debug <- getsServer $ sniff . soptions@@ -133,7 +134,7 @@     ChanServer{requestUIS=Just{}} -> writeQueue resp $ responseS chan     _ -> return () -sendQueryAI :: MonadServerReadRequest m => FactionId -> ActorId -> m RequestAI+sendQueryAI :: MonadServerComm m => FactionId -> ActorId -> m RequestAI sendQueryAI fid aid = do   let respAI = RespQueryAI aid   debug <- getsServer $ sniff . soptions@@ -145,7 +146,7 @@   when debug $ debugRequestAI aid   return req -sendQueryUI :: (MonadServerAtomic m, MonadServerReadRequest m)+sendQueryUI :: (MonadServerAtomic m, MonadServerComm m)             => FactionId -> ActorId -> m RequestUI sendQueryUI fid _aid = do   let respUI = RespQueryUI@@ -158,7 +159,7 @@   when debug $ debugRequestUI _aid   return req -killAllClients :: (MonadServerAtomic m, MonadServerReadRequest m) => m ()+killAllClients :: (MonadServerAtomic m, MonadServerComm m) => m () killAllClients = do   d <- getDict   let sendKill fid _ = sendUpdNoState fid $ UpdKillExit fid@@ -174,7 +175,7 @@ -- | Update connections to the new definition of factions. -- Connect to clients in old or newly spawned threads -- that read and write directly to the channels.-updateConn :: (MonadServerAtomic m, MonadServerReadRequest m)+updateConn :: (MonadServerAtomic m, MonadServerComm m)            => (Bool -> FactionId -> ChanServer -> IO ())            -> m () updateConn executorClient = do@@ -211,7 +212,7 @@         forkUI fid conn   liftIO $ mapWithKeyM_ forkClient toSpawn -tryRestore :: MonadServerReadRequest m => m (Maybe (State, StateServer))+tryRestore :: MonadServerComm m => m (Maybe (State, StateServer)) tryRestore = do   cops <- getsState scops   soptions <- getsServer soptions
Game/LambdaHack/Server/ServerOptions.hs view
@@ -10,7 +10,7 @@ import           Data.Binary import qualified System.Random as R -import Game.LambdaHack.Client+import Game.LambdaHack.Client (ClientOptions (..), defClientOptions) import Game.LambdaHack.Common.Faction import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ModeKind
Game/LambdaHack/Server/StartM.hs view
@@ -186,8 +186,9 @@       rnd :: Rnd (FactionDict, FlavourMap, DiscoveryKind, DiscoveryKindRev,                   DungeonGen.FreshDungeon, ContentId ModeKind)       rnd = do-        modeKindId <- fromMaybe (error $ "" `showFailure` gameMode)-                      <$> opick comode gameMode (const True)+        modeKindId <-+          fromMaybe (error $ "Unknown game mode:" `showFailure` gameMode)+          <$> opick comode gameMode (const True)         let mode = okind comode modeKindId             automatePS ps = ps {rosterList =               map (first $ automatePlayer True) $ rosterList ps}
Game/LambdaHack/Server/State.hs view
@@ -36,7 +36,6 @@   , sdiscoKindRev :: DiscoveryKindRev                                     -- ^ reverse map, used for item creation   , suniqueSet    :: UniqueSet      -- ^ already generated unique items-  , sitemSeedD    :: ItemSeedDict   -- ^ map from item ids to item seeds   , sitemRev      :: ItemRev        -- ^ reverse id map, used for item creation   , sflavour      :: FlavourMap     -- ^ association of flavour to items   , sacounter     :: ActorId        -- ^ stores next actor index@@ -76,7 +75,6 @@     , sactorStasis = ES.empty     , sdiscoKindRev = emptyDiscoveryKindRev     , suniqueSet = ES.empty-    , sitemSeedD = EM.empty     , sitemRev = HM.empty     , sflavour = emptyFlavourMap     , sacounter = toEnum 0@@ -118,7 +116,6 @@     put sactorStasis     put sdiscoKindRev     put suniqueSet-    put sitemSeedD     put sitemRev     put sflavour     put sacounter@@ -133,7 +130,6 @@     sactorStasis <- get     sdiscoKindRev <- get     suniqueSet <- get-    sitemSeedD <- get     sitemRev <- get     sflavour <- get     sacounter <- get
GameDefinition/Content/CaveKind.hs view
@@ -121,8 +121,8 @@   { csymbol       = 'E'   , cname         = "Tall cavern"   , cfreq         = [("caveEmpty", 1)]-  , cgrid         = DiceXY 1 1-  , cminPlaceSize = DiceXY 12 12+  , cgrid         = DiceXY 2 2+  , cminPlaceSize = DiceXY 12 9   , cmaxPlaceSize = DiceXY 48 32  -- favour large rooms   , cdarkChance   = 1 `d` 100 + 1 `dL` 100   , cnightChance  = 0  -- always day
GameDefinition/Content/ItemKind.hs view
@@ -233,7 +233,8 @@ light1 = ItemKind   { isymbol  = symbolLight   , iname    = "wooden torch"-  , ifreq    = [("common item", 100), ("light source", 100), ("wooden torch", 1)]+  , ifreq    = [ ("common item", 100), ("light source", 100)+               , ("wooden torch", 1) ]   , iflavour = zipPlain [Brown]   , icount   = 1 `dL` 4   , irarity  = [(1, 15)]@@ -245,7 +246,7 @@   , ieffects = [Burn 1]   , ifeature = [Lobable, Equipable, EqpSlot EqpSlotLightSource]                  -- not Fragile; reusable flare-  , idesc    = "A smoking, heavy wooden torch, burning in an unsteady glow."+  , idesc    = "A heavy smoking wooden torch, improvised using a cloth soaked in tar, burning in an unsteady glow."   , ikit     = []   } light2 = ItemKind
GameDefinition/Content/RuleKind.hs view
@@ -44,17 +44,10 @@   -- The keybindings overwrite places marked with left curly brace signs.   -- This sign is forbidden anywhere else in the picture.   -- The picture and the whole main menu is displayed dull white on black.-  ---  -- The picture should be exactly 60 rows by 110 columns,-  -- but only the middle rectangle of 24 rows by 80 columns is partially-  -- overwritten with UI information and the curly brace signs are allowed-  -- only there. So, the rectangle is 15 characters distant from the left-  -- and 18 from top. For screen sizes larger than 60 by 100,-  -- the picture is centered and padded with spaces, so it makes sense-  -- for some or all of the picture borders to be spaces, as well.-  -- If the screen is smaller than 60 by 100, borders of the picture-  -- are cut off. Minimal screes size is 24 by 80 and the picture-  -- should look well at this size, as well.+  -- The glyphs, or at least the character cells, are perfect squares.+  -- The picture should be exactly 45 rows by 80 columns.+  -- For larger screen sizes, the picture is centered and padded with spaces,+  -- so it makes sense for some or all of the picture borders to be spaces.   , rmainMenuArt = $(do       let path = "GameDefinition/MainMenu.ascii"       qAddDependentFile path
GameDefinition/Content/TileKind.hs view
@@ -117,7 +117,6 @@   , talter   = 2   , tfeature = [ RevealAs "trapped vertical door Lit"                , ObscureAs "obscured vertical wall Lit"-                ]   } wallObscured = TileKind@@ -129,7 +128,6 @@   , talter   = 5   , tfeature = [ Embed "scratch on wall"                , HideAs "suspect vertical wall Lit"-                ]   } wallH = TileKind@@ -139,9 +137,7 @@   , tcolor   = BrWhite   , tcolor2  = defFG   , talter   = 100-  , tfeature = [ BuildAs "suspect horizontal wall Lit"--               ]+  , tfeature = [BuildAs "suspect horizontal wall Lit"]   } wallSuspectH = TileKind  -- only on client   { tsymbol  = '-'@@ -152,7 +148,6 @@   , talter   = 2   , tfeature = [ RevealAs "trapped horizontal door Lit"                , ObscureAs "obscured horizontal wall Lit"-                ]   } wallObscuredDefacedH = TileKind@@ -164,7 +159,6 @@   , talter   = 5   , tfeature = [ Embed "obscene pictogram"                , HideAs "suspect horizontal wall Lit"-                ]   } wallObscuredFrescoedH = TileKind@@ -176,7 +170,6 @@   , talter   = 5   , tfeature = [ Embed "subtle fresco"                , HideAs "suspect horizontal wall Lit"-                ]  -- a bit beneficial, but AI would loop if allowed to trigger                   -- so no @ConsideredByAI@   }@@ -222,7 +215,6 @@   , talter   = 5   , tfeature = [ ConsideredByAI  -- changes after use, so safe for AI                , RevealAs "signboard"  -- to display as hidden-                ]   } signboardRead = TileKind@@ -299,7 +291,6 @@   , tfeature = [ Embed "doorway trap"                , OpenTo "open vertical door Lit"                , HideAs "suspect vertical wall Lit"-                ]   } doorClosed = TileKind@@ -321,7 +312,6 @@   , tfeature = [ Embed "doorway trap"                , OpenTo "open horizontal door Lit"                , HideAs "suspect horizontal wall Lit"-                ]   } doorClosedH = TileKind
GameDefinition/Implementation/MonadClientImplementation.hs view
@@ -19,7 +19,6 @@  import           Game.LambdaHack.Atomic (MonadStateWrite (..), putState) import           Game.LambdaHack.Client-import           Game.LambdaHack.Client.ClientOptions import           Game.LambdaHack.Client.HandleAtomicM import           Game.LambdaHack.Client.HandleResponseM import           Game.LambdaHack.Client.LoopM
GameDefinition/Implementation/MonadServerImplementation.hs view
@@ -77,7 +77,7 @@   chanSaveServer = SerImplementation $ gets serToSave   liftIO         = SerImplementation . IO.liftIO -instance MonadServerReadRequest SerImplementation where+instance MonadServerComm SerImplementation where   {-# INLINE getsDict #-}   getsDict   f = SerImplementation $ gets $ f . serDict   {-# INLINE modifyDict #-}
GameDefinition/Main.hs view
@@ -8,6 +8,7 @@  import Game.LambdaHack.Common.Prelude +import           Control.Concurrent import           Control.Concurrent.Async import qualified Control.Exception as Ex import qualified Options.Applicative as OA@@ -19,9 +20,9 @@ import qualified System.IO as SIO  import Game.LambdaHack.Common.File (tryCreateDir)-import Game.LambdaHack.Common.Misc #endif +import Game.LambdaHack.Common.Misc import Game.LambdaHack.Server (serverOptionsPI)  import Implementation.TieKnot@@ -30,9 +31,14 @@ -- run the game and handle exit. main :: IO () main = do+  -- This may be broken with JS and also bloats the outcome file, so disabled. #ifndef USE_JSFILE-  -- For the case when the game is started not on a console.-  -- This is broken with JS and also bloats the outcome file.+  -- Special case hack, when the game is started not on a console.+  -- Without this, any attempt to output on stdout crashes a Windows exe+  -- (at least on Windows Vista) launched from the desktop or start menu.+  -- This is very crude and results in the inability to, e.g., process+  -- the output of @--help@ through a unix pipe. However, this should be+  -- effective on all Windows version, without the need to test all.   isTerminal <- SIO.hIsTerminalDevice SIO.stdout   unless isTerminal $ do     dataDir <- appDataDir@@ -41,12 +47,23 @@     fstderr <- SIO.openFile (dataDir </> "stderr.txt") SIO.WriteMode     GHC.IO.Handle.hDuplicateTo fstdout SIO.stdout     GHC.IO.Handle.hDuplicateTo fstderr SIO.stderr+  let fillWorkaround =+        -- Set up void workaround if nothing specific required.+        void $ tryPutMVar workaroundOnMainThreadMVar $ return () #endif   -- Fail here, not inside server code, so that savefiles are not removed,   -- because they are not the source of the failure.   !serverOptions <- OA.execParser serverOptionsPI   -- Avoid the bound thread that would slow down the communication.   a <- async $ tieKnot serverOptions+#ifndef USE_JSFILE+               `Ex.finally` fillWorkaround+  -- Run a (possibly void) workaround. It's needed for architectures/frontends+  -- that need to perform some actions on the main thread+  -- (not just any bound thread), e.g., newer OS X drawing with SDL2.+  workaround <- takeMVar workaroundOnMainThreadMVar+  workaround+#endif   resOrEx <- waitCatch a   let unwrapEx e = #if MIN_VERSION_async(2,2,1)
GameDefinition/MainMenu.ascii view
@@ -1,60 +1,45 @@-                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -               fffffjjjjtti,:Lft:                tDEGLLGEKEK;   .    .   . .  .iEDEGL.;iiij ...               -               fLLLLfffjjjti;.fL .              GDDLfGDEDEf .    .  .      .    ;LDWEGi,;iit ..               -               LD#WWELfffjjtt;.if.:           .DEGLLGEDLti,   . .    . . .        ,tLKDG ,;itt.               -               fK#WWW#DLffjjtt;:;j...        tDEGfLDEDGtK.  . LambdaHack           itLEG::;itt.               -               ;K#WWWWW Lfffjjti:.t...      tDEGfLDEDL, .                           tDGj.;itt.                -                EWWWWKW  GLffjjti: t,      tDEGLGEEDj;   <lambdahack.github.io>      tLDLi,ittj               -                EKWWWEWG  GLffjjti: tt   .tDEGGDEDGi,                                ;fEG :iitj               -                LEWWWKKK   GLfffjti: tt  tDDLGDEDGf.  {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ;jGG :iitj               -                 DWWWKDWL   DLffjjti: jt.DDLGDEDLD    {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ,jDG .ittj               -                 LEWWWEDKj   DLffjjti: jj.LGDEDLE     {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ,jDG  ittj               -                  DKKWKDEKf   GLffjjti::ff.EEDLE      {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ,fGG  ittj               -                   GWKWEDEEt   GLffjjji :fL.ELE       {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ :tGL  ittf               -                   EEWKKDGDEjt..DLfftjji.,fG:K,       {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ,fGj,.tjjf               -                    EfKGKDLGDDDGDGLffiiti ttf:.       {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ .LG;i,;itt               -                   ..EDKEKEGjiLDDfGLLfijtii;fL:       {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ jLj ,;tjtL               -                  . . KLEEKKDGLLLGLGLfffjji,;LL:,.    {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{,tfL.fijffL               -                 .......jDKEEKKKKKEDGLffffji;;LL:...  {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{j fGii tjff               -               ..........KtGDKEDEEDGLGLfffjti,;Lf:::: {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{iDf j:jffL.               -               ..........::,E,tjjifL,,LLfffjji.;fL.,: {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{fiififffL .               -                ......::,;tjLGGGGGLfji;LLfffjjt.,jft.                              ;t;i:jfff  .               -                ..:::::,;;;,iiiiiiii;;;;LLfffjjt,,;LL:  ...                       ,iiijjfffL ..               -               ..:::::,,;;;;;;;;;;;;;;;;;GLffffjt;j,jff,:::,                   ;ifLjjijifffL ..               -               .......::,,,,;;;;,,,,,,,,,:GLffffjjt:::tLiL                   LLLLGj;i,ffLLL ...               -               .    ..:::::,,,,,,,,,,, Version X.X.X (frontend: xxx, engine: LambdaHack X.X.X).               -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              -                                                                                                              +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +fffffjjjjtti,:Lft:                tDEGLLGEKEK;   .    .   . .  .iEDEGL.;iiij ...+fLLLLfffjjjti;.fL .              GDDLfGDEDEf .    .  .      .    ;LDWEGi,;iit ..+LD#WWELfffjjtt;.if.:           .DEGLLGEDLti,   . .    . . .        ,tLKDG ,;itt.+fK#WWW#DLffjjtt;:;j...        tDEGfLDEDGtK.  . LambdaHack           itLEG::;itt.+;K#WWWWW Lfffjjti:.t...      tDEGfLDEDL, .                           tDGj.;itt. + EWWWWKW  GLffjjti: t,      tDEGLGEEDj;   <lambdahack.github.io>      tLDLi,ittj+ EKWWWEWG  GLffjjti: tt   .tDEGGDEDGi,                                ;fEG :iitj+ LEWWWKKK   GLfffjti: tt  tDDLGDEDGf.  {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ;jGG :iitj+  DWWWKDWL   DLffjjti: jt.DDLGDEDLD    {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ,jDG .ittj+  LEWWWEDKj   DLffjjti: jj.LGDEDLE     {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ,jDG  ittj+   DKKWKDEKf   GLffjjti::ff.EEDLE      {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ,fGG  ittj+    GWKWEDEEt   GLffjjji :fL.ELE       {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ :tGL  ittf+    EEWKKDGDEjt..DLfftjji.,fG:K,       {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ,fGj,.tjjf+     EfKGKDLGDDDGDGLffiiti ttf:.       {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ .LG;i,;itt+    ..EDKEKEGjiLDDfGLLfijtii;fL:       {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ jLj ,;tjtL+   . . KLEEKKDGLLLGLGLfffjji,;LL:,.    {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{,tfL.fijffL+  .......jDKEEKKKKKEDGLffffji;;LL:...  {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{j fGii tjff+..........KtGDKEDEEDGLGLfffjti,;Lf:::: {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{iDf j:jffL.+..........::,E,tjjifL,,LLfffjji.;fL.,: {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{fiififffL .+ ......::,;tjLGGGGGLfji;LLfffjjt.,jft.                              ;t;i:jfff  .+ ..:::::,;;;,iiiiiiii;;;;LLfffjjt,,;LL:  ...                       ,iiijjfffL ..+..:::::,,;;;;;;;;;;;;;;;;;GLffffjt;j,jff,:::,                   ;ifLjjijifffL ..+.......::,,,,;;;;,,,,,,,,,:GLffffjjt:::tLiL                   LLLLGj;i,ffLLL ...+.    ..:::::,,,,,,,,,,, Version X.X.X (frontend: xxx, engine: LambdaHack X.X.X).+                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                +                                                                                
LambdaHack.cabal view
@@ -5,13 +5,13 @@ -- PVP summary:+-+------- breaking API changes --             | | +----- minor or non-breaking API additions --             | | | +--- code changes with no API change-version:       0.8.1.2+version:       0.8.3.0 synopsis:      A game engine library for tactical squad ASCII roguelike dungeon crawlers description:   LambdaHack is a Haskell game engine library for ASCII roguelike                games of arbitrary theme, size and complexity, with optional                tactical squad combat. It's packaged together with a sample                dungeon crawler in fantasy setting that can be tried out-               in the browser: <http://lambdahack.github.io>+               in the browser at <http://lambdahack.github.io>.                (It runs fastest on Chrome. Keyboard commands and savefiles                are supported only on recent enough versions of browsers.                Mouse should work everywhere.)@@ -93,7 +93,7 @@   manual:             True  flag jsaddle-  description:        switch to the JSaddle frontend+  description:        switch to the JSaddle frontend (may be bit-rotted)   default:            False   manual:             True 
Makefile view
@@ -82,7 +82,7 @@ 	dist/build/LambdaHack/LambdaHack --dbgMsgSer --logPriority 4 --newGame 3 --maxFps 100000 --frontendNull --benchmark --stopAfterFrames 7000 --automateAll --keepAutomated --gameMode battle --setDungeonRng 7 --setMainRng 7  benchFrontendBattle:-	dist/build/LambdaHack/LambdaHack --dbgMsgSer --logPriority 4 --newGame 3 --noAnim --maxFps 100000 --benchmark --stopAfterFrames 1500 --automateAll --keepAutomated --gameMode battle --setDungeonRng 7 --setMainRng 7+	dist/build/LambdaHack/LambdaHack --dbgMsgSer --logPriority 4 --newGame 3 --noAnim --maxFps 100000 --benchmark --stopAfterFrames 2000 --automateAll --keepAutomated --gameMode battle --setDungeonRng 7 --setMainRng 7  benchCrawl: 	dist/build/LambdaHack/LambdaHack --dbgMsgSer --logPriority 4 --newGame 1 --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfterFrames 7000 --automateAll --keepAutomated --gameMode crawl --setDungeonRng 0 --setMainRng 0@@ -217,11 +217,18 @@ 	cp COPYLEFT LambdaHackTheGame 	cp CREDITS LambdaHackTheGame -build-binary: build-binary-common+build-binary-ubuntu: build-binary-common 	cp LambdaHackTheGameInstall/bin/LambdaHack LambdaHackTheGame 	dist/build/LambdaHack/LambdaHack --version > /dev/null; \ 	LH_VERSION=$$(cat ~/.LambdaHack/stdout.txt); \ 	tar -czf LambdaHack_$${LH_VERSION}_ubuntu-16.04-amd64.tar.gz LambdaHackTheGame++build-binary-macosx: build-binary-common+	cp LambdaHackTheGameInstall/bin/LambdaHack LambdaHackTheGame+	dist/build/LambdaHack/LambdaHack --version > /dev/null; \+	LH_VERSION=$$(cat ~/.LambdaHack/stdout.txt); \+	OS_VERSION=$$(sw_vers -productVersion); \+	tar -czf LambdaHack_$${LH_VERSION}_macosx-$${OS_VERSION}-amd64.tar.gz LambdaHackTheGame  new-build-dev: 	cabal new-build --datadir=. --disable-optimization -j1
README.md view
@@ -9,7 +9,7 @@ games of arbitrary theme, size and complexity, with optional tactical squad combat. It's packaged together with a sample dungeon crawler in fantasy setting that can be tried out-in the browser: http://lambdahack.github.io+in the browser at http://lambdahack.github.io. (It runs fastest on Chrome. Keyboard commands and savefiles are supported only on recent enough versions of browsers. Mouse should work everywhere.)@@ -82,16 +82,19 @@ you may prefer to use a native binary for your architecture, if it exists.  Pre-compiled game binaries are available through-the release page[11] (and continuously from AppVeyor[18]).-Note that Windows binaries no longer work on Windows XP, since Cygwin-and MSYS2 dropped support for XP. To use a pre-compiled binary archive,-unpack it and run the executable in the unpacked directory-or use program shortcuts from the installer, if available.+the release page[11] (and, for Windows, continuously from AppVeyor[18]).+To use a pre-compiled binary archive, unpack it and run the executable+in the unpacked directory or use program shortcuts from the installer,+if available.  On Linux, make sure you have the SDL2 libraries installed on your system-(e.g., libsdl2-2.0-0, libsdl2-ttf-2.0-0 on Ubuntu; also libdw1).-For Windows, the SDL2 and all other needed libraries are already contained-in the game's binary archive.+(e.g., libsdl2-2.0-0, libsdl2-ttf-2.0-0 on Ubuntu).+On Mac OS X, you need SDL2 installed, e.g.,+from [libsdlorg](https://www.libsdl.org/download-2.0.php).+For Windows, the SDL2 and all other needed libraries are already+contained in the game's binary archive.+Note that Windows binaries no longer work on Windows XP, since Cygwin+and MSYS2 dropped support for XP.   Screen and keyboard configuration@@ -155,7 +158,7 @@     cabal update     cabal install LambdaHack -For a newer snapshot, download the source code from github[5]+For a newer snapshot, clone the source code from github[5] and run Cabal from the main directory      cabal install@@ -247,7 +250,7 @@ [8]: https://github.com/tuturto/space-privateers [9]: https://github.com/LambdaHack/LambdaHack/wiki/Sample-dungeon-crawler [10]: https://github.com/AllureOfTheStars/Allure-[11]: https://github.com/LambdaHack/LambdaHack/releases/latest+[11]: https://github.com/LambdaHack/LambdaHack/releases [15]: https://github.com/ghcjs/ghcjs [16]: https://www.npmjs.com/package/google-closure-compiler [18]: https://ci.appveyor.com/project/Mikolaj/lambdahack/build/artifacts