{-# LANGUAGE TupleSections #-}
module Game.LambdaHack.Client.UI.Watch.WatchQuitM
( quitFactionUI
#ifdef EXPOSE_INTERNAL
, displayGameOverLoot, displayGameOverAnalytics, displayGameOverLore
, viewFinalLore
#endif
) where
import Prelude ()
import Game.LambdaHack.Core.Prelude
import qualified Data.EnumMap.Strict as EM
import qualified Data.EnumSet as ES
import qualified Data.Map.Strict as M
import qualified NLP.Miniutter.English as MU
import Game.LambdaHack.Client.MonadClient
import Game.LambdaHack.Client.State
import Game.LambdaHack.Client.UI.ActorUI
import Game.LambdaHack.Client.UI.Content.Screen
import Game.LambdaHack.Client.UI.ContentClientUI
import Game.LambdaHack.Client.UI.EffectDescription
import Game.LambdaHack.Client.UI.Frame
import Game.LambdaHack.Client.UI.HandleHelperM
import qualified Game.LambdaHack.Client.UI.Key as K
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.Client.UI.Slideshow
import Game.LambdaHack.Client.UI.SlideshowM
import Game.LambdaHack.Common.Actor
import Game.LambdaHack.Common.ActorState
import Game.LambdaHack.Common.Analytics
import Game.LambdaHack.Common.ClientOptions
import Game.LambdaHack.Common.Faction
import Game.LambdaHack.Common.Item
import qualified Game.LambdaHack.Common.ItemAspect as IA
import Game.LambdaHack.Common.Kind
import Game.LambdaHack.Common.Misc
import Game.LambdaHack.Common.MonadStateRead
import Game.LambdaHack.Common.State
import Game.LambdaHack.Common.Types
import Game.LambdaHack.Content.FactionKind
import qualified Game.LambdaHack.Content.ItemKind as IK
import Game.LambdaHack.Content.ModeKind
import qualified Game.LambdaHack.Definition.Ability as Ability
import Game.LambdaHack.Definition.Defs
quitFactionUI :: MonadClientUI m
=> FactionId -> Maybe Status
-> Maybe (FactionAnalytics, GenerationAnalytics)
-> m ()
quitFactionUI :: forall (m :: * -> *).
MonadClientUI m =>
FactionId
-> Maybe Status
-> Maybe (FactionAnalytics, GenerationAnalytics)
-> m ()
quitFactionUI FactionId
fid Maybe Status
toSt Maybe (FactionAnalytics, GenerationAnalytics)
manalytics = do
side <- (StateClient -> FactionId) -> m FactionId
forall a. (StateClient -> a) -> m a
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> FactionId
sside
gameModeId <- getsState sgameModeId
when (side == fid) $ case toSt of
Just Status{stOutcome :: Status -> Outcome
stOutcome=Outcome
Camping} ->
(SessionUI -> SessionUI) -> m ()
forall (m :: * -> *).
MonadClientUI m =>
(SessionUI -> SessionUI) -> m ()
modifySession ((SessionUI -> SessionUI) -> m ())
-> (SessionUI -> SessionUI) -> m ()
forall a b. (a -> b) -> a -> b
$ \SessionUI
sess ->
SessionUI
sess {scampings = ES.insert gameModeId $ scampings sess}
Just Status{stOutcome :: Status -> Outcome
stOutcome=Outcome
Restart} ->
(SessionUI -> SessionUI) -> m ()
forall (m :: * -> *).
MonadClientUI m =>
(SessionUI -> SessionUI) -> m ()
modifySession ((SessionUI -> SessionUI) -> m ())
-> (SessionUI -> SessionUI) -> m ()
forall a b. (a -> b) -> a -> b
$ \SessionUI
sess ->
SessionUI
sess {srestarts = ES.insert gameModeId $ srestarts sess}
Just Status{Outcome
stOutcome :: Status -> Outcome
stOutcome :: Outcome
stOutcome} | Outcome
stOutcome Outcome -> [Outcome] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Outcome]
victoryOutcomes -> do
scurChal <- (StateClient -> Challenge) -> m Challenge
forall a. (StateClient -> a) -> m a
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> Challenge
scurChal
let sing = Challenge -> Int -> Map Challenge Int
forall k a. k -> a -> Map k a
M.singleton Challenge
scurChal Int
1
f = (Int -> Int -> Int)
-> Map Challenge Int -> Map Challenge Int -> Map Challenge Int
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
M.unionWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(+)
g = (Map Challenge Int -> Map Challenge Int -> Map Challenge Int)
-> ContentId ModeKind
-> Map Challenge Int
-> EnumMap (ContentId ModeKind) (Map Challenge Int)
-> EnumMap (ContentId ModeKind) (Map Challenge Int)
forall k a.
Enum k =>
(a -> a -> a) -> k -> a -> EnumMap k a -> EnumMap k a
EM.insertWith Map Challenge Int -> Map Challenge Int -> Map Challenge Int
f ContentId ModeKind
gameModeId Map Challenge Int
sing
modifySession $ \SessionUI
sess -> SessionUI
sess {svictories = g $ svictories sess}
Maybe Status
_ -> () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
ClientOptions{sexposeItems} <- getsClient soptions
fact <- getsState $ (EM.! fid) . sfactionD
let fidName = Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ Faction -> Text
gname Faction
fact
person = if FactionKind -> Bool
fhasGender (FactionKind -> Bool) -> FactionKind -> Bool
forall a b. (a -> b) -> a -> b
$ Faction -> FactionKind
gkind Faction
fact then Person
MU.PlEtc else Person
MU.Sg3rd
horror = Faction -> Bool
isHorrorFact Faction
fact
camping = Bool -> (Status -> Bool) -> Maybe Status -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True ((Outcome -> Outcome -> Bool
forall a. Eq a => a -> a -> Bool
== Outcome
Camping) (Outcome -> Bool) -> (Status -> Outcome) -> Status -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Status -> Outcome
stOutcome) Maybe Status
toSt
when (fid == side && not camping) $ do
tellGameClipPS
resetGameStart
gameMode <- getGameMode
allNframes <- getsSession sallNframes
let startingPart = case Maybe Status
toSt of
Maybe Status
_ | Bool
horror -> Maybe Part
forall a. Maybe a
Nothing
Just Status{stOutcome :: Status -> Outcome
stOutcome=stOutcome :: Outcome
stOutcome@Outcome
Restart, stNewGame :: Status -> Maybe (GroupName ModeKind)
stNewGame=Just GroupName ModeKind
gn} ->
Part -> Maybe Part
forall a. a -> Maybe a
Just (Part -> Maybe Part) -> Part -> Maybe Part
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ Outcome -> Text
nameOutcomeVerb Outcome
stOutcome
Text -> Text -> Text
<+> Text
"to restart in"
Text -> Text -> Text
<+> GroupName ModeKind -> Text
forall c. GroupName c -> Text
displayGroupName GroupName ModeKind
gn
Text -> Text -> Text
<+> Text
"mode"
Just Status{stOutcome :: Status -> Outcome
stOutcome=Outcome
Restart, stNewGame :: Status -> Maybe (GroupName ModeKind)
stNewGame=Maybe (GroupName ModeKind)
Nothing} ->
String -> Maybe Part
forall a. HasCallStack => String -> a
error (String -> Maybe Part) -> String -> Maybe Part
forall a b. (a -> b) -> a -> b
$ String
"" String -> (FactionId, Maybe Status) -> String
forall v. Show v => String -> v -> String
`showFailure` (FactionId
fid, Maybe Status
toSt)
Just Status{Outcome
stOutcome :: Status -> Outcome
stOutcome :: Outcome
stOutcome} -> Part -> Maybe Part
forall a. a -> Maybe a
Just (Part -> Maybe Part) -> Part -> Maybe Part
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text (Text -> Part) -> Text -> Part
forall a b. (a -> b) -> a -> b
$ Outcome -> Text
nameOutcomeVerb Outcome
stOutcome
Maybe Status
Nothing -> Maybe Part
forall a. Maybe a
Nothing
middlePart = case Maybe Status
toSt of
Maybe Status
_ | FactionId
fid FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
/= FactionId
side -> Maybe Text
forall a. Maybe a
Nothing
Just Status{Outcome
stOutcome :: Status -> Outcome
stOutcome :: Outcome
stOutcome} -> Outcome -> [(Outcome, Text)] -> Maybe Text
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Outcome
stOutcome ([(Outcome, Text)] -> Maybe Text)
-> [(Outcome, Text)] -> Maybe Text
forall a b. (a -> b) -> a -> b
$ ModeKind -> [(Outcome, Text)]
mendMsg ModeKind
gameMode
Maybe Status
Nothing -> Maybe Text
forall a. Maybe a
Nothing
partingPart = if FactionId
fid FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
/= FactionId
side Bool -> Bool -> Bool
|| Int
allNframes Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== -Int
1
then Maybe Text
forall a. Maybe a
Nothing
else Outcome -> Text
endMessageOutcome (Outcome -> Text) -> (Status -> Outcome) -> Status -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Status -> Outcome
stOutcome (Status -> Text) -> Maybe Status -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Status
toSt
case startingPart of
Maybe Part
Nothing -> () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just Part
sp ->
let blurb :: Text
blurb = [Part] -> Text
makeSentence [Person -> Polarity -> Part -> Part -> Part
MU.SubjectVerb Person
person Polarity
MU.Yes Part
fidName Part
sp]
in MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgLnAdd MsgClassShowAndSave
MsgFinalOutcome Text
blurb
case (toSt, partingPart) of
(Just Status
status, Just Text
pp) -> do
noConfirmsGame <- m Bool
forall (m :: * -> *). MonadStateRead m => m Bool
isNoConfirmsGame
go <- if noConfirmsGame
then return False
else displaySpaceEsc ColorFull ""
recordHistory
(itemBag, total) <- getsState $ calculateTotal side
when go $ do
case middlePart of
Maybe Text
Nothing -> () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just Text
sp1 -> do
factionD <- (State -> EnumMap FactionId Faction)
-> m (EnumMap FactionId Faction)
forall a. (State -> a) -> m a
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> EnumMap FactionId Faction
sfactionD
itemToF <- getsState $ flip itemToFull
let getTrunkFull (ActorId
aid, Actor
b) = (ActorId
aid, ItemId -> ItemFull
itemToF (ItemId -> ItemFull) -> ItemId -> ItemFull
forall a b. (a -> b) -> a -> b
$ Actor -> ItemId
btrunk Actor
b)
ourTrunks <- getsState $ map getTrunkFull
. fidActorNotProjGlobalAssocs side
let smartFaction Faction
fact2 = FactionKind -> Bool
fhasPointman (Faction -> FactionKind
gkind Faction
fact2)
canBeSmart = ((a, Faction) -> Bool) -> Frequency (a, Faction) -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Faction -> Bool
smartFaction (Faction -> Bool)
-> ((a, Faction) -> Faction) -> (a, Faction) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a, Faction) -> Faction
forall a b. (a, b) -> b
snd)
canBeOurFaction = ((FactionId, Faction) -> Bool)
-> Frequency (FactionId, Faction) -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\(FactionId
fid2, Faction
_) -> FactionId
fid2 FactionId -> FactionId -> Bool
forall a. Eq a => a -> a -> Bool
== FactionId
side)
smartEnemy ItemFull
trunkFull =
let possible :: Frequency (FactionId, Faction)
possible =
[GroupName ItemKind]
-> ItemKind
-> EnumMap FactionId Faction
-> Frequency (FactionId, Faction)
possibleActorFactions [] (ItemFull -> ItemKind
itemKind ItemFull
trunkFull) EnumMap FactionId Faction
factionD
in Bool -> Bool
not (Frequency (FactionId, Faction) -> Bool
canBeOurFaction Frequency (FactionId, Faction)
possible) Bool -> Bool -> Bool
&& Frequency (FactionId, Faction) -> Bool
forall {a}. Frequency (a, Faction) -> Bool
canBeSmart Frequency (FactionId, Faction)
possible
smartEnemiesOurs = ((ActorId, ItemFull) -> Bool)
-> [(ActorId, ItemFull)] -> [(ActorId, ItemFull)]
forall a. (a -> Bool) -> [a] -> [a]
filter (ItemFull -> Bool
smartEnemy (ItemFull -> Bool)
-> ((ActorId, ItemFull) -> ItemFull) -> (ActorId, ItemFull) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ActorId, ItemFull) -> ItemFull
forall a b. (a, b) -> b
snd) [(ActorId, ItemFull)]
ourTrunks
uniqueActor ItemFull
trunkFull = Flag -> AspectRecord -> Bool
IA.checkFlag Flag
Ability.Unique
(AspectRecord -> Bool) -> AspectRecord -> Bool
forall a b. (a -> b) -> a -> b
$ ItemFull -> AspectRecord
aspectRecordFull ItemFull
trunkFull
uniqueEnemiesOurs = ((ActorId, ItemFull) -> Bool)
-> [(ActorId, ItemFull)] -> [(ActorId, ItemFull)]
forall a. (a -> Bool) -> [a] -> [a]
filter (ItemFull -> Bool
uniqueActor (ItemFull -> Bool)
-> ((ActorId, ItemFull) -> ItemFull) -> (ActorId, ItemFull) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ActorId, ItemFull) -> ItemFull
forall a b. (a, b) -> b
snd) [(ActorId, ItemFull)]
smartEnemiesOurs
smartUniqueEnemyCaptured = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [(ActorId, ItemFull)] -> Bool
forall a. [a] -> Bool
null [(ActorId, ItemFull)]
uniqueEnemiesOurs
smartEnemyCaptured = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [(ActorId, ItemFull)] -> Bool
forall a. [a] -> Bool
null [(ActorId, ItemFull)]
smartEnemiesOurs
smartEnemySentence <- case uniqueEnemiesOurs ++ smartEnemiesOurs of
[] -> Text -> m Text
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Text
""
(ActorId
enemyAid, ItemFull
_) : [(ActorId, ItemFull)]
_ -> do
bUI <- (SessionUI -> ActorUI) -> m ActorUI
forall a. (SessionUI -> a) -> m a
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession ((SessionUI -> ActorUI) -> m ActorUI)
-> (SessionUI -> ActorUI) -> m ActorUI
forall a b. (a -> b) -> a -> b
$ ActorId -> SessionUI -> ActorUI
getActorUI ActorId
enemyAid
return $! makePhrase [MU.Capitalize (partActor bUI)] <> "?"
let won = Bool -> (Status -> Bool) -> Maybe Status -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False ((Outcome -> [Outcome] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Outcome]
victoryOutcomes) (Outcome -> Bool) -> (Status -> Outcome) -> Status -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Status -> Outcome
stOutcome) Maybe Status
toSt
lost = Bool -> (Status -> Bool) -> Maybe Status -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False ((Outcome -> [Outcome] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Outcome]
deafeatOutcomes) (Outcome -> Bool) -> (Status -> Outcome) -> Status -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Status -> Outcome
stOutcome) Maybe Status
toSt
msgClass | Bool
won = MsgClassShowAndSave
MsgGoodMiscEvent
| Bool
lost = MsgClassShowAndSave
MsgBadMiscEvent
| Bool
otherwise = MsgClassShowAndSave
MsgNeutralEvent
(sp2, escPrompt) =
if | lost -> ("", "Accept the unacceptable?")
| smartUniqueEnemyCaptured ->
( "\nOh, wait, who is this, towering behind your escaping crew?" <+> smartEnemySentence <+> "This changes everything. For everybody. Everywhere. Forever. Did you plan for this? Are you sure it was your idea?"
, "What happens now?" )
| smartEnemyCaptured ->
( "\nOh, wait, who is this, hunched among your escaping crew?" <+> smartEnemySentence <+> "Suddenly, this makes your crazy story credible. Suddenly, the door of knowledge opens again."
, "How will you play that move?" )
| otherwise -> ("", "Let's see what we've got here.")
msgAdd msgClass sp1
msgAdd MsgFactionIntel sp2
void $ displaySpaceEsc ColorFull escPrompt
case manalytics of
Maybe (FactionAnalytics, GenerationAnalytics)
Nothing -> () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just (FactionAnalytics
factionAn, GenerationAnalytics
generationAn) ->
[m KM] -> [m KM] -> m ()
forall (m :: * -> *). MonadClientUI m => [m KM] -> [m KM] -> m ()
cycleLore []
[ (ItemBag, Int) -> GenerationAnalytics -> m KM
forall (m :: * -> *).
MonadClientUI m =>
(ItemBag, Int) -> GenerationAnalytics -> m KM
displayGameOverLoot (ItemBag
itemBag, Int
total) GenerationAnalytics
generationAn
, SLore -> Bool -> GenerationAnalytics -> m KM
forall (m :: * -> *).
MonadClientUI m =>
SLore -> Bool -> GenerationAnalytics -> m KM
displayGameOverLore SLore
SOrgan Bool
True GenerationAnalytics
generationAn
, FactionAnalytics -> GenerationAnalytics -> m KM
forall (m :: * -> *).
MonadClientUI m =>
FactionAnalytics -> GenerationAnalytics -> m KM
displayGameOverAnalytics FactionAnalytics
factionAn GenerationAnalytics
generationAn
, SLore -> Bool -> GenerationAnalytics -> m KM
forall (m :: * -> *).
MonadClientUI m =>
SLore -> Bool -> GenerationAnalytics -> m KM
displayGameOverLore SLore
SCondition Bool
sexposeItems GenerationAnalytics
generationAn
, SLore -> Bool -> GenerationAnalytics -> m KM
forall (m :: * -> *).
MonadClientUI m =>
SLore -> Bool -> GenerationAnalytics -> m KM
displayGameOverLore SLore
SBlast Bool
True GenerationAnalytics
generationAn
, SLore -> Bool -> GenerationAnalytics -> m KM
forall (m :: * -> *).
MonadClientUI m =>
SLore -> Bool -> GenerationAnalytics -> m KM
displayGameOverLore SLore
SEmbed Bool
True GenerationAnalytics
generationAn ]
go2 <- if noConfirmsGame then return False else do
scoreSlides <- scoreToSlideshow total status
km <- getConfirms ColorFull [K.spaceKM, K.escKM] scoreSlides
return $! km == K.spaceKM
let epilogue = do
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
camping (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ MsgClassShow -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShow
MsgPromptGeneric Text
"Saving..."
m ()
forall (m :: * -> *). MonadClientUI m => m ()
pushReportFrame
if go2 && not noConfirmsGame && not camping then do
msgAdd MsgPromptGeneric $ pp <+> "(Press RET to have one last look at the arena of your struggle before it gets forgotten.)"
slides <-
reportToSlideshowKeepHalt True [K.returnKM, K.spaceKM, K.escKM]
km <- getConfirms ColorFull [K.returnKM, K.spaceKM, K.escKM] slides
if km == K.returnKM then do
lidV <- viewedLevelUI
let saimMode = AimMode -> Maybe AimMode
forall a. a -> Maybe a
Just (AimMode -> Maybe AimMode) -> AimMode -> Maybe AimMode
forall a b. (a -> b) -> a -> b
$ LevelId -> DetailLevel -> AimMode
AimMode LevelId
lidV DetailLevel
defaultDetailLevel
modifySession $ \SessionUI
sess -> SessionUI
sess { sreqDelay = ReqDelayHandled
, saimMode }
else epilogue
else do
when (not noConfirmsGame || camping) $ do
msgAdd MsgPromptGeneric pp
epilogue
(Maybe Status, Maybe Text)
_ ->
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe Part -> Bool
forall a. Maybe a -> Bool
isJust Maybe Part
startingPart Bool -> Bool -> Bool
&& (Status -> Outcome
stOutcome (Status -> Outcome) -> Maybe Status -> Maybe Outcome
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Status
toSt) Maybe Outcome -> Maybe Outcome -> Bool
forall a. Eq a => a -> a -> Bool
== Outcome -> Maybe Outcome
forall a. a -> Maybe a
Just Outcome
Killed) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ do
MsgClassShowAndSave -> Text -> m ()
forall (m :: * -> *) a.
(MonadClientUI m, MsgShared a) =>
a -> Text -> m ()
msgAdd MsgClassShowAndSave
MsgTutorialHint Text
"When a whole faction gets eliminated, no new members of the party will ever appear and its stashed belongings may remain far off, unclaimed and undefended. While some adventures require elimination a faction (to be verified in the adventure description screen in the help menu), for others it's an optional task, if possible at all. Instead, finding an exit may be necessary to win. It's enough if one character finds and triggers the exit. Others automatically follow, duly hauling all common belongings. Similarly, if eliminating foes ends a challenge, it happens immediately, with no need to move party members anywhere."
ColorMode -> Text -> m ()
forall (m :: * -> *). MonadClientUI m => ColorMode -> Text -> m ()
displayMore ColorMode
ColorFull Text
"This is grave news. What now?"
displayGameOverLoot :: MonadClientUI m
=> (ItemBag, Int) -> GenerationAnalytics -> m K.KM
displayGameOverLoot :: forall (m :: * -> *).
MonadClientUI m =>
(ItemBag, Int) -> GenerationAnalytics -> m KM
displayGameOverLoot (ItemBag
heldBag, Int
total) GenerationAnalytics
generationAn = do
ClientOptions{sexposeItems} <- (StateClient -> ClientOptions) -> m ClientOptions
forall a. (StateClient -> a) -> m a
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> ClientOptions
soptions
COps{coitem} <- getsState scops
let currencyName = ItemKind -> Text
IK.iname (ItemKind -> Text) -> ItemKind -> Text
forall a b. (a -> b) -> a -> b
$ ContentData ItemKind -> ContentId ItemKind -> ItemKind
forall a. ContentData a -> ContentId a -> a
okind ContentData ItemKind
coitem (ContentId ItemKind -> ItemKind) -> ContentId ItemKind -> ItemKind
forall a b. (a -> b) -> a -> b
$ ContentData ItemKind -> GroupName ItemKind -> ContentId ItemKind
forall a. Show a => ContentData a -> GroupName a -> ContentId a
ouniqGroup ContentData ItemKind
coitem GroupName ItemKind
IK.S_CURRENCY
generationItem = GenerationAnalytics
generationAn GenerationAnalytics -> SLore -> EnumMap ItemId Int
forall k a. Enum k => EnumMap k a -> k -> a
EM.! SLore
SItem
itemBag =
if Bool
sexposeItems
then let generationBag :: ItemBag
generationBag = (Int -> (Int, [ItemTimer])) -> EnumMap ItemId Int -> ItemBag
forall a b k. (a -> b) -> EnumMap k a -> EnumMap k b
EM.map (\Int
k -> (-Int
k, [])) EnumMap ItemId Int
generationItem
in ItemBag
heldBag ItemBag -> ItemBag -> ItemBag
forall k a. EnumMap k a -> EnumMap k a -> EnumMap k a
`EM.union` ItemBag
generationBag
else ItemBag
heldBag
promptFun ItemId
iid ItemFull
itemFull2 Int
k =
let worth :: Int
worth = Int -> ItemKind -> Int
itemPrice Int
1 (ItemKind -> Int) -> ItemKind -> Int
forall a b. (a -> b) -> a -> b
$ ItemFull -> ItemKind
itemKind ItemFull
itemFull2
lootMsg :: Text
lootMsg = if Int
worth Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then Text
"" else
let pile :: Part
pile = if Int
k Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
1 then Part
"exemplar" else Part
"hoard"
in [Part] -> Text
makeSentence ([Part] -> Text) -> [Part] -> Text
forall a b. (a -> b) -> a -> b
$
[Part
"this treasure", Part
pile, Part
"is worth"]
[Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ (if Int
k Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1 then [ Int -> Part
MU.Cardinal Int
k, Part
"times"] else [])
[Part] -> [Part] -> [Part]
forall a. [a] -> [a] -> [a]
++ [Int -> Part -> Part
MU.CarWs Int
worth (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text Text
currencyName]
holdsMsg :: Text
holdsMsg =
let n :: Int
n = EnumMap ItemId Int
generationItem EnumMap ItemId Int -> ItemId -> Int
forall k a. Enum k => EnumMap k a -> k -> a
EM.! ItemId
iid
in if | Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 Bool -> Bool -> Bool
&& Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 ->
Text
"You keep the only specimen extant:"
| Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 Bool -> Bool -> Bool
&& Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 ->
Text
"You don't have the only hypothesized specimen:"
| Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 Bool -> Bool -> Bool
&& Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 ->
Text
"No such specimen was recorded:"
| Bool
otherwise ->
[Part] -> Text
makePhrase [ Part
"You hold"
, if Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
n
then Part
"all pieces"
else Int -> Part -> Part
MU.CardinalAWs (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 Int
k) Part
"piece"
, Part
"out of"
, Int -> Part
MU.Car Int
n
, Part
"scattered:" ]
in Text
lootMsg Text -> Text -> Text
<+> Text
holdsMsg
dungeonTotal <- getsState sgold
let promptGold = Text -> Int -> Int -> Text
spoilsBlurb Text
currencyName Int
total Int
dungeonTotal
prompt =
Text
promptGold
Text -> Text -> Text
<+> (if Bool
sexposeItems
then Text
"Non-positive count means none held but this many generated."
else Text
"")
viewFinalLore "GameOverLoot" itemBag prompt promptFun (MLore SItem)
displayGameOverAnalytics :: MonadClientUI m
=> FactionAnalytics -> GenerationAnalytics
-> m K.KM
displayGameOverAnalytics :: forall (m :: * -> *).
MonadClientUI m =>
FactionAnalytics -> GenerationAnalytics -> m KM
displayGameOverAnalytics FactionAnalytics
factionAn GenerationAnalytics
generationAn = do
ClientOptions{sexposeActors} <- (StateClient -> ClientOptions) -> m ClientOptions
forall a. (StateClient -> a) -> m a
forall (m :: * -> *) a.
MonadClientRead m =>
(StateClient -> a) -> m a
getsClient StateClient -> ClientOptions
soptions
side <- getsClient sside
ItemRoles itemRoles <- getsSession sroles
let ourAn = Analytics -> EnumMap KillHow KillMap
akillCounts
(Analytics -> EnumMap KillHow KillMap)
-> Analytics -> EnumMap KillHow KillMap
forall a b. (a -> b) -> a -> b
$ Analytics -> FactionId -> FactionAnalytics -> Analytics
forall k a. Enum k => a -> k -> EnumMap k a -> a
EM.findWithDefault Analytics
emptyAnalytics FactionId
side FactionAnalytics
factionAn
foesAn = (Int -> Int -> Int) -> [EnumMap ItemId Int] -> EnumMap ItemId Int
forall a k. (a -> a -> a) -> [EnumMap k a] -> EnumMap k a
EM.unionsWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) ([EnumMap ItemId Int] -> EnumMap ItemId Int)
-> [EnumMap ItemId Int] -> EnumMap ItemId Int
forall a b. (a -> b) -> a -> b
$ (KillMap -> [EnumMap ItemId Int])
-> [KillMap] -> [EnumMap ItemId Int]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap KillMap -> [EnumMap ItemId Int]
forall k a. EnumMap k a -> [a]
EM.elems
([KillMap] -> [EnumMap ItemId Int])
-> [KillMap] -> [EnumMap ItemId Int]
forall a b. (a -> b) -> a -> b
$ (KillHow -> Maybe KillMap) -> [KillHow] -> [KillMap]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (KillHow -> EnumMap KillHow KillMap -> Maybe KillMap
forall k a. Enum k => k -> EnumMap k a -> Maybe a
`EM.lookup` EnumMap KillHow KillMap
ourAn)
[KillHow
KillKineticMelee .. KillHow
KillOtherPush]
killedBagIncludingProjectiles = (Int -> (Int, [ItemTimer])) -> EnumMap ItemId Int -> ItemBag
forall a b k. (a -> b) -> EnumMap k a -> EnumMap k b
EM.map (, []) EnumMap ItemId Int
foesAn
killedBag = (ItemId -> (Int, [ItemTimer]) -> Bool) -> ItemBag -> ItemBag
forall k a.
Enum k =>
(k -> a -> Bool) -> EnumMap k a -> EnumMap k a
EM.filterWithKey
(\ItemId
iid (Int, [ItemTimer])
_ -> ItemId
iid ItemId -> EnumSet ItemId -> Bool
forall k. Enum k => k -> EnumSet k -> Bool
`ES.member` (EnumMap SLore (EnumSet ItemId)
itemRoles EnumMap SLore (EnumSet ItemId) -> SLore -> EnumSet ItemId
forall k a. Enum k => EnumMap k a -> k -> a
EM.! SLore
STrunk))
ItemBag
killedBagIncludingProjectiles
generationTrunk = GenerationAnalytics
generationAn GenerationAnalytics -> SLore -> EnumMap ItemId Int
forall k a. Enum k => EnumMap k a -> k -> a
EM.! SLore
STrunk
trunkBag =
if Bool
sexposeActors
then let generationBag :: ItemBag
generationBag = (Int -> (Int, [ItemTimer])) -> EnumMap ItemId Int -> ItemBag
forall a b k. (a -> b) -> EnumMap k a -> EnumMap k b
EM.map (\Int
k -> (-Int
k, [])) EnumMap ItemId Int
generationTrunk
in ItemBag
killedBag ItemBag -> ItemBag -> ItemBag
forall k a. EnumMap k a -> EnumMap k a -> EnumMap k a
`EM.union` ItemBag
generationBag
else ItemBag
killedBag
total = [Int] -> Int
forall a. Num a => [a] -> a
sum ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
filter (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ ((Int, [ItemTimer]) -> Int) -> [(Int, [ItemTimer])] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int, [ItemTimer]) -> Int
forall a b. (a, b) -> a
fst ([(Int, [ItemTimer])] -> [Int]) -> [(Int, [ItemTimer])] -> [Int]
forall a b. (a -> b) -> a -> b
$ ItemBag -> [(Int, [ItemTimer])]
forall k a. EnumMap k a -> [a]
EM.elems ItemBag
trunkBag
promptFun :: ItemId -> ItemFull-> Int -> Text
promptFun ItemId
iid ItemFull
_ Int
k =
let n :: Int
n = EnumMap ItemId Int
generationTrunk EnumMap ItemId Int -> ItemId -> Int
forall k a. Enum k => EnumMap k a -> k -> a
EM.! ItemId
iid
in [Part] -> Text
makePhrase [ Part
"You recall the adversary, which you killed on"
, Int -> Part -> Part
MU.CarWs (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 Int
k) Part
"occasion", Part
"while reports mention"
, Int -> Part -> Part
MU.CarWs Int
n Part
"individual", Part
"in total:" ]
prompt =
[Part] -> Text
makeSentence [Part
"your team vanquished", Int -> Part -> Part
MU.CarWs Int
total Part
"adversary"]
Text -> Text -> Text
<+> (if Bool
sexposeActors
then Text
"Non-positive count means none killed but this many reported."
else Text
"")
viewFinalLore "GameOverAnalytics" trunkBag prompt promptFun (MLore STrunk)
displayGameOverLore :: MonadClientUI m
=> SLore -> Bool -> GenerationAnalytics -> m K.KM
displayGameOverLore :: forall (m :: * -> *).
MonadClientUI m =>
SLore -> Bool -> GenerationAnalytics -> m KM
displayGameOverLore SLore
slore Bool
exposeCount GenerationAnalytics
generationAn = do
itemD <- (State -> ItemDict) -> m ItemDict
forall a. (State -> a) -> m a
forall (m :: * -> *) a. MonadStateRead m => (State -> a) -> m a
getsState State -> ItemDict
sitemD
let
generationLore = (ItemId -> Int -> Bool) -> EnumMap ItemId Int -> EnumMap ItemId Int
forall k a.
Enum k =>
(k -> a -> Bool) -> EnumMap k a -> EnumMap k a
EM.filterWithKey (\ItemId
iid Int
_ -> ItemId
iid ItemId -> ItemDict -> Bool
forall k a. Enum k => k -> EnumMap k a -> Bool
`EM.member` ItemDict
itemD)
(EnumMap ItemId Int -> EnumMap ItemId Int)
-> EnumMap ItemId Int -> EnumMap ItemId Int
forall a b. (a -> b) -> a -> b
$ GenerationAnalytics
generationAn GenerationAnalytics -> SLore -> EnumMap ItemId Int
forall k a. Enum k => EnumMap k a -> k -> a
EM.! SLore
slore
generationBag = (Int -> (Int, [ItemTimer])) -> EnumMap ItemId Int -> ItemBag
forall a b k. (a -> b) -> EnumMap k a -> EnumMap k b
EM.map (\Int
k -> (if Bool
exposeCount then Int
k else Int
1, []))
EnumMap ItemId Int
generationLore
total = [Int] -> Int
forall a. Num a => [a] -> a
sum ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ ((Int, [ItemTimer]) -> Int) -> [(Int, [ItemTimer])] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int, [ItemTimer]) -> Int
forall a b. (a, b) -> a
fst ([(Int, [ItemTimer])] -> [Int]) -> [(Int, [ItemTimer])] -> [Int]
forall a b. (a -> b) -> a -> b
$ ItemBag -> [(Int, [ItemTimer])]
forall k a. EnumMap k a -> [a]
EM.elems ItemBag
generationBag
promptFun :: ItemId -> ItemFull-> Int -> Text
promptFun ItemId
_ ItemFull
_ Int
k =
[Part] -> Text
makeSentence
[ Part
"this", Text -> Part
MU.Text (SLore -> Text
ppSLore SLore
slore), Part
"manifested during your quest"
, Int -> Part -> Part
MU.CarWs Int
k Part
"time" ]
verb = if | SLore
slore SLore -> [SLore] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [SLore
SCondition, SLore
SBlast] -> Part
"experienced"
| SLore
slore SLore -> SLore -> Bool
forall a. Eq a => a -> a -> Bool
== SLore
SEmbed -> Part
"ambled among"
| Bool
otherwise -> Part
"lived among"
prompt = case Int
total of
Int
0 -> [Part] -> Text
makeSentence [ Part
"you didn't experience any"
, Part -> Part
MU.Ws (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text (SLore -> Text
headingSLore SLore
slore)
, Part
"this time" ]
Int
1 -> [Part] -> Text
makeSentence [ Part
"you saw the following"
, Text -> Part
MU.Text (SLore -> Text
headingSLore SLore
slore) ]
Int
_ -> [Part] -> Text
makeSentence [ Part
"you", Part
verb, Part
"the following variety of"
, Int -> Part -> Part
MU.CarWs Int
total (Part -> Part) -> Part -> Part
forall a b. (a -> b) -> a -> b
$ Text -> Part
MU.Text (SLore -> Text
headingSLore SLore
slore) ]
viewFinalLore ("GameOverLore" ++ show slore)
generationBag prompt promptFun (MLore slore)
viewFinalLore :: forall m . MonadClientUI m
=> String -> ItemBag -> Text
-> (ItemId -> ItemFull -> Int -> Text)
-> ItemDialogMode
-> m K.KM
viewFinalLore :: forall (m :: * -> *).
MonadClientUI m =>
String
-> ItemBag
-> Text
-> (ItemId -> ItemFull -> Int -> Text)
-> ItemDialogMode
-> m KM
viewFinalLore String
menuName ItemBag
trunkBag Text
prompt ItemId -> ItemFull -> Int -> Text
promptFun ItemDialogMode
dmode = do
CCUI{coscreen=ScreenContent{rheight}} <- (SessionUI -> CCUI) -> m CCUI
forall a. (SessionUI -> a) -> m a
forall (m :: * -> *) a. MonadClientUI m => (SessionUI -> a) -> m a
getsSession SessionUI -> CCUI
sccui
itemToF <- getsState $ flip itemToFull
let iids = (ItemId -> ItemFull)
-> [(ItemId, (Int, [ItemTimer]))] -> [(ItemId, (Int, [ItemTimer]))]
sortIids ItemId -> ItemFull
itemToF ([(ItemId, (Int, [ItemTimer]))] -> [(ItemId, (Int, [ItemTimer]))])
-> [(ItemId, (Int, [ItemTimer]))] -> [(ItemId, (Int, [ItemTimer]))]
forall a b. (a -> b) -> a -> b
$ ItemBag -> [(ItemId, (Int, [ItemTimer]))]
forall k a. Enum k => EnumMap k a -> [(k, a)]
EM.assocs ItemBag
trunkBag
viewAtSlot :: MenuSlot -> m K.KM
viewAtSlot MenuSlot
slot = do
let renderOneItem :: MenuSlot -> m OKX
renderOneItem = (ItemId -> ItemFull -> Int -> Text)
-> Int
-> ItemDialogMode
-> [(ItemId, (Int, [ItemTimer]))]
-> MenuSlot
-> m OKX
forall (m :: * -> *).
MonadClientUI m =>
(ItemId -> ItemFull -> Int -> Text)
-> Int
-> ItemDialogMode
-> [(ItemId, (Int, [ItemTimer]))]
-> MenuSlot
-> m OKX
okxItemLoreMsg ItemId -> ItemFull -> Int -> Text
promptFun Int
0 ItemDialogMode
dmode [(ItemId, (Int, [ItemTimer]))]
iids
extraKeys :: [a]
extraKeys = []
slotBound :: Int
slotBound = [(ItemId, (Int, [ItemTimer]))] -> Int
forall a. [a] -> Int
length [(ItemId, (Int, [ItemTimer]))]
iids Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
km <- (MenuSlot -> m OKX) -> [KM] -> Int -> MenuSlot -> m KM
forall (m :: * -> *).
MonadClientUI m =>
(MenuSlot -> m OKX) -> [KM] -> Int -> MenuSlot -> m KM
displayOneMenuItem MenuSlot -> m OKX
renderOneItem [KM]
forall a. [a]
extraKeys Int
slotBound MenuSlot
slot
case K.key km of
Key
K.Space -> String
-> ItemBag
-> Text
-> (ItemId -> ItemFull -> Int -> Text)
-> ItemDialogMode
-> m KM
forall (m :: * -> *).
MonadClientUI m =>
String
-> ItemBag
-> Text
-> (ItemId -> ItemFull -> Int -> Text)
-> ItemDialogMode
-> m KM
viewFinalLore String
menuName ItemBag
trunkBag Text
prompt ItemId -> ItemFull -> Int -> Text
promptFun ItemDialogMode
dmode
Key
K.Esc -> KM -> m KM
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return KM
km
Key
_ -> String -> m KM
forall a. HasCallStack => String -> a
error (String -> m KM) -> String -> m KM
forall a b. (a -> b) -> a -> b
$ String
"" String -> KM -> String
forall v. Show v => String -> v -> String
`showFailure` KM
km
msgAdd MsgPromptGeneric prompt
let keys = [KM
K.spaceKM, Char -> KM
K.mkChar Char
'<', Char -> KM
K.mkChar Char
'>', KM
K.escKM]
okx <- itemOverlay iids dmode
sli <- overlayToSlideshow (rheight - 2) keys okx
ekm <- displayChoiceScreenWithDefItemKey
(okxItemLoreInline promptFun 0 dmode iids) sli keys menuName
case ekm of
Left KM
km | KM
km KM -> [KM] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [KM]
keys -> KM -> m KM
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return KM
km
Left KM
km -> String -> m KM
forall a. HasCallStack => String -> a
error (String -> m KM) -> String -> m KM
forall a b. (a -> b) -> a -> b
$ String
"" String -> KM -> String
forall v. Show v => String -> v -> String
`showFailure` KM
km
Right MenuSlot
slot -> MenuSlot -> m KM
viewAtSlot MenuSlot
slot