diff --git a/src/Swarm/Game/Step.hs b/src/Swarm/Game/Step.hs index a4133fba3..e82cda2ad 100644 --- a/src/Swarm/Game/Step.hs +++ b/src/Swarm/Game/Step.hs @@ -190,6 +190,17 @@ hypotheticalWinCheck em g ws oc = do _ -> ws winCondition .= WinConditions newWinState (completions finalAccumulator) + + case newWinState of + Unwinnable _ -> do + currentTime <- sendIO getZonedTime + gameAchievements + %= M.insertWith + (<>) + LoseScenario + (Attainment (GameplayAchievement LoseScenario) Nothing currentTime) + _ -> return () + announcementQueue %= (>< Seq.fromList (map ObjectiveCompleted $ completionAnnouncementQueue finalAccumulator)) mapM_ handleException $ exceptions finalAccumulator @@ -730,11 +741,12 @@ stepCESK cesk = case cesk of case exn of CmdFailed _ _ (Just a) -> do currentTime <- sendIO getZonedTime + scenarioPath <- use currentScenarioPath gameAchievements %= M.insertWith (<>) a - (Attainment (GameplayAchievement a) Nothing currentTime) + (Attainment (GameplayAchievement a) scenarioPath currentTime) _ -> return () -- If an exception rises all the way to the top level without being diff --git a/src/Swarm/TUI/Controller.hs b/src/Swarm/TUI/Controller.hs index 1fe169399..139dac8a1 100644 --- a/src/Swarm/TUI/Controller.hs +++ b/src/Swarm/TUI/Controller.hs @@ -445,7 +445,7 @@ saveScenarioInfoOnQuit = do case segments of firstDir : _ -> do when (won && firstDir == tutorialsDirname) $ - attainAchievement' t (Just $ T.pack p) (GlobalAchievement CompletedSingleTutorial) + attainAchievement' t (Just p) (GlobalAchievement CompletedSingleTutorial) _ -> return () liftIO $ saveScenarioInfo p si diff --git a/src/Swarm/TUI/Model/Achievement/Attainment.hs b/src/Swarm/TUI/Model/Achievement/Attainment.hs index a48ebb79d..0cf9a5304 100644 --- a/src/Swarm/TUI/Model/Achievement/Attainment.hs +++ b/src/Swarm/TUI/Model/Achievement/Attainment.hs @@ -10,7 +10,6 @@ import Data.Aeson ( genericToJSON, ) import Data.Function (on) -import Data.Text (Text) import Data.Time (ZonedTime, zonedTimeToUTC) import Data.Yaml as Y import GHC.Generics (Generic) @@ -18,7 +17,7 @@ import Swarm.TUI.Model.Achievement.Definitions data Attainment = Attainment { _achievement :: CategorizedAchievement - , _maybeScenarioPath :: Maybe Text + , _maybeScenarioPath :: Maybe FilePath -- ^ from which scenario was it obtained? , _obtainedAt :: ZonedTime } diff --git a/src/Swarm/TUI/Model/Achievement/Definitions.hs b/src/Swarm/TUI/Model/Achievement/Definitions.hs index 540bba964..9de0384b0 100644 --- a/src/Swarm/TUI/Model/Achievement/Definitions.hs +++ b/src/Swarm/TUI/Model/Achievement/Definitions.hs @@ -77,6 +77,7 @@ data GameplayAchievement | RobotIntoWater | AttemptSelfDestructBase | DestroyedBase + | LoseScenario deriving (Eq, Ord, Show, Bounded, Enum, Generic) instance FromJSON GameplayAchievement diff --git a/src/Swarm/TUI/Model/Achievement/Description.hs b/src/Swarm/TUI/Model/Achievement/Description.hs index 84b4ec0ca..d8d9dcef5 100644 --- a/src/Swarm/TUI/Model/Achievement/Description.hs +++ b/src/Swarm/TUI/Model/Achievement/Description.hs @@ -61,3 +61,10 @@ describe (GameplayAchievement DestroyedBase) = "Actually destroy your base." Moderate True +describe (GameplayAchievement LoseScenario) = + AchievementInfo + "Silver Lining" + (Just $ Freeform "Here's your consolation prize.") + "Lose at a scenario." + Easy + True diff --git a/src/Swarm/TUI/Model/StateUpdate.hs b/src/Swarm/TUI/Model/StateUpdate.hs index 149508a1b..84a58c88a 100644 --- a/src/Swarm/TUI/Model/StateUpdate.hs +++ b/src/Swarm/TUI/Model/StateUpdate.hs @@ -114,7 +114,12 @@ attainAchievement a = do currentTime <- liftIO getZonedTime attainAchievement' currentTime Nothing a -attainAchievement' :: (MonadIO m, MonadState AppState m) => ZonedTime -> Maybe Text -> CategorizedAchievement -> m () +attainAchievement' :: + (MonadIO m, MonadState AppState m) => + ZonedTime -> + Maybe FilePath -> + CategorizedAchievement -> + m () attainAchievement' t p a = do (uiState . uiAchievements) %= M.insertWith