{-# LANGUAGE FlexibleContexts #-} -- | The main loop of the client, processing human and computer player -- moves turn by turn. module Game.LambdaHack.Client.LoopAction (loopAI, loopUI) where import Control.Monad import qualified Data.Text as T import Game.LambdaHack.Client.Action import Game.LambdaHack.Client.State import Game.LambdaHack.Common.Action import Game.LambdaHack.Common.Animation import Game.LambdaHack.Common.AtomicCmd import Game.LambdaHack.Common.ClientCmd import qualified Game.LambdaHack.Common.Kind as Kind import Game.LambdaHack.Common.Msg import Game.LambdaHack.Common.State import Game.LambdaHack.Content.RuleKind import Control.Exception.Assert.Sugar initCli :: MonadClient m => DebugModeCli -> (State -> m ()) -> m Bool initCli sdebugCli putSt = do -- Warning: state and client state are invalid here, e.g., sdungeon -- and sper are empty. cops <- getsState scops modifyClient $ \cli -> cli {sdebugCli} restored <- restoreGame case restored of Just (s, cli) | not $ snewGameCli sdebugCli -> do -- Restore the game. let sCops = updateCOps (const cops) s putSt sCops putClient cli {sdebugCli} return True _ -> -- First visit ever, use the initial state. return False loopAI :: (MonadClientReadServer CmdClientAI m) => DebugModeCli -> (CmdClientAI -> m ()) -> m () loopAI sdebugCli cmdClientAISem = do side <- getsClient sside restored <- initCli sdebugCli $ \s -> cmdClientAISem $ CmdAtomicAI $ ResumeServerA s cmd1 <- readServer case (restored, cmd1) of (True, CmdAtomicAI ResumeA{}) -> return () (True, CmdAtomicAI RestartA{}) -> return () -- ignoring old savefile (False, CmdAtomicAI ResumeA{}) -> do removeServerSave error $ T.unpack $ "Savefile of client" <+> showT side <+> "not usable. Removing server savefile. Please restart now." (False, CmdAtomicAI RestartA{}) -> return () _ -> assert `failure` "unexpected command" `twith` (side, restored, cmd1) cmdClientAISem cmd1 -- State and client state now valid. debugPrint $ "AI client" <+> showT side <+> "started." loop debugPrint $ "AI client" <+> showT side <+> "stopped." where loop = do cmd <- readServer cmdClientAISem cmd quit <- getsClient squit unless quit loop loopUI :: (MonadClientUI m, MonadClientReadServer CmdClientUI m) => DebugModeCli -> (CmdClientUI -> m ()) -> m () loopUI sdebugCli cmdClientUISem = do Kind.COps{corule} <- getsState scops let title = rtitle $ Kind.stdRuleset corule side <- getsClient sside restored <- initCli sdebugCli $ \s -> cmdClientUISem $ CmdAtomicUI $ ResumeServerA s cmd1 <- readServer case (restored, cmd1) of (True, CmdAtomicUI ResumeA{}) -> do let msg = "Welcome back to" <+> title <> "." cmdClientUISem cmd1 msgAdd msg (True, CmdAtomicUI RestartA{}) -> do let msg = "Starting a new" <+> title <+> "game." -- ignore old savefile cmdClientUISem cmd1 msgAdd msg (False, CmdAtomicUI ResumeA{}) -> do removeServerSave error $ T.unpack $ "Savefile of client" <+> showT side <+> "not usable. Removing server savefile. Please restart now." (False, CmdAtomicUI RestartA{}) -> do let msg = "Welcome to" <+> title <> "!" cmdClientUISem cmd1 msgAdd msg _ -> assert `failure` "unexpected command" `twith` (side, restored, cmd1) -- State and client state now valid. debugPrint $ "UI client" <+> showT side <+> "started." loop debugPrint $ "UI client" <+> showT side <+> "stopped." where loop = do cmd <- readServer cmdClientUISem cmd quit <- getsClient squit unless quit loop