-- | Common code for displaying atomic update and SFX commands. module Game.LambdaHack.Client.UI.Watch.WatchCommonM ( fadeOutOrIn, markDisplayNeeded, lookAtMove, stopAtMove , aidVerbMU, aidVerbDuplicateMU, itemVerbMUGeneral, itemVerbMU , itemVerbMUShort, itemAidVerbMU, mitemAidVerbMU, itemAidDistinctMU , manyItemsAidVerbMU #ifdef EXPOSE_INTERNAL -- * Internal operations #endif ) where import Prelude () import Game.LambdaHack.Core.Prelude import qualified Data.EnumMap.Strict as EM import qualified Data.Text as T import qualified NLP.Miniutter.English as MU import Game.LambdaHack.Client.MonadClient import Game.LambdaHack.Client.State import Game.LambdaHack.Client.UI.Animation import Game.LambdaHack.Client.UI.Content.Screen import Game.LambdaHack.Client.UI.ContentClientUI import Game.LambdaHack.Client.UI.FrameM import Game.LambdaHack.Client.UI.HandleHelperM import Game.LambdaHack.Client.UI.ItemDescription import Game.LambdaHack.Client.UI.MonadClientUI import Game.LambdaHack.Client.UI.Msg import Game.LambdaHack.Client.UI.MsgM import Game.LambdaHack.Client.UI.SessionUI import Game.LambdaHack.Common.Actor import Game.LambdaHack.Common.ActorState import Game.LambdaHack.Common.Faction import Game.LambdaHack.Common.Item import qualified Game.LambdaHack.Common.ItemAspect as IA import Game.LambdaHack.Common.Misc import Game.LambdaHack.Common.MonadStateRead import Game.LambdaHack.Common.State import Game.LambdaHack.Common.Types import qualified Game.LambdaHack.Definition.Ability as Ability fadeOutOrIn :: MonadClientUI m => Bool -> m () fadeOutOrIn out = do arena <- getArenaUI CCUI{coscreen} <- getsSession sccui animMap <- rndToActionUI $ fadeout coscreen out 2 animFrs <- renderAnimFrames arena animMap (Just False) displayFrames arena (tail animFrs) -- no basic frame between fadeout and in markDisplayNeeded :: MonadClientUI m => LevelId -> m () markDisplayNeeded lid = do lidV <- viewedLevelUI when (lidV == lid) $ modifySession $ \sess -> sess {sdisplayNeeded = True} lookAtMove :: MonadClientUI m => ActorId -> m () lookAtMove aid = do mleader <- getsClient sleader body <- getsState $ getActorBody aid side <- getsClient sside aimMode <- getsSession saimMode when (not (bproj body) && bfid body == side && isNothing aimMode) $ do -- aiming does a more extensive look stashBlurb <- lookAtStash (bpos body) (blid body) (itemsBlurb, _) <- lookAtItems True (bpos body) (blid body) (Just aid) Nothing let msgClass = if Just aid == mleader then MsgAtFeetMajor else MsgAtFeetMinor blurb = stashBlurb <+> itemsBlurb unless (T.null blurb) $ msgAdd msgClass blurb stopAtMove :: MonadClientUI m => ActorId -> m () stopAtMove aid = do body <- getsState $ getActorBody aid side <- getsClient sside fact <- getsState $ (EM.! bfid body) . sfactionD adjBigAssocs <- getsState $ adjacentBigAssocs body adjProjAssocs <- getsState $ adjacentProjAssocs body if not (bproj body) && bfid body == side then do let foe (_, b2) = isFoe (bfid body) fact (bfid b2) adjFoes = filter foe $ adjBigAssocs ++ adjProjAssocs unless (null adjFoes) stopPlayBack else when (isFoe (bfid body) fact side) $ do let our (_, b2) = bfid b2 == side adjOur = filter our adjBigAssocs unless (null adjOur) stopPlayBack aidVerbMU :: (MonadClientUI m, MsgShared a) => a -> ActorId -> MU.Part -> m () aidVerbMU msgClass aid verb = do subject <- partActorLeader aid msgAdd msgClass $ makeSentence [MU.SubjectVerbSg subject verb] aidVerbDuplicateMU :: (MonadClientUI m, MsgShared a) => a -> ActorId -> MU.Part -> m Bool aidVerbDuplicateMU msgClass aid verb = do subject <- partActorLeader aid msgAddDuplicate msgClass (makeSentence [MU.SubjectVerbSg subject verb]) itemVerbMUGeneral :: MonadClientUI m => Bool -> ItemId -> ItemQuant -> MU.Part -> Container -> m Text itemVerbMUGeneral verbose iid kit@(k, _) verb c = assert (k > 0) $ do CCUI{coscreen=ScreenContent{rwidth}} <- getsSession sccui lid <- getsState $ lidFromC c localTime <- getsState $ getLocalTime lid itemFull <- getsState $ itemToFull iid side <- getsClient sside factionD <- getsState sfactionD let arItem = aspectRecordFull itemFull partItemWsChosen | verbose = partItemWs | otherwise = partItemWsShort subject = partItemWsChosen rwidth side factionD k localTime itemFull kit msg | k > 1 && not (IA.checkFlag Ability.Condition arItem) = makeSentence [MU.SubjectVerb MU.PlEtc MU.Yes subject verb] | otherwise = makeSentence [MU.SubjectVerbSg subject verb] return $! msg itemVerbMU :: (MonadClientUI m, MsgShared a) => a -> ItemId -> ItemQuant -> MU.Part -> Container -> m () itemVerbMU msgClass iid kit verb c = do msg <- itemVerbMUGeneral True iid kit verb c msgAdd msgClass msg itemVerbMUShort :: (MonadClientUI m, MsgShared a) => a -> ItemId -> ItemQuant -> MU.Part -> Container -> m () itemVerbMUShort msgClass iid kit verb c = do msg <- itemVerbMUGeneral False iid kit verb c msgAdd msgClass msg itemAidVerbMU :: (MonadClientUI m, MsgShared a) => a -> ActorId -> MU.Part -> ItemId -> Either Int Int -> m () itemAidVerbMU msgClass aid verb iid ek = do CCUI{coscreen=ScreenContent{rwidth}} <- getsSession sccui body <- getsState $ getActorBody aid side <- getsClient sside factionD <- getsState sfactionD let lid = blid body fakeKit = quantSingle localTime <- getsState $ getLocalTime lid subject <- partActorLeader aid -- The item may no longer be in @c@, but it was. itemFull <- getsState $ itemToFull iid let object = case ek of Left n -> partItemWs rwidth side factionD n localTime itemFull fakeKit Right n -> let (name1, powers) = partItemShort rwidth side factionD localTime itemFull fakeKit in MU.Phrase ["the", MU.Car1Ws n name1, powers] msg = makeSentence [MU.SubjectVerbSg subject verb, object] msgAdd msgClass msg mitemAidVerbMU :: (MonadClientUI m, MsgShared a) => a -> ActorId -> MU.Part -> ItemId -> Maybe MU.Part -> m () mitemAidVerbMU msgClass aid verb iid msuffix = do itemD <- getsState sitemD case msuffix of Just suffix | iid `EM.member` itemD -> itemAidVerbMU msgClass aid (MU.Phrase [verb, suffix]) iid (Right 1) _ -> do #ifdef WITH_EXPENSIVE_ASSERTIONS side <- getsClient sside b <- getsState $ getActorBody aid bUI <- getsSession $ getActorUI aid -- It's not actually expensive, but it's particularly likely -- to fail with wild content, indicating server game rules logic -- needs to be fixed/extended. -- Observer from another faction may receive the effect information -- from the server, because the affected actor is visible, -- but the position of the item may be out of FOV. This is fine; -- the message is then shorter, because only the effect was seen, -- while the cause remains misterious. assert (isNothing msuffix -- item description not requested || bfid b /= side -- not from affected faction; only observing `blame` "item never seen by the affected actor" `swith` (aid, b, bUI, verb, iid, msuffix)) $ #endif aidVerbMU msgClass aid verb itemAidDistinctMU :: MonadClientUI m => MsgClassDistinct -> ActorId -> MU.Part -> MU.Part -> ItemId -> m () itemAidDistinctMU msgClass aid verbShow verbSave iid = do CCUI{coscreen=ScreenContent{rwidth}} <- getsSession sccui body <- getsState $ getActorBody aid side <- getsClient sside factionD <- getsState sfactionD let lid = blid body fakeKit = quantSingle localTime <- getsState $ getLocalTime lid subject <- partActorLeader aid -- The item may no longer be in @c@, but it was. itemFull <- getsState $ itemToFull iid let object = let (name, powers) = partItem rwidth side factionD localTime itemFull fakeKit in MU.Phrase [name, powers] t1 = makeSentence [MU.SubjectVerbSg subject verbShow, object] t2 = makeSentence [MU.SubjectVerbSg subject verbSave, object] dotsIfShorter = if t1 == t2 then "" else ".." msgAddDistinct msgClass (t1 <> dotsIfShorter, t2) manyItemsAidVerbMU :: (MonadClientUI m, MsgShared a) => a -> ActorId -> MU.Part -> [(ItemId, ItemQuant)] -> (Int -> Either (Maybe Int) Int) -> m () manyItemsAidVerbMU msgClass aid verb sortedAssocs ekf = do CCUI{coscreen=ScreenContent{rwidth}} <- getsSession sccui body <- getsState $ getActorBody aid side <- getsClient sside factionD <- getsState sfactionD let lid = blid body fakeKit = quantSingle localTime <- getsState $ getLocalTime lid subject <- partActorLeader aid -- The item may no longer be in @c@, but it was. itemToF <- getsState $ flip itemToFull let object (iid, (k, _)) = let itemFull = itemToF iid in case ekf k of Left (Just n) -> partItemWs rwidth side factionD n localTime itemFull fakeKit Left Nothing -> let (name, powers) = partItem rwidth side factionD localTime itemFull fakeKit in MU.Phrase [name, powers] Right n -> let (name1, powers) = partItemShort rwidth side factionD localTime itemFull fakeKit in MU.Phrase ["the", MU.Car1Ws n name1, powers] msg = makeSentence [ MU.SubjectVerbSg subject verb , MU.WWandW $ map object sortedAssocs] msgAdd msgClass msg