{-# LANGUAGE OverloadedStrings #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- The main TUI update logic that is called from other controller parts.
module Swarm.TUI.Controller.UpdateUI (
  updateUI,
) where

import Brick hiding (Direction, Location)
import Brick.Focus

-- See Note [liftA2 re-export from Prelude]
import Brick.Widgets.List qualified as BL
import Control.Applicative (liftA2, pure)
import Control.Lens as Lens
import Control.Monad (unless, when)
import Data.Foldable (toList)
import Data.List.Extra (enumerate)
import Data.Maybe (isNothing)
import Data.String (fromString)
import Data.Text qualified as T
import Swarm.Game.Entity hiding (empty)
import Swarm.Game.Robot
import Swarm.Game.Robot.Concrete
import Swarm.Game.State
import Swarm.Game.State.Landscape
import Swarm.Game.State.Substate
import Swarm.Language.Pretty
import Swarm.Language.Typed (Typed (..))
import Swarm.Language.Types
import Swarm.Language.Value (Value (VExc, VUnit), envTydefs, prettyValue)
import Swarm.TUI.Controller.SaveScenario (saveScenarioInfoOnFinishNocheat)
import Swarm.TUI.Controller.Util
import Swarm.TUI.Model
import Swarm.TUI.Model.Goal
import Swarm.TUI.Model.Name
import Swarm.TUI.Model.Popup (Popup (..), addPopup)
import Swarm.TUI.Model.Repl
import Swarm.TUI.Model.UI
import Swarm.TUI.View.Objective qualified as GR
import Witch (into)
import Prelude hiding (Applicative (..))

-- | Update the UI.  This function is used after running the
--   game for some number of ticks.
updateUI :: EventM Name AppState Bool
updateUI :: EventM Name AppState Bool
updateUI = do
  EventM Name AppState ()
loadVisibleRegion

  -- If the game state indicates a redraw is needed, invalidate the
  -- world cache so it will be redrawn.
  GameState
g <- Getting GameState AppState GameState
-> EventM Name AppState GameState
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting GameState AppState GameState
Lens' AppState GameState
gameState
  Bool -> EventM Name AppState () -> EventM Name AppState ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (GameState
g GameState -> Getting Bool GameState Bool -> Bool
forall s a. s -> Getting a s a -> a
^. Getting Bool GameState Bool
Lens' GameState Bool
needsRedraw) (EventM Name AppState () -> EventM Name AppState ())
-> EventM Name AppState () -> EventM Name AppState ()
forall a b. (a -> b) -> a -> b
$ Name -> EventM Name AppState ()
forall n s. Ord n => n -> EventM n s ()
invalidateCacheEntry Name
WorldCache

  -- The hash of the robot whose inventory is currently displayed (if any)
  Maybe Int
listRobotHash <- ((Int, List Name InventoryListEntry) -> Int)
-> Maybe (Int, List Name InventoryListEntry) -> Maybe Int
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int, List Name InventoryListEntry) -> Int
forall a b. (a, b) -> a
fst (Maybe (Int, List Name InventoryListEntry) -> Maybe Int)
-> EventM Name AppState (Maybe (Int, List Name InventoryListEntry))
-> EventM Name AppState (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Getting
  (Maybe (Int, List Name InventoryListEntry))
  AppState
  (Maybe (Int, List Name InventoryListEntry))
-> EventM Name AppState (Maybe (Int, List Name InventoryListEntry))
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((UIState
 -> Const (Maybe (Int, List Name InventoryListEntry)) UIState)
-> AppState
-> Const (Maybe (Int, List Name InventoryListEntry)) AppState
Lens' AppState UIState
uiState ((UIState
  -> Const (Maybe (Int, List Name InventoryListEntry)) UIState)
 -> AppState
 -> Const (Maybe (Int, List Name InventoryListEntry)) AppState)
-> ((Maybe (Int, List Name InventoryListEntry)
     -> Const
          (Maybe (Int, List Name InventoryListEntry))
          (Maybe (Int, List Name InventoryListEntry)))
    -> UIState
    -> Const (Maybe (Int, List Name InventoryListEntry)) UIState)
-> Getting
     (Maybe (Int, List Name InventoryListEntry))
     AppState
     (Maybe (Int, List Name InventoryListEntry))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIGameplay
 -> Const (Maybe (Int, List Name InventoryListEntry)) UIGameplay)
-> UIState
-> Const (Maybe (Int, List Name InventoryListEntry)) UIState
Lens' UIState UIGameplay
uiGameplay ((UIGameplay
  -> Const (Maybe (Int, List Name InventoryListEntry)) UIGameplay)
 -> UIState
 -> Const (Maybe (Int, List Name InventoryListEntry)) UIState)
-> ((Maybe (Int, List Name InventoryListEntry)
     -> Const
          (Maybe (Int, List Name InventoryListEntry))
          (Maybe (Int, List Name InventoryListEntry)))
    -> UIGameplay
    -> Const (Maybe (Int, List Name InventoryListEntry)) UIGameplay)
-> (Maybe (Int, List Name InventoryListEntry)
    -> Const
         (Maybe (Int, List Name InventoryListEntry))
         (Maybe (Int, List Name InventoryListEntry)))
-> UIState
-> Const (Maybe (Int, List Name InventoryListEntry)) UIState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIInventory
 -> Const (Maybe (Int, List Name InventoryListEntry)) UIInventory)
-> UIGameplay
-> Const (Maybe (Int, List Name InventoryListEntry)) UIGameplay
Lens' UIGameplay UIInventory
uiInventory ((UIInventory
  -> Const (Maybe (Int, List Name InventoryListEntry)) UIInventory)
 -> UIGameplay
 -> Const (Maybe (Int, List Name InventoryListEntry)) UIGameplay)
-> ((Maybe (Int, List Name InventoryListEntry)
     -> Const
          (Maybe (Int, List Name InventoryListEntry))
          (Maybe (Int, List Name InventoryListEntry)))
    -> UIInventory
    -> Const (Maybe (Int, List Name InventoryListEntry)) UIInventory)
-> (Maybe (Int, List Name InventoryListEntry)
    -> Const
         (Maybe (Int, List Name InventoryListEntry))
         (Maybe (Int, List Name InventoryListEntry)))
-> UIGameplay
-> Const (Maybe (Int, List Name InventoryListEntry)) UIGameplay
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe (Int, List Name InventoryListEntry)
 -> Const
      (Maybe (Int, List Name InventoryListEntry))
      (Maybe (Int, List Name InventoryListEntry)))
-> UIInventory
-> Const (Maybe (Int, List Name InventoryListEntry)) UIInventory
Lens' UIInventory (Maybe (Int, List Name InventoryListEntry))
uiInventoryList)

  -- The hash of the focused robot (if any)
  Maybe Robot
fr <- Getting (Maybe Robot) AppState (Maybe Robot)
-> EventM Name AppState (Maybe Robot)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((GameState -> Const (Maybe Robot) GameState)
-> AppState -> Const (Maybe Robot) AppState
Lens' AppState GameState
gameState ((GameState -> Const (Maybe Robot) GameState)
 -> AppState -> Const (Maybe Robot) AppState)
-> ((Maybe Robot -> Const (Maybe Robot) (Maybe Robot))
    -> GameState -> Const (Maybe Robot) GameState)
-> Getting (Maybe Robot) AppState (Maybe Robot)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GameState -> Maybe Robot)
-> (Maybe Robot -> Const (Maybe Robot) (Maybe Robot))
-> GameState
-> Const (Maybe Robot) GameState
forall (p :: * -> * -> *) (f :: * -> *) s a.
(Profunctor p, Contravariant f) =>
(s -> a) -> Optic' p f s a
to GameState -> Maybe Robot
focusedRobot)
  let focusedRobotHash :: Maybe Int
focusedRobotHash = Getting Int Robot Int -> Robot -> Int
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Int Robot Int
Getter Robot Int
inventoryHash (Robot -> Int) -> Maybe Robot -> Maybe Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Robot
fr

  -- Check if the inventory list needs to be updated.
  Bool
shouldUpdate <- Getting Bool AppState Bool -> EventM Name AppState Bool
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((UIState -> Const Bool UIState) -> AppState -> Const Bool AppState
Lens' AppState UIState
uiState ((UIState -> Const Bool UIState)
 -> AppState -> Const Bool AppState)
-> ((Bool -> Const Bool Bool) -> UIState -> Const Bool UIState)
-> Getting Bool AppState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIGameplay -> Const Bool UIGameplay)
-> UIState -> Const Bool UIState
Lens' UIState UIGameplay
uiGameplay ((UIGameplay -> Const Bool UIGameplay)
 -> UIState -> Const Bool UIState)
-> ((Bool -> Const Bool Bool)
    -> UIGameplay -> Const Bool UIGameplay)
-> (Bool -> Const Bool Bool)
-> UIState
-> Const Bool UIState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIInventory -> Const Bool UIInventory)
-> UIGameplay -> Const Bool UIGameplay
Lens' UIGameplay UIInventory
uiInventory ((UIInventory -> Const Bool UIInventory)
 -> UIGameplay -> Const Bool UIGameplay)
-> ((Bool -> Const Bool Bool)
    -> UIInventory -> Const Bool UIInventory)
-> (Bool -> Const Bool Bool)
-> UIGameplay
-> Const Bool UIGameplay
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> Const Bool Bool) -> UIInventory -> Const Bool UIInventory
Lens' UIInventory Bool
uiInventoryShouldUpdate)

  -- Whether the focused robot is too far away to sense, & whether
  -- that has recently changed
  Maybe RobotRange
dist <- Getting (Maybe RobotRange) AppState (Maybe RobotRange)
-> EventM Name AppState (Maybe RobotRange)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((GameState -> Const (Maybe RobotRange) GameState)
-> AppState -> Const (Maybe RobotRange) AppState
Lens' AppState GameState
gameState ((GameState -> Const (Maybe RobotRange) GameState)
 -> AppState -> Const (Maybe RobotRange) AppState)
-> ((Maybe RobotRange
     -> Const (Maybe RobotRange) (Maybe RobotRange))
    -> GameState -> Const (Maybe RobotRange) GameState)
-> Getting (Maybe RobotRange) AppState (Maybe RobotRange)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GameState -> Maybe RobotRange)
-> (Maybe RobotRange
    -> Const (Maybe RobotRange) (Maybe RobotRange))
-> GameState
-> Const (Maybe RobotRange) GameState
forall (p :: * -> * -> *) (f :: * -> *) s a.
(Profunctor p, Contravariant f) =>
(s -> a) -> Optic' p f s a
to GameState -> Maybe RobotRange
focusedRange)
  Bool
farOK <- (Bool -> Bool -> Bool)
-> EventM Name AppState Bool
-> EventM Name AppState Bool
-> EventM Name AppState Bool
forall a b c.
(a -> b -> c)
-> EventM Name AppState a
-> EventM Name AppState b
-> EventM Name AppState c
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 Bool -> Bool -> Bool
(||) (Getting Bool AppState Bool -> EventM Name AppState Bool
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((GameState -> Const Bool GameState)
-> AppState -> Const Bool AppState
Lens' AppState GameState
gameState ((GameState -> Const Bool GameState)
 -> AppState -> Const Bool AppState)
-> Getting Bool GameState Bool -> Getting Bool AppState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting Bool GameState Bool
Lens' GameState Bool
creativeMode)) (Getting Bool AppState Bool -> EventM Name AppState Bool
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((GameState -> Const Bool GameState)
-> AppState -> Const Bool AppState
Lens' AppState GameState
gameState ((GameState -> Const Bool GameState)
 -> AppState -> Const Bool AppState)
-> Getting Bool GameState Bool -> Getting Bool AppState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Landscape -> Const Bool Landscape)
-> GameState -> Const Bool GameState
Lens' GameState Landscape
landscape ((Landscape -> Const Bool Landscape)
 -> GameState -> Const Bool GameState)
-> ((Bool -> Const Bool Bool) -> Landscape -> Const Bool Landscape)
-> Getting Bool GameState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> Const Bool Bool) -> Landscape -> Const Bool Landscape
Lens' Landscape Bool
worldScrollable))
  let tooFar :: Bool
tooFar = Bool -> Bool
not Bool
farOK Bool -> Bool -> Bool
&& Maybe RobotRange
dist Maybe RobotRange -> Maybe RobotRange -> Bool
forall a. Eq a => a -> a -> Bool
== RobotRange -> Maybe RobotRange
forall a. a -> Maybe a
Just RobotRange
Far
      farChanged :: Bool
farChanged = Bool
tooFar Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
/= Maybe Int -> Bool
forall a. Maybe a -> Bool
isNothing Maybe Int
listRobotHash

  -- If the robot moved in or out of range, or hashes don't match
  -- (either because which robot (or whether any robot) is focused
  -- changed, or the focused robot's inventory changed), or the
  -- inventory was flagged to be updated, regenerate the inventory list.
  Bool
inventoryUpdated <-
    if Bool
farChanged Bool -> Bool -> Bool
|| (Bool -> Bool
not Bool
farChanged Bool -> Bool -> Bool
&& Maybe Int
listRobotHash Maybe Int -> Maybe Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Maybe Int
focusedRobotHash) Bool -> Bool -> Bool
|| Bool
shouldUpdate
      then do
        LensLike'
  (Zoomed (EventM Name UIInventory) ()) AppState UIInventory
-> EventM Name UIInventory () -> EventM Name AppState ()
forall c.
LensLike' (Zoomed (EventM Name UIInventory) c) AppState UIInventory
-> EventM Name UIInventory c -> EventM Name AppState c
forall (m :: * -> *) (n :: * -> *) s t c.
Zoom m n s t =>
LensLike' (Zoomed m c) t s -> m c -> n c
Brick.zoom ((UIState -> Zoomed (EventM Name UIInventory) () UIState)
-> AppState -> Zoomed (EventM Name UIInventory) () AppState
Lens' AppState UIState
uiState ((UIState -> Zoomed (EventM Name UIInventory) () UIState)
 -> AppState -> Zoomed (EventM Name UIInventory) () AppState)
-> ((UIInventory
     -> Zoomed (EventM Name UIInventory) () UIInventory)
    -> UIState -> Zoomed (EventM Name UIInventory) () UIState)
-> LensLike'
     (Zoomed (EventM Name UIInventory) ()) AppState UIInventory
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIGameplay -> Zoomed (EventM Name UIInventory) () UIGameplay)
-> UIState -> Zoomed (EventM Name UIInventory) () UIState
Lens' UIState UIGameplay
uiGameplay ((UIGameplay -> Zoomed (EventM Name UIInventory) () UIGameplay)
 -> UIState -> Zoomed (EventM Name UIInventory) () UIState)
-> ((UIInventory
     -> Zoomed (EventM Name UIInventory) () UIInventory)
    -> UIGameplay -> Zoomed (EventM Name UIInventory) () UIGameplay)
-> (UIInventory -> Zoomed (EventM Name UIInventory) () UIInventory)
-> UIState
-> Zoomed (EventM Name UIInventory) () UIState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIInventory -> Zoomed (EventM Name UIInventory) () UIInventory)
-> UIGameplay -> Zoomed (EventM Name UIInventory) () UIGameplay
Lens' UIGameplay UIInventory
uiInventory) (EventM Name UIInventory () -> EventM Name AppState ())
-> EventM Name UIInventory () -> EventM Name AppState ()
forall a b. (a -> b) -> a -> b
$ do
          Maybe Robot -> EventM Name UIInventory ()
forall (m :: * -> *).
MonadState UIInventory m =>
Maybe Robot -> m ()
populateInventoryList (Maybe Robot -> EventM Name UIInventory ())
-> Maybe Robot -> EventM Name UIInventory ()
forall a b. (a -> b) -> a -> b
$ if Bool
tooFar then Maybe Robot
forall a. Maybe a
Nothing else Maybe Robot
fr
          (Bool -> Identity Bool) -> UIInventory -> Identity UIInventory
Lens' UIInventory Bool
uiInventoryShouldUpdate ((Bool -> Identity Bool) -> UIInventory -> Identity UIInventory)
-> Bool -> EventM Name UIInventory ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Bool
False
        Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True
      else Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False

  -- Now check if the base finished running a program entered at the REPL.
  Bool
replUpdated <- case GameState
g GameState -> Getting REPLStatus GameState REPLStatus -> REPLStatus
forall s a. s -> Getting a s a -> a
^. (GameControls -> Const REPLStatus GameControls)
-> GameState -> Const REPLStatus GameState
Lens' GameState GameControls
gameControls ((GameControls -> Const REPLStatus GameControls)
 -> GameState -> Const REPLStatus GameState)
-> ((REPLStatus -> Const REPLStatus REPLStatus)
    -> GameControls -> Const REPLStatus GameControls)
-> Getting REPLStatus GameState REPLStatus
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (REPLStatus -> Const REPLStatus REPLStatus)
-> GameControls -> Const REPLStatus GameControls
Lens' GameControls REPLStatus
replStatus of
    REPLWorking Polytype
pty (Just Value
v)
      -- It did, and the result was the unit value or an exception.  Just reset replStatus.
      | Value
v Value -> [Value] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Value
VUnit, Value
VExc] -> do
          (GameState -> Identity GameState) -> AppState -> Identity AppState
Lens' AppState GameState
gameState ((GameState -> Identity GameState)
 -> AppState -> Identity AppState)
-> ((REPLStatus -> Identity REPLStatus)
    -> GameState -> Identity GameState)
-> (REPLStatus -> Identity REPLStatus)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GameControls -> Identity GameControls)
-> GameState -> Identity GameState
Lens' GameState GameControls
gameControls ((GameControls -> Identity GameControls)
 -> GameState -> Identity GameState)
-> ((REPLStatus -> Identity REPLStatus)
    -> GameControls -> Identity GameControls)
-> (REPLStatus -> Identity REPLStatus)
-> GameState
-> Identity GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (REPLStatus -> Identity REPLStatus)
-> GameControls -> Identity GameControls
Lens' GameControls REPLStatus
replStatus ((REPLStatus -> Identity REPLStatus)
 -> AppState -> Identity AppState)
-> REPLStatus -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Maybe (Polytype, Value) -> REPLStatus
REPLDone ((Polytype, Value) -> Maybe (Polytype, Value)
forall a. a -> Maybe a
Just (Polytype
pty, Value
v))
          Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True

      -- It did, and returned some other value.  Create new 'it'
      -- variables, pretty-print the result as a REPL output, with its
      -- type, and reset the replStatus.
      | Bool
otherwise -> do
          Integer
itIx <- Getting Integer AppState Integer -> EventM Name AppState Integer
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((GameState -> Const Integer GameState)
-> AppState -> Const Integer AppState
Lens' AppState GameState
gameState ((GameState -> Const Integer GameState)
 -> AppState -> Const Integer AppState)
-> ((Integer -> Const Integer Integer)
    -> GameState -> Const Integer GameState)
-> Getting Integer AppState Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GameControls -> Const Integer GameControls)
-> GameState -> Const Integer GameState
Lens' GameState GameControls
gameControls ((GameControls -> Const Integer GameControls)
 -> GameState -> Const Integer GameState)
-> ((Integer -> Const Integer Integer)
    -> GameControls -> Const Integer GameControls)
-> (Integer -> Const Integer Integer)
-> GameState
-> Const Integer GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Integer -> Const Integer Integer)
-> GameControls -> Const Integer GameControls
Lens' GameControls Integer
replNextValueIndex)
          Env
env <- Getting Env AppState Env -> EventM Name AppState Env
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((GameState -> Const Env GameState)
-> AppState -> Const Env AppState
Lens' AppState GameState
gameState ((GameState -> Const Env GameState)
 -> AppState -> Const Env AppState)
-> ((Env -> Const Env Env) -> GameState -> Const Env GameState)
-> Getting Env AppState Env
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Env -> Const Env Env) -> GameState -> Const Env GameState
Traversal' GameState Env
baseEnv)
          let finalType :: Polytype
finalType = TDCtx -> Polytype -> Polytype
stripCmd (Env
env Env -> Getting TDCtx Env TDCtx -> TDCtx
forall s a. s -> Getting a s a -> a
^. Getting TDCtx Env TDCtx
Lens' Env TDCtx
envTydefs) Polytype
pty
              itName :: Var
itName = [Char] -> Var
forall a. IsString a => [Char] -> a
fromString ([Char] -> Var) -> [Char] -> Var
forall a b. (a -> b) -> a -> b
$ [Char]
"it" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Integer -> [Char]
forall a. Show a => a -> [Char]
show Integer
itIx
              out :: Var
out = Var -> [Var] -> Var
T.intercalate Var
" " [Var
itName, Var
":", Polytype -> Var
forall a. PrettyPrec a => a -> Var
prettyText Polytype
finalType, Var
"=", Var -> Var
forall target source. From source target => source -> target
into (Value -> Var
prettyValue Value
v)]
          REPLHistItem -> EventM Name AppState ()
forall (m :: * -> *). MonadState AppState m => REPLHistItem -> m ()
addREPLHistItem (Var -> REPLHistItem
mkREPLOutput Var
out)
          Name -> EventM Name AppState ()
forall n s. Ord n => n -> EventM n s ()
invalidateCacheEntry Name
REPLHistoryCache
          ViewportScroll Name -> forall s. EventM Name s ()
forall n. ViewportScroll n -> forall s. EventM n s ()
vScrollToEnd ViewportScroll Name
replScroll
          (GameState -> Identity GameState) -> AppState -> Identity AppState
Lens' AppState GameState
gameState ((GameState -> Identity GameState)
 -> AppState -> Identity AppState)
-> ((REPLStatus -> Identity REPLStatus)
    -> GameState -> Identity GameState)
-> (REPLStatus -> Identity REPLStatus)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GameControls -> Identity GameControls)
-> GameState -> Identity GameState
Lens' GameState GameControls
gameControls ((GameControls -> Identity GameControls)
 -> GameState -> Identity GameState)
-> ((REPLStatus -> Identity REPLStatus)
    -> GameControls -> Identity GameControls)
-> (REPLStatus -> Identity REPLStatus)
-> GameState
-> Identity GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (REPLStatus -> Identity REPLStatus)
-> GameControls -> Identity GameControls
Lens' GameControls REPLStatus
replStatus ((REPLStatus -> Identity REPLStatus)
 -> AppState -> Identity AppState)
-> REPLStatus -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Maybe (Polytype, Value) -> REPLStatus
REPLDone ((Polytype, Value) -> Maybe (Polytype, Value)
forall a. a -> Maybe a
Just (Polytype
finalType, Value
v))
          (GameState -> Identity GameState) -> AppState -> Identity AppState
Lens' AppState GameState
gameState ((GameState -> Identity GameState)
 -> AppState -> Identity AppState)
-> ((Maybe (Typed Value) -> Identity (Maybe (Typed Value)))
    -> GameState -> Identity GameState)
-> (Maybe (Typed Value) -> Identity (Maybe (Typed Value)))
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Env -> Identity Env) -> GameState -> Identity GameState
Traversal' GameState Env
baseEnv ((Env -> Identity Env) -> GameState -> Identity GameState)
-> ((Maybe (Typed Value) -> Identity (Maybe (Typed Value)))
    -> Env -> Identity Env)
-> (Maybe (Typed Value) -> Identity (Maybe (Typed Value)))
-> GameState
-> Identity GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index Env -> Lens' Env (Maybe (IxValue Env))
forall m. At m => Index m -> Lens' m (Maybe (IxValue m))
at Var
Index Env
itName ((Maybe (Typed Value) -> Identity (Maybe (Typed Value)))
 -> AppState -> Identity AppState)
-> Maybe (Typed Value) -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Typed Value -> Maybe (Typed Value)
forall a. a -> Maybe a
Just (Value -> Polytype -> Requirements -> Typed Value
forall v. v -> Polytype -> Requirements -> Typed v
Typed Value
v Polytype
finalType Requirements
forall a. Monoid a => a
mempty)
          (GameState -> Identity GameState) -> AppState -> Identity AppState
Lens' AppState GameState
gameState ((GameState -> Identity GameState)
 -> AppState -> Identity AppState)
-> ((Maybe (Typed Value) -> Identity (Maybe (Typed Value)))
    -> GameState -> Identity GameState)
-> (Maybe (Typed Value) -> Identity (Maybe (Typed Value)))
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Env -> Identity Env) -> GameState -> Identity GameState
Traversal' GameState Env
baseEnv ((Env -> Identity Env) -> GameState -> Identity GameState)
-> ((Maybe (Typed Value) -> Identity (Maybe (Typed Value)))
    -> Env -> Identity Env)
-> (Maybe (Typed Value) -> Identity (Maybe (Typed Value)))
-> GameState
-> Identity GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index Env -> Lens' Env (Maybe (IxValue Env))
forall m. At m => Index m -> Lens' m (Maybe (IxValue m))
at Var
Index Env
"it" ((Maybe (Typed Value) -> Identity (Maybe (Typed Value)))
 -> AppState -> Identity AppState)
-> Maybe (Typed Value) -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Typed Value -> Maybe (Typed Value)
forall a. a -> Maybe a
Just (Value -> Polytype -> Requirements -> Typed Value
forall v. v -> Polytype -> Requirements -> Typed v
Typed Value
v Polytype
finalType Requirements
forall a. Monoid a => a
mempty)
          (GameState -> Identity GameState) -> AppState -> Identity AppState
Lens' AppState GameState
gameState ((GameState -> Identity GameState)
 -> AppState -> Identity AppState)
-> ((Integer -> Identity Integer)
    -> GameState -> Identity GameState)
-> (Integer -> Identity Integer)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GameControls -> Identity GameControls)
-> GameState -> Identity GameState
Lens' GameState GameControls
gameControls ((GameControls -> Identity GameControls)
 -> GameState -> Identity GameState)
-> ((Integer -> Identity Integer)
    -> GameControls -> Identity GameControls)
-> (Integer -> Identity Integer)
-> GameState
-> Identity GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Integer -> Identity Integer)
-> GameControls -> Identity GameControls
Lens' GameControls Integer
replNextValueIndex ((Integer -> Identity Integer) -> AppState -> Identity AppState)
-> (Integer -> Integer) -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1)
          Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True

    -- Otherwise, do nothing.
    REPLStatus
_ -> Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False

  -- If the focused robot's log has been updated and the UI focus
  -- isn't currently on the inventory or info panels, attempt to
  -- automatically switch to the logger and scroll all the way down so
  -- the new message can be seen.
  (UIState -> Identity UIState) -> AppState -> Identity AppState
Lens' AppState UIState
uiState ((UIState -> Identity UIState) -> AppState -> Identity AppState)
-> ((Bool -> Identity Bool) -> UIState -> Identity UIState)
-> (Bool -> Identity Bool)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIGameplay -> Identity UIGameplay) -> UIState -> Identity UIState
Lens' UIState UIGameplay
uiGameplay ((UIGameplay -> Identity UIGameplay)
 -> UIState -> Identity UIState)
-> ((Bool -> Identity Bool) -> UIGameplay -> Identity UIGameplay)
-> (Bool -> Identity Bool)
-> UIState
-> Identity UIState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> Identity Bool) -> UIGameplay -> Identity UIGameplay
Lens' UIGameplay Bool
uiScrollToEnd ((Bool -> Identity Bool) -> AppState -> Identity AppState)
-> Bool -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Bool
False
  Bool
logUpdated <- do
    -- If the inventory or info panels are currently focused, it would
    -- be rude to update them right under the user's nose, so consider
    -- them "sticky".  They will be updated as soon as the player moves
    -- the focus away.
    FocusRing Name
fring <- Getting (FocusRing Name) AppState (FocusRing Name)
-> EventM Name AppState (FocusRing Name)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use (Getting (FocusRing Name) AppState (FocusRing Name)
 -> EventM Name AppState (FocusRing Name))
-> Getting (FocusRing Name) AppState (FocusRing Name)
-> EventM Name AppState (FocusRing Name)
forall a b. (a -> b) -> a -> b
$ (UIState -> Const (FocusRing Name) UIState)
-> AppState -> Const (FocusRing Name) AppState
Lens' AppState UIState
uiState ((UIState -> Const (FocusRing Name) UIState)
 -> AppState -> Const (FocusRing Name) AppState)
-> ((FocusRing Name -> Const (FocusRing Name) (FocusRing Name))
    -> UIState -> Const (FocusRing Name) UIState)
-> Getting (FocusRing Name) AppState (FocusRing Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIGameplay -> Const (FocusRing Name) UIGameplay)
-> UIState -> Const (FocusRing Name) UIState
Lens' UIState UIGameplay
uiGameplay ((UIGameplay -> Const (FocusRing Name) UIGameplay)
 -> UIState -> Const (FocusRing Name) UIState)
-> ((FocusRing Name -> Const (FocusRing Name) (FocusRing Name))
    -> UIGameplay -> Const (FocusRing Name) UIGameplay)
-> (FocusRing Name -> Const (FocusRing Name) (FocusRing Name))
-> UIState
-> Const (FocusRing Name) UIState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FocusRing Name -> Const (FocusRing Name) (FocusRing Name))
-> UIGameplay -> Const (FocusRing Name) UIGameplay
Lens' UIGameplay (FocusRing Name)
uiFocusRing
    let sticky :: Bool
sticky = FocusRing Name -> Maybe Name
forall n. FocusRing n -> Maybe n
focusGetCurrent FocusRing Name
fring Maybe Name -> [Maybe Name] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` (FocusablePanel -> Maybe Name) -> [FocusablePanel] -> [Maybe Name]
forall a b. (a -> b) -> [a] -> [b]
map (Name -> Maybe Name
forall a. a -> Maybe a
Just (Name -> Maybe Name)
-> (FocusablePanel -> Name) -> FocusablePanel -> Maybe Name
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FocusablePanel -> Name
FocusablePanel) [FocusablePanel
RobotPanel, FocusablePanel
InfoPanel]

    -- Check if the robot log was updated and we are allowed to change
    -- the inventory+info panels.
    case Bool -> (Robot -> Bool) -> Maybe Robot -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (Getting Bool Robot Bool -> Robot -> Bool
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Bool Robot Bool
Lens' Robot Bool
robotLogUpdated) Maybe Robot
fr Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
sticky of
      Bool
False -> Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False
      Bool
True -> do
        -- Reset the log updated flag
        StateC GameState (TimeIOC (LiftC IO)) () -> EventM Name AppState ()
forall (m :: * -> *) a.
(MonadState AppState m, MonadIO m) =>
StateC GameState (TimeIOC (LiftC IO)) a -> m a
zoomGameState (StateC GameState (TimeIOC (LiftC IO)) ()
 -> EventM Name AppState ())
-> StateC GameState (TimeIOC (LiftC IO)) ()
-> EventM Name AppState ()
forall a b. (a -> b) -> a -> b
$ StateC Robots Identity ()
-> StateC GameState (TimeIOC (LiftC IO)) ()
forall (sig :: (* -> *) -> * -> *) (m :: * -> *) b.
Has (State GameState) sig m =>
StateC Robots Identity b -> m b
zoomRobots StateC Robots Identity ()
forall (sig :: (* -> *) -> * -> *) (m :: * -> *).
Has (State Robots) sig m =>
m ()
clearFocusedRobotLogUpdated

        -- Find and focus an equipped "logger" device in the inventory list.
        let isLogger :: InventoryListEntry -> Bool
isLogger (EquippedEntry Entity
e) = Entity
e Entity -> Getting Var Entity Var -> Var
forall s a. s -> Getting a s a -> a
^. Getting Var Entity Var
Lens' Entity Var
entityName Var -> Var -> Bool
forall a. Eq a => a -> a -> Bool
== Var
"logger"
            isLogger InventoryListEntry
_ = Bool
False
            focusLogger :: GenericList n Vector InventoryListEntry
-> GenericList n Vector InventoryListEntry
focusLogger = (InventoryListEntry -> Bool)
-> GenericList n Vector InventoryListEntry
-> GenericList n Vector InventoryListEntry
forall (t :: * -> *) e n.
(Foldable t, Splittable t) =>
(e -> Bool) -> GenericList n t e -> GenericList n t e
BL.listFindBy InventoryListEntry -> Bool
isLogger

        (UIState -> Identity UIState) -> AppState -> Identity AppState
Lens' AppState UIState
uiState ((UIState -> Identity UIState) -> AppState -> Identity AppState)
-> ((List Name InventoryListEntry
     -> Identity (List Name InventoryListEntry))
    -> UIState -> Identity UIState)
-> (List Name InventoryListEntry
    -> Identity (List Name InventoryListEntry))
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIGameplay -> Identity UIGameplay) -> UIState -> Identity UIState
Lens' UIState UIGameplay
uiGameplay ((UIGameplay -> Identity UIGameplay)
 -> UIState -> Identity UIState)
-> ((List Name InventoryListEntry
     -> Identity (List Name InventoryListEntry))
    -> UIGameplay -> Identity UIGameplay)
-> (List Name InventoryListEntry
    -> Identity (List Name InventoryListEntry))
-> UIState
-> Identity UIState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIInventory -> Identity UIInventory)
-> UIGameplay -> Identity UIGameplay
Lens' UIGameplay UIInventory
uiInventory ((UIInventory -> Identity UIInventory)
 -> UIGameplay -> Identity UIGameplay)
-> ((List Name InventoryListEntry
     -> Identity (List Name InventoryListEntry))
    -> UIInventory -> Identity UIInventory)
-> (List Name InventoryListEntry
    -> Identity (List Name InventoryListEntry))
-> UIGameplay
-> Identity UIGameplay
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe (Int, List Name InventoryListEntry)
 -> Identity (Maybe (Int, List Name InventoryListEntry)))
-> UIInventory -> Identity UIInventory
Lens' UIInventory (Maybe (Int, List Name InventoryListEntry))
uiInventoryList ((Maybe (Int, List Name InventoryListEntry)
  -> Identity (Maybe (Int, List Name InventoryListEntry)))
 -> UIInventory -> Identity UIInventory)
-> ((List Name InventoryListEntry
     -> Identity (List Name InventoryListEntry))
    -> Maybe (Int, List Name InventoryListEntry)
    -> Identity (Maybe (Int, List Name InventoryListEntry)))
-> (List Name InventoryListEntry
    -> Identity (List Name InventoryListEntry))
-> UIInventory
-> Identity UIInventory
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Int, List Name InventoryListEntry)
 -> Identity (Int, List Name InventoryListEntry))
-> Maybe (Int, List Name InventoryListEntry)
-> Identity (Maybe (Int, List Name InventoryListEntry))
forall a b (p :: * -> * -> *) (f :: * -> *).
(Choice p, Applicative f) =>
p a (f b) -> p (Maybe a) (f (Maybe b))
_Just (((Int, List Name InventoryListEntry)
  -> Identity (Int, List Name InventoryListEntry))
 -> Maybe (Int, List Name InventoryListEntry)
 -> Identity (Maybe (Int, List Name InventoryListEntry)))
-> ((List Name InventoryListEntry
     -> Identity (List Name InventoryListEntry))
    -> (Int, List Name InventoryListEntry)
    -> Identity (Int, List Name InventoryListEntry))
-> (List Name InventoryListEntry
    -> Identity (List Name InventoryListEntry))
-> Maybe (Int, List Name InventoryListEntry)
-> Identity (Maybe (Int, List Name InventoryListEntry))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (List Name InventoryListEntry
 -> Identity (List Name InventoryListEntry))
-> (Int, List Name InventoryListEntry)
-> Identity (Int, List Name InventoryListEntry)
forall s t a b. Field2 s t a b => Lens s t a b
Lens
  (Int, List Name InventoryListEntry)
  (Int, List Name InventoryListEntry)
  (List Name InventoryListEntry)
  (List Name InventoryListEntry)
_2 ((List Name InventoryListEntry
  -> Identity (List Name InventoryListEntry))
 -> AppState -> Identity AppState)
-> (List Name InventoryListEntry -> List Name InventoryListEntry)
-> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= List Name InventoryListEntry -> List Name InventoryListEntry
forall {n}.
GenericList n Vector InventoryListEntry
-> GenericList n Vector InventoryListEntry
focusLogger

        -- Now inform the UI that it should scroll the info panel to
        -- the very end.
        (UIState -> Identity UIState) -> AppState -> Identity AppState
Lens' AppState UIState
uiState ((UIState -> Identity UIState) -> AppState -> Identity AppState)
-> ((Bool -> Identity Bool) -> UIState -> Identity UIState)
-> (Bool -> Identity Bool)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIGameplay -> Identity UIGameplay) -> UIState -> Identity UIState
Lens' UIState UIGameplay
uiGameplay ((UIGameplay -> Identity UIGameplay)
 -> UIState -> Identity UIState)
-> ((Bool -> Identity Bool) -> UIGameplay -> Identity UIGameplay)
-> (Bool -> Identity Bool)
-> UIState
-> Identity UIState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> Identity Bool) -> UIGameplay -> Identity UIGameplay
Lens' UIGameplay Bool
uiScrollToEnd ((Bool -> Identity Bool) -> AppState -> Identity AppState)
-> Bool -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Bool
True
        Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True

  Bool
goalOrWinUpdated <- EventM Name AppState Bool
doGoalUpdates

  Bool
newPopups <- EventM Name AppState Bool
generateNotificationPopups

  let redraw :: Bool
redraw =
        GameState
g GameState -> Getting Bool GameState Bool -> Bool
forall s a. s -> Getting a s a -> a
^. Getting Bool GameState Bool
Lens' GameState Bool
needsRedraw
          Bool -> Bool -> Bool
|| Bool
inventoryUpdated
          Bool -> Bool -> Bool
|| Bool
replUpdated
          Bool -> Bool -> Bool
|| Bool
logUpdated
          Bool -> Bool -> Bool
|| Bool
goalOrWinUpdated
          Bool -> Bool -> Bool
|| Bool
newPopups
  Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
redraw

-- | Either pops up the updated Goals modal
-- or pops up the Congratulations (Win) modal, or pops
-- up the Condolences (Lose) modal.
-- The Win modal will take precedence if the player
-- has met the necessary conditions to win the game.
--
-- If the player chooses to "Keep Playing" from the Win modal, the
-- updated Goals will then immediately appear.
-- This is desirable for:
-- * feedback as to the final goal the player accomplished,
-- * as a summary of all of the goals of the game
-- * shows the player more "optional" goals they can continue to pursue
doGoalUpdates :: EventM Name AppState Bool
doGoalUpdates :: EventM Name AppState Bool
doGoalUpdates = do
  GoalTracking
curGoal <- Getting GoalTracking AppState GoalTracking
-> EventM Name AppState GoalTracking
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((UIState -> Const GoalTracking UIState)
-> AppState -> Const GoalTracking AppState
Lens' AppState UIState
uiState ((UIState -> Const GoalTracking UIState)
 -> AppState -> Const GoalTracking AppState)
-> ((GoalTracking -> Const GoalTracking GoalTracking)
    -> UIState -> Const GoalTracking UIState)
-> Getting GoalTracking AppState GoalTracking
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIGameplay -> Const GoalTracking UIGameplay)
-> UIState -> Const GoalTracking UIState
Lens' UIState UIGameplay
uiGameplay ((UIGameplay -> Const GoalTracking UIGameplay)
 -> UIState -> Const GoalTracking UIState)
-> ((GoalTracking -> Const GoalTracking GoalTracking)
    -> UIGameplay -> Const GoalTracking UIGameplay)
-> (GoalTracking -> Const GoalTracking GoalTracking)
-> UIState
-> Const GoalTracking UIState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GoalDisplay -> Const GoalTracking GoalDisplay)
-> UIGameplay -> Const GoalTracking UIGameplay
Lens' UIGameplay GoalDisplay
uiGoal ((GoalDisplay -> Const GoalTracking GoalDisplay)
 -> UIGameplay -> Const GoalTracking UIGameplay)
-> ((GoalTracking -> Const GoalTracking GoalTracking)
    -> GoalDisplay -> Const GoalTracking GoalDisplay)
-> (GoalTracking -> Const GoalTracking GoalTracking)
-> UIGameplay
-> Const GoalTracking UIGameplay
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GoalTracking -> Const GoalTracking GoalTracking)
-> GoalDisplay -> Const GoalTracking GoalDisplay
Lens' GoalDisplay GoalTracking
goalsContent)
  Bool
isCheating <- Getting Bool AppState Bool -> EventM Name AppState Bool
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((UIState -> Const Bool UIState) -> AppState -> Const Bool AppState
Lens' AppState UIState
uiState ((UIState -> Const Bool UIState)
 -> AppState -> Const Bool AppState)
-> ((Bool -> Const Bool Bool) -> UIState -> Const Bool UIState)
-> Getting Bool AppState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> Const Bool Bool) -> UIState -> Const Bool UIState
Lens' UIState Bool
uiCheatMode)
  WinCondition
curWinCondition <- Getting WinCondition AppState WinCondition
-> EventM Name AppState WinCondition
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((GameState -> Const WinCondition GameState)
-> AppState -> Const WinCondition AppState
Lens' AppState GameState
gameState ((GameState -> Const WinCondition GameState)
 -> AppState -> Const WinCondition AppState)
-> ((WinCondition -> Const WinCondition WinCondition)
    -> GameState -> Const WinCondition GameState)
-> Getting WinCondition AppState WinCondition
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (WinCondition -> Const WinCondition WinCondition)
-> GameState -> Const WinCondition GameState
Lens' GameState WinCondition
winCondition)
  Seq Announcement
announcementsSeq <- Getting (Seq Announcement) AppState (Seq Announcement)
-> EventM Name AppState (Seq Announcement)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((GameState -> Const (Seq Announcement) GameState)
-> AppState -> Const (Seq Announcement) AppState
Lens' AppState GameState
gameState ((GameState -> Const (Seq Announcement) GameState)
 -> AppState -> Const (Seq Announcement) AppState)
-> ((Seq Announcement
     -> Const (Seq Announcement) (Seq Announcement))
    -> GameState -> Const (Seq Announcement) GameState)
-> Getting (Seq Announcement) AppState (Seq Announcement)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Messages -> Const (Seq Announcement) Messages)
-> GameState -> Const (Seq Announcement) GameState
Lens' GameState Messages
messageInfo ((Messages -> Const (Seq Announcement) Messages)
 -> GameState -> Const (Seq Announcement) GameState)
-> ((Seq Announcement
     -> Const (Seq Announcement) (Seq Announcement))
    -> Messages -> Const (Seq Announcement) Messages)
-> (Seq Announcement
    -> Const (Seq Announcement) (Seq Announcement))
-> GameState
-> Const (Seq Announcement) GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Seq Announcement -> Const (Seq Announcement) (Seq Announcement))
-> Messages -> Const (Seq Announcement) Messages
Lens' Messages (Seq Announcement)
announcementQueue)
  let announcementsList :: [Announcement]
announcementsList = Seq Announcement -> [Announcement]
forall a. Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq Announcement
announcementsSeq

  -- Decide whether we need to update the current goal text and pop
  -- up a modal dialog.
  case WinCondition
curWinCondition of
    WinCondition
NoWinCondition -> Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
    WinConditions (Unwinnable Bool
False) ObjectiveCompletion
x -> do
      -- This clears the "flag" that the Lose dialog needs to pop up
      (GameState -> Identity GameState) -> AppState -> Identity AppState
Lens' AppState GameState
gameState ((GameState -> Identity GameState)
 -> AppState -> Identity AppState)
-> ((WinCondition -> Identity WinCondition)
    -> GameState -> Identity GameState)
-> (WinCondition -> Identity WinCondition)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (WinCondition -> Identity WinCondition)
-> GameState -> Identity GameState
Lens' GameState WinCondition
winCondition ((WinCondition -> Identity WinCondition)
 -> AppState -> Identity AppState)
-> WinCondition -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= WinStatus -> ObjectiveCompletion -> WinCondition
WinConditions (Bool -> WinStatus
Unwinnable Bool
True) ObjectiveCompletion
x
      ModalType -> EventM Name AppState ()
openModal (ModalType -> EventM Name AppState ())
-> ModalType -> EventM Name AppState ()
forall a b. (a -> b) -> a -> b
$ ScenarioOutcome -> ModalType
ScenarioEndModal ScenarioOutcome
LoseModal
      EventM Name AppState ()
forall (m :: * -> *). (MonadIO m, MonadState AppState m) => m ()
saveScenarioInfoOnFinishNocheat
      Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
    WinConditions (Won Bool
False TickNumber
ts) ObjectiveCompletion
x -> do
      -- This clears the "flag" that the Win dialog needs to pop up
      (GameState -> Identity GameState) -> AppState -> Identity AppState
Lens' AppState GameState
gameState ((GameState -> Identity GameState)
 -> AppState -> Identity AppState)
-> ((WinCondition -> Identity WinCondition)
    -> GameState -> Identity GameState)
-> (WinCondition -> Identity WinCondition)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (WinCondition -> Identity WinCondition)
-> GameState -> Identity GameState
Lens' GameState WinCondition
winCondition ((WinCondition -> Identity WinCondition)
 -> AppState -> Identity AppState)
-> WinCondition -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= WinStatus -> ObjectiveCompletion -> WinCondition
WinConditions (Bool -> TickNumber -> WinStatus
Won Bool
True TickNumber
ts) ObjectiveCompletion
x
      ModalType -> EventM Name AppState ()
openModal (ModalType -> EventM Name AppState ())
-> ModalType -> EventM Name AppState ()
forall a b. (a -> b) -> a -> b
$ ScenarioOutcome -> ModalType
ScenarioEndModal ScenarioOutcome
WinModal
      EventM Name AppState ()
forall (m :: * -> *). (MonadIO m, MonadState AppState m) => m ()
saveScenarioInfoOnFinishNocheat
      -- We do NOT advance the New Game menu to the next item here (we
      -- used to!), because we do not know if the user is going to
      -- select 'keep playing' or 'next challenge'.  We maintain the
      -- invariant that the current menu item is always the same as
      -- the scenario currently being played.  If the user either (1)
      -- quits to the menu or (2) selects 'next challenge' we will
      -- advance the menu at that point.
      Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
    WinConditions WinStatus
_ ObjectiveCompletion
oc -> do
      let newGoalTracking :: GoalTracking
newGoalTracking = [Announcement] -> CategorizedGoals -> GoalTracking
GoalTracking [Announcement]
announcementsList (CategorizedGoals -> GoalTracking)
-> CategorizedGoals -> GoalTracking
forall a b. (a -> b) -> a -> b
$ Bool -> ObjectiveCompletion -> CategorizedGoals
constructGoalMap Bool
isCheating ObjectiveCompletion
oc
          -- The "uiGoal" field is initialized with empty members, so we know that
          -- this will be the first time showing it if it will be nonempty after previously
          -- being empty.
          isFirstGoalDisplay :: Bool
isFirstGoalDisplay = GoalTracking -> Bool
hasAnythingToShow GoalTracking
newGoalTracking Bool -> Bool -> Bool
&& Bool -> Bool
not (GoalTracking -> Bool
hasAnythingToShow GoalTracking
curGoal)
          goalWasUpdated :: Bool
goalWasUpdated = Bool
isFirstGoalDisplay Bool -> Bool -> Bool
|| Bool -> Bool
not ([Announcement] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Announcement]
announcementsList)

      -- Decide whether to show a pop-up modal congratulating the user on
      -- successfully completing the current challenge.
      Bool -> EventM Name AppState () -> EventM Name AppState ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
goalWasUpdated (EventM Name AppState () -> EventM Name AppState ())
-> EventM Name AppState () -> EventM Name AppState ()
forall a b. (a -> b) -> a -> b
$ do
        let hasMultiple :: Bool
hasMultiple = GoalTracking -> Bool
hasMultipleGoals GoalTracking
newGoalTracking
            defaultFocus :: GoalWidget
defaultFocus =
              if Bool
hasMultiple
                then GoalWidget
ObjectivesList
                else GoalWidget
GoalSummary

            ring :: FocusRing Name
ring =
              [Name] -> FocusRing Name
forall n. [n] -> FocusRing n
focusRing ([Name] -> FocusRing Name) -> [Name] -> FocusRing Name
forall a b. (a -> b) -> a -> b
$
                (GoalWidget -> Name) -> [GoalWidget] -> [Name]
forall a b. (a -> b) -> [a] -> [b]
map GoalWidget -> Name
GoalWidgets ([GoalWidget] -> [Name]) -> [GoalWidget] -> [Name]
forall a b. (a -> b) -> a -> b
$
                  if Bool
hasMultiple
                    then [GoalWidget]
forall a. (Enum a, Bounded a) => [a]
enumerate
                    else [GoalWidget
GoalSummary]

        -- The "uiGoal" field is necessary at least to "persist" the data that is needed
        -- if the player chooses to later "recall" the goals dialog with CTRL+g.
        (UIState -> Identity UIState) -> AppState -> Identity AppState
Lens' AppState UIState
uiState
          ((UIState -> Identity UIState) -> AppState -> Identity AppState)
-> ((GoalDisplay -> Identity GoalDisplay)
    -> UIState -> Identity UIState)
-> (GoalDisplay -> Identity GoalDisplay)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIGameplay -> Identity UIGameplay) -> UIState -> Identity UIState
Lens' UIState UIGameplay
uiGameplay
          ((UIGameplay -> Identity UIGameplay)
 -> UIState -> Identity UIState)
-> ((GoalDisplay -> Identity GoalDisplay)
    -> UIGameplay -> Identity UIGameplay)
-> (GoalDisplay -> Identity GoalDisplay)
-> UIState
-> Identity UIState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GoalDisplay -> Identity GoalDisplay)
-> UIGameplay -> Identity UIGameplay
Lens' UIGameplay GoalDisplay
uiGoal
          ((GoalDisplay -> Identity GoalDisplay)
 -> AppState -> Identity AppState)
-> GoalDisplay -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= GoalTracking
-> List Name GoalEntry -> FocusRing Name -> GoalDisplay
GoalDisplay
            GoalTracking
newGoalTracking
            (GoalTracking -> List Name GoalEntry
GR.makeListWidget GoalTracking
newGoalTracking)
            (Name -> FocusRing Name -> FocusRing Name
forall n. Eq n => n -> FocusRing n -> FocusRing n
focusSetCurrent (GoalWidget -> Name
GoalWidgets GoalWidget
defaultFocus) FocusRing Name
ring)

        -- This clears the "flag" that indicate that the goals dialog needs to be
        -- automatically popped up.
        (GameState -> Identity GameState) -> AppState -> Identity AppState
Lens' AppState GameState
gameState ((GameState -> Identity GameState)
 -> AppState -> Identity AppState)
-> ((Seq Announcement -> Identity (Seq Announcement))
    -> GameState -> Identity GameState)
-> (Seq Announcement -> Identity (Seq Announcement))
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Messages -> Identity Messages) -> GameState -> Identity GameState
Lens' GameState Messages
messageInfo ((Messages -> Identity Messages)
 -> GameState -> Identity GameState)
-> ((Seq Announcement -> Identity (Seq Announcement))
    -> Messages -> Identity Messages)
-> (Seq Announcement -> Identity (Seq Announcement))
-> GameState
-> Identity GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Seq Announcement -> Identity (Seq Announcement))
-> Messages -> Identity Messages
Lens' Messages (Seq Announcement)
announcementQueue ((Seq Announcement -> Identity (Seq Announcement))
 -> AppState -> Identity AppState)
-> Seq Announcement -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Seq Announcement
forall a. Monoid a => a
mempty

        Bool
hideGoals <- Getting Bool AppState Bool -> EventM Name AppState Bool
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use (Getting Bool AppState Bool -> EventM Name AppState Bool)
-> Getting Bool AppState Bool -> EventM Name AppState Bool
forall a b. (a -> b) -> a -> b
$ (UIState -> Const Bool UIState) -> AppState -> Const Bool AppState
Lens' AppState UIState
uiState ((UIState -> Const Bool UIState)
 -> AppState -> Const Bool AppState)
-> ((Bool -> Const Bool Bool) -> UIState -> Const Bool UIState)
-> Getting Bool AppState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (UIGameplay -> Const Bool UIGameplay)
-> UIState -> Const Bool UIState
Lens' UIState UIGameplay
uiGameplay ((UIGameplay -> Const Bool UIGameplay)
 -> UIState -> Const Bool UIState)
-> ((Bool -> Const Bool Bool)
    -> UIGameplay -> Const Bool UIGameplay)
-> (Bool -> Const Bool Bool)
-> UIState
-> Const Bool UIState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> Const Bool Bool) -> UIGameplay -> Const Bool UIGameplay
Lens' UIGameplay Bool
uiHideGoals
        Bool -> EventM Name AppState () -> EventM Name AppState ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
hideGoals (EventM Name AppState () -> EventM Name AppState ())
-> EventM Name AppState () -> EventM Name AppState ()
forall a b. (a -> b) -> a -> b
$
          ModalType -> EventM Name AppState ()
openModal ModalType
GoalModal

      Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
goalWasUpdated

-- | Pops up notifications when new recipes or commands are unlocked.
generateNotificationPopups :: EventM Name AppState Bool
generateNotificationPopups :: EventM Name AppState Bool
generateNotificationPopups = do
  Notifications (Recipe Entity)
rs <- Getting
  (Notifications (Recipe Entity))
  AppState
  (Notifications (Recipe Entity))
-> EventM Name AppState (Notifications (Recipe Entity))
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use (Getting
   (Notifications (Recipe Entity))
   AppState
   (Notifications (Recipe Entity))
 -> EventM Name AppState (Notifications (Recipe Entity)))
-> Getting
     (Notifications (Recipe Entity))
     AppState
     (Notifications (Recipe Entity))
-> EventM Name AppState (Notifications (Recipe Entity))
forall a b. (a -> b) -> a -> b
$ (GameState -> Const (Notifications (Recipe Entity)) GameState)
-> AppState -> Const (Notifications (Recipe Entity)) AppState
Lens' AppState GameState
gameState ((GameState -> Const (Notifications (Recipe Entity)) GameState)
 -> AppState -> Const (Notifications (Recipe Entity)) AppState)
-> ((Notifications (Recipe Entity)
     -> Const
          (Notifications (Recipe Entity)) (Notifications (Recipe Entity)))
    -> GameState -> Const (Notifications (Recipe Entity)) GameState)
-> Getting
     (Notifications (Recipe Entity))
     AppState
     (Notifications (Recipe Entity))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Discovery -> Const (Notifications (Recipe Entity)) Discovery)
-> GameState -> Const (Notifications (Recipe Entity)) GameState
Lens' GameState Discovery
discovery ((Discovery -> Const (Notifications (Recipe Entity)) Discovery)
 -> GameState -> Const (Notifications (Recipe Entity)) GameState)
-> ((Notifications (Recipe Entity)
     -> Const
          (Notifications (Recipe Entity)) (Notifications (Recipe Entity)))
    -> Discovery -> Const (Notifications (Recipe Entity)) Discovery)
-> (Notifications (Recipe Entity)
    -> Const
         (Notifications (Recipe Entity)) (Notifications (Recipe Entity)))
-> GameState
-> Const (Notifications (Recipe Entity)) GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Notifications (Recipe Entity)
 -> Const
      (Notifications (Recipe Entity)) (Notifications (Recipe Entity)))
-> Discovery -> Const (Notifications (Recipe Entity)) Discovery
Lens' Discovery (Notifications (Recipe Entity))
availableRecipes
  let newRecipes :: Bool
newRecipes = Notifications (Recipe Entity)
rs Notifications (Recipe Entity)
-> Getting Bool (Notifications (Recipe Entity)) Bool -> Bool
forall s a. s -> Getting a s a -> a
^. Getting Bool (Notifications (Recipe Entity)) Bool
forall a (f :: * -> *).
Functor f =>
(Bool -> f Bool) -> Notifications a -> f (Notifications a)
notificationsShouldAlert
  Bool -> EventM Name AppState () -> EventM Name AppState ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
newRecipes (EventM Name AppState () -> EventM Name AppState ())
-> EventM Name AppState () -> EventM Name AppState ()
forall a b. (a -> b) -> a -> b
$ do
    (UIState -> Identity UIState) -> AppState -> Identity AppState
Lens' AppState UIState
uiState ((UIState -> Identity UIState) -> AppState -> Identity AppState)
-> ((PopupState -> Identity PopupState)
    -> UIState -> Identity UIState)
-> (PopupState -> Identity PopupState)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PopupState -> Identity PopupState) -> UIState -> Identity UIState
Lens' UIState PopupState
uiPopups ((PopupState -> Identity PopupState)
 -> AppState -> Identity AppState)
-> (PopupState -> PopupState) -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Popup -> PopupState -> PopupState
addPopup Popup
RecipesPopup
    (GameState -> Identity GameState) -> AppState -> Identity AppState
Lens' AppState GameState
gameState ((GameState -> Identity GameState)
 -> AppState -> Identity AppState)
-> ((Bool -> Identity Bool) -> GameState -> Identity GameState)
-> (Bool -> Identity Bool)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Discovery -> Identity Discovery)
-> GameState -> Identity GameState
Lens' GameState Discovery
discovery ((Discovery -> Identity Discovery)
 -> GameState -> Identity GameState)
-> ((Bool -> Identity Bool) -> Discovery -> Identity Discovery)
-> (Bool -> Identity Bool)
-> GameState
-> Identity GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Notifications (Recipe Entity)
 -> Identity (Notifications (Recipe Entity)))
-> Discovery -> Identity Discovery
Lens' Discovery (Notifications (Recipe Entity))
availableRecipes ((Notifications (Recipe Entity)
  -> Identity (Notifications (Recipe Entity)))
 -> Discovery -> Identity Discovery)
-> ((Bool -> Identity Bool)
    -> Notifications (Recipe Entity)
    -> Identity (Notifications (Recipe Entity)))
-> (Bool -> Identity Bool)
-> Discovery
-> Identity Discovery
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> Identity Bool)
-> Notifications (Recipe Entity)
-> Identity (Notifications (Recipe Entity))
forall a (f :: * -> *).
Functor f =>
(Bool -> f Bool) -> Notifications a -> f (Notifications a)
notificationsShouldAlert ((Bool -> Identity Bool) -> AppState -> Identity AppState)
-> Bool -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Bool
False

  Notifications Const
cs <- Getting (Notifications Const) AppState (Notifications Const)
-> EventM Name AppState (Notifications Const)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use (Getting (Notifications Const) AppState (Notifications Const)
 -> EventM Name AppState (Notifications Const))
-> Getting (Notifications Const) AppState (Notifications Const)
-> EventM Name AppState (Notifications Const)
forall a b. (a -> b) -> a -> b
$ (GameState -> Const (Notifications Const) GameState)
-> AppState -> Const (Notifications Const) AppState
Lens' AppState GameState
gameState ((GameState -> Const (Notifications Const) GameState)
 -> AppState -> Const (Notifications Const) AppState)
-> ((Notifications Const
     -> Const (Notifications Const) (Notifications Const))
    -> GameState -> Const (Notifications Const) GameState)
-> Getting (Notifications Const) AppState (Notifications Const)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Discovery -> Const (Notifications Const) Discovery)
-> GameState -> Const (Notifications Const) GameState
Lens' GameState Discovery
discovery ((Discovery -> Const (Notifications Const) Discovery)
 -> GameState -> Const (Notifications Const) GameState)
-> ((Notifications Const
     -> Const (Notifications Const) (Notifications Const))
    -> Discovery -> Const (Notifications Const) Discovery)
-> (Notifications Const
    -> Const (Notifications Const) (Notifications Const))
-> GameState
-> Const (Notifications Const) GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Notifications Const
 -> Const (Notifications Const) (Notifications Const))
-> Discovery -> Const (Notifications Const) Discovery
Lens' Discovery (Notifications Const)
availableCommands
  let alertCommands :: Bool
alertCommands = Notifications Const
cs Notifications Const
-> Getting Bool (Notifications Const) Bool -> Bool
forall s a. s -> Getting a s a -> a
^. Getting Bool (Notifications Const) Bool
forall a (f :: * -> *).
Functor f =>
(Bool -> f Bool) -> Notifications a -> f (Notifications a)
notificationsShouldAlert
  Bool -> EventM Name AppState () -> EventM Name AppState ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
alertCommands (EventM Name AppState () -> EventM Name AppState ())
-> EventM Name AppState () -> EventM Name AppState ()
forall a b. (a -> b) -> a -> b
$ do
    let newCommands :: [Const]
newCommands = Int -> [Const] -> [Const]
forall a. Int -> [a] -> [a]
take (Notifications Const
cs Notifications Const -> Getting Int (Notifications Const) Int -> Int
forall s a. s -> Getting a s a -> a
^. Getting Int (Notifications Const) Int
forall a (f :: * -> *).
Functor f =>
(Int -> f Int) -> Notifications a -> f (Notifications a)
notificationsCount) (Notifications Const
cs Notifications Const
-> Getting [Const] (Notifications Const) [Const] -> [Const]
forall s a. s -> Getting a s a -> a
^. Getting [Const] (Notifications Const) [Const]
forall a1 a2 (f :: * -> *).
Functor f =>
([a1] -> f [a2]) -> Notifications a1 -> f (Notifications a2)
notificationsContent)
    (UIState -> Identity UIState) -> AppState -> Identity AppState
Lens' AppState UIState
uiState ((UIState -> Identity UIState) -> AppState -> Identity AppState)
-> ((PopupState -> Identity PopupState)
    -> UIState -> Identity UIState)
-> (PopupState -> Identity PopupState)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PopupState -> Identity PopupState) -> UIState -> Identity UIState
Lens' UIState PopupState
uiPopups ((PopupState -> Identity PopupState)
 -> AppState -> Identity AppState)
-> (PopupState -> PopupState) -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Popup -> PopupState -> PopupState
addPopup ([Const] -> Popup
CommandsPopup [Const]
newCommands)
    (GameState -> Identity GameState) -> AppState -> Identity AppState
Lens' AppState GameState
gameState ((GameState -> Identity GameState)
 -> AppState -> Identity AppState)
-> ((Bool -> Identity Bool) -> GameState -> Identity GameState)
-> (Bool -> Identity Bool)
-> AppState
-> Identity AppState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Discovery -> Identity Discovery)
-> GameState -> Identity GameState
Lens' GameState Discovery
discovery ((Discovery -> Identity Discovery)
 -> GameState -> Identity GameState)
-> ((Bool -> Identity Bool) -> Discovery -> Identity Discovery)
-> (Bool -> Identity Bool)
-> GameState
-> Identity GameState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Notifications Const -> Identity (Notifications Const))
-> Discovery -> Identity Discovery
Lens' Discovery (Notifications Const)
availableCommands ((Notifications Const -> Identity (Notifications Const))
 -> Discovery -> Identity Discovery)
-> ((Bool -> Identity Bool)
    -> Notifications Const -> Identity (Notifications Const))
-> (Bool -> Identity Bool)
-> Discovery
-> Identity Discovery
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> Identity Bool)
-> Notifications Const -> Identity (Notifications Const)
forall a (f :: * -> *).
Functor f =>
(Bool -> f Bool) -> Notifications a -> f (Notifications a)
notificationsShouldAlert ((Bool -> Identity Bool) -> AppState -> Identity AppState)
-> Bool -> EventM Name AppState ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Bool
False

  Bool -> EventM Name AppState Bool
forall a. a -> EventM Name AppState a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> EventM Name AppState Bool)
-> Bool -> EventM Name AppState Bool
forall a b. (a -> b) -> a -> b
$ Bool
newRecipes Bool -> Bool -> Bool
|| Bool
alertCommands

-- | Strips the top-level @Cmd@ from a type, if any (to compute the
--   result type of a REPL command evaluation).
stripCmd :: TDCtx -> Polytype -> Polytype
stripCmd :: TDCtx -> Polytype -> Polytype
stripCmd TDCtx
tdCtx (Forall [Var]
xs Type
ty) = case TDCtx -> Type -> Type
whnfType TDCtx
tdCtx Type
ty of
  TyCmd Type
resTy -> [Var] -> Type -> Polytype
forall t. [Var] -> t -> Poly t
Forall [Var]
xs Type
resTy
  Type
_ -> [Var] -> Type -> Polytype
forall t. [Var] -> t -> Poly t
Forall [Var]
xs Type
ty