diff --git a/docs/dev.md b/docs/dev.md index 9e86285e7b..980b7f5488 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -5,7 +5,7 @@ You will first need: - Standard dependencies: `bash`, `curl`, `unzip`, `gunzip` -- Rust, at least 1.40. https://www.rust-lang.org/tools/install +- Rust, at least 1.41. https://www.rust-lang.org/tools/install One-time setup: diff --git a/game/src/game.rs b/game/src/game.rs index b2c46806ba..25f164fd95 100644 --- a/game/src/game.rs +++ b/game/src/game.rs @@ -81,11 +81,11 @@ impl GUI for Game { self.states.pop().unwrap().on_destroy(ctx, &mut self.ui); self.states.push(state); } - Transition::Clear(state) => { + Transition::Clear(states) => { while !self.states.is_empty() { self.states.pop().unwrap().on_destroy(ctx, &mut self.ui); } - self.states.push(state); + self.states.extend(states); } Transition::ApplyObjectAction(action) => { self.ui.per_obj.action_chosen(action); @@ -187,7 +187,7 @@ pub enum Transition { Push(Box), Replace(Box), PopThenReplace(Box), - Clear(Box), + Clear(Vec>), ApplyObjectAction(String), PushTwice(Box, Box), } diff --git a/game/src/sandbox/gameplay/fix_traffic_signals.rs b/game/src/sandbox/gameplay/fix_traffic_signals.rs index b52e76990a..9c83361fec 100644 --- a/game/src/sandbox/gameplay/fix_traffic_signals.rs +++ b/game/src/sandbox/gameplay/fix_traffic_signals.rs @@ -1,8 +1,8 @@ use crate::common::Overlays; -use crate::game::{msg, Transition}; +use crate::game::Transition; use crate::helpers::cmp_duration_shorter; use crate::managed::{WrappedComposite, WrappedOutcome}; -use crate::sandbox::gameplay::{challenge_controller, GameplayMode, GameplayState}; +use crate::sandbox::gameplay::{challenge_controller, FinalScore, GameplayMode, GameplayState}; use crate::ui::UI; use ezgui::{EventCtx, GfxCtx, Line, ManagedWidget, Text}; use geom::{Duration, Statistic, Time}; @@ -51,8 +51,11 @@ impl GameplayState for FixTrafficSignals { } if ui.primary.sim.is_done() { - // TODO Stop the challenge somehow - return Some(Transition::Push(msg("Final score", vec![final_score(ui)]))); + return Some(Transition::Push(FinalScore::new( + ctx, + final_score(ui), + self.mode.clone(), + ))); } None @@ -91,7 +94,7 @@ fn make_top_center(ctx: &mut EventCtx, ui: &UI, mode: GameplayMode) -> WrappedCo WrappedComposite::text_button(ctx, "details", None).margin(5), ]) .centered(), - ManagedWidget::draw_text(ctx, Text::from(Line(format!("Goal: {}", GOAL)))), + ManagedWidget::draw_text(ctx, Text::from(Line(format!("Goal: {} faster", GOAL)))), ], ) .cb( diff --git a/game/src/sandbox/gameplay/mod.rs b/game/src/sandbox/gameplay/mod.rs index 6ce4273711..a1c8c9f470 100644 --- a/game/src/sandbox/gameplay/mod.rs +++ b/game/src/sandbox/gameplay/mod.rs @@ -7,17 +7,19 @@ mod play_scenario; pub mod spawner; use crate::challenges; -use crate::common::Overlays; +use crate::challenges::challenges_picker; +use crate::common::{CommonState, Overlays}; use crate::edit::EditMode; -use crate::game::{msg, Transition}; +use crate::game::{msg, State, Transition}; use crate::managed::WrappedComposite; +use crate::pregame::main_menu; use crate::render::{AgentColorScheme, InnerAgentColorScheme}; use crate::sandbox::SandboxMode; use crate::ui::UI; use abstutil::Timer; use ezgui::{ lctrl, Choice, Color, Composite, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, Line, - ManagedWidget, ModalMenu, Text, VerticalAlignment, Wizard, + ManagedWidget, ModalMenu, Outcome, Text, VerticalAlignment, Wizard, }; use geom::{Duration, Polygon}; use map_model::{EditCmd, Map, MapEdits}; @@ -320,3 +322,71 @@ fn challenge_controller( Box::new(move |_, _| Some(Transition::Push(msg("Challenge", description.clone())))), ) } + +struct FinalScore { + composite: Composite, + mode: GameplayMode, +} + +impl FinalScore { + fn new(ctx: &mut EventCtx, verdict: String, mode: GameplayMode) -> Box { + let mut txt = Text::prompt("Final score"); + txt.add(Line(verdict)); + Box::new(FinalScore { + composite: Composite::new( + ManagedWidget::col(vec![ + ManagedWidget::draw_text(ctx, txt), + ManagedWidget::row(vec![ + WrappedComposite::text_button(ctx, "try again", None), + WrappedComposite::text_button(ctx, "back to challenges", None), + ]) + .centered(), + ]) + .bg(Color::grey(0.4)) + .outline(10.0, Color::WHITE) + .padding(10), + ) + .aligned(HorizontalAlignment::Center, VerticalAlignment::Center) + .build(ctx), + mode, + }) + } +} + +impl State for FinalScore { + fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition { + match self.composite.event(ctx) { + Some(Outcome::Clicked(x)) => match x.as_ref() { + "try again" => { + ui.primary.clear_sim(); + Transition::PopThenReplace(Box::new(SandboxMode::new( + ctx, + ui, + self.mode.clone(), + ))) + } + "back to challenges" => { + ui.primary.clear_sim(); + Transition::Clear(vec![main_menu(ctx, ui), challenges_picker(ctx)]) + } + _ => unreachable!(), + }, + None => Transition::Keep, + } + } + + fn draw(&self, g: &mut GfxCtx, ui: &UI) { + // Make it clear the map can't be interacted with right now. + g.fork_screenspace(); + // TODO - OSD height + g.draw_polygon( + Color::BLACK.alpha(0.5), + &Polygon::rectangle(g.canvas.window_width, g.canvas.window_height), + ); + g.unfork(); + + self.composite.draw(g); + // Still want to show hotkeys + CommonState::draw_osd(g, ui, &None); + } +} diff --git a/game/src/sandbox/mod.rs b/game/src/sandbox/mod.rs index fd777835a8..65117aef37 100644 --- a/game/src/sandbox/mod.rs +++ b/game/src/sandbox/mod.rs @@ -153,7 +153,7 @@ impl State for SandboxMode { ui.primary.clear_sim(); ui.set_prebaked(None); ctx.canvas.save_camera_state(ui.primary.map.get_name()); - Some(Transition::Clear(main_menu(ctx, ui))) + Some(Transition::Clear(vec![main_menu(ctx, ui)])) } "quit challenge" => { if !ui.primary.map.get_edits().is_empty() { @@ -166,7 +166,7 @@ impl State for SandboxMode { ui.primary.clear_sim(); ui.set_prebaked(None); ctx.canvas.save_camera_state(ui.primary.map.get_name()); - Some(Transition::Clear(main_menu(ctx, ui))) + Some(Transition::Clear(vec![main_menu(ctx, ui)])) } "keep playing" => Some(Transition::Pop), _ => unreachable!(),