diff --git a/game/src/lib.rs b/game/src/lib.rs index 864810e7a5..f6ab7a8020 100644 --- a/game/src/lib.rs +++ b/game/src/lib.rs @@ -96,7 +96,13 @@ pub fn main() { let name = MapName::new("gb", &city, "center"); flags.sim_flags.load = name.path(); flags.study_area = Some(site); - mode = Some(sandbox::GameplayMode::Blog(name)); + // Start with the baseline scenario if it exists. + let scenario = if abstio::file_exists(abstio::path_scenario(&name, "base")) { + Some("base".to_string()) + } else { + None + }; + mode = Some(sandbox::GameplayMode::Blog(name, scenario)); } args.done(); @@ -277,7 +283,7 @@ fn finish_app_setup( let states: Vec>> = if title { vec![Box::new(TitleScreen::new(ctx, app))] } else if let Some(mode) = maybe_mode { - if let GameplayMode::Blog(_) = mode { + if let GameplayMode::Blog(_, _) = mode { vec![SandboxMode::async_new(app, mode, start_daytime)] } else { vec![SandboxMode::simple_new(app, mode)] diff --git a/game/src/sandbox/gameplay/blog.rs b/game/src/sandbox/gameplay/blog.rs index a093e2cd24..ceae1a1e76 100644 --- a/game/src/sandbox/gameplay/blog.rs +++ b/game/src/sandbox/gameplay/blog.rs @@ -1,6 +1,5 @@ -use std::collections::BTreeMap; - use map_gui::tools::{grey_out_map, nice_map_name, open_browser, PopupMsg}; +use sim::{PersonID, TripID}; use widgetry::{ lctrl, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, SimpleState, StyledButtons, Text, TextExt, VerticalAlignment, Widget, @@ -8,19 +7,21 @@ use widgetry::{ use crate::app::{App, Transition}; use crate::edit::EditMode; -use crate::info::Tab; +use crate::info::{OpenTrip, Tab}; use crate::sandbox::gameplay::freeform::ChangeScenario; use crate::sandbox::gameplay::{GameplayMode, GameplayState}; use crate::sandbox::{Actions, SandboxControls}; pub struct Blog { top_center: Panel, + scenario_name: Option, } impl Blog { - pub fn new(ctx: &mut EventCtx) -> Box { + pub fn new(ctx: &mut EventCtx, scenario_name: Option) -> Box { Box::new(Blog { top_center: Panel::empty(ctx), + scenario_name, }) } } @@ -68,19 +69,12 @@ impl GameplayState for Blog { Some(Transition::Push(SimpleState::new(panel, Box::new(About)))) } "follow someone" => { - // Just find the first active non-bus person - if let Some(person) = app - .primary - .sim - .active_agents() - .into_iter() - .filter_map(|a| app.primary.sim.agent_to_person(a)) - .next() - { + if let Some((person, trip)) = find_active_trip(app) { + ctx.canvas.cam_zoom = 40.0; controls.common.as_mut().unwrap().launch_info_panel( ctx, app, - Tab::PersonTrips(person, BTreeMap::new()), + Tab::PersonTrips(person, OpenTrip::single(trip)), actions, ); None @@ -121,7 +115,10 @@ impl GameplayState for Blog { .draw(ctx), Widget::vert_separator(ctx, 50.0), ctx.style() - .btn_light_popup_icon_text("system/assets/tools/calendar.svg", "none") + .btn_light_popup_icon_text( + "system/assets/tools/calendar.svg", + self.scenario_name.as_ref().unwrap_or(&"none".to_string()), + ) .hotkey(Key::S) .build_widget(ctx, "change scenario"), ctx.style() @@ -167,3 +164,14 @@ impl SimpleState for About { grey_out_map(g, app); } } + +fn find_active_trip(app: &App) -> Option<(PersonID, TripID)> { + for agent in app.primary.sim.active_agents() { + if let Some(trip) = app.primary.sim.agent_to_trip(agent) { + if let Some(person) = app.primary.sim.trip_to_person(trip) { + return Some((person, trip)); + } + } + } + None +} diff --git a/game/src/sandbox/gameplay/mod.rs b/game/src/sandbox/gameplay/mod.rs index eb9de6fa94..da8c267135 100644 --- a/game/src/sandbox/gameplay/mod.rs +++ b/game/src/sandbox/gameplay/mod.rs @@ -39,7 +39,8 @@ pub enum GameplayMode { PlayScenario(MapName, String, Vec), FixTrafficSignals, OptimizeCommute(OrigPersonID, Duration), - Blog(MapName), + // Map name, scenario name + Blog(MapName, Option), // current Tutorial(TutorialPointer), @@ -104,15 +105,14 @@ impl GameplayMode { GameplayMode::FixTrafficSignals => MapName::seattle("downtown"), GameplayMode::OptimizeCommute(_, _) => MapName::seattle("montlake"), GameplayMode::Tutorial(_) => MapName::seattle("montlake"), - GameplayMode::Blog(ref name) => name.clone(), + GameplayMode::Blog(ref name, _) => name.clone(), } } pub fn scenario(&self, app: &App, mut rng: XorShiftRng, timer: &mut Timer) -> LoadScenario { let map = &app.primary.map; let name = match self { - // TODO Start with a scenario in blog mode, once all the actdev scenarios are imported. - GameplayMode::Freeform(_) | GameplayMode::Blog(_) => { + GameplayMode::Freeform(_) => { let mut s = Scenario::empty(map, "empty"); s.only_seed_buses = None; return LoadScenario::Scenario(s); @@ -126,7 +126,18 @@ impl GameplayMode { None => LoadScenario::Nothing, }; } - _ => "weekday".to_string(), + GameplayMode::Blog(_, ref maybe_scenario) => { + if let Some(s) = maybe_scenario { + s.to_string() + } else { + let mut s = Scenario::empty(map, "empty"); + s.only_seed_buses = None; + return LoadScenario::Scenario(s); + } + } + GameplayMode::FixTrafficSignals | GameplayMode::OptimizeCommute(_, _) => { + "weekday".to_string() + } }; if name == "random" { LoadScenario::Scenario(ScenarioGenerator::small_run(map).generate(map, &mut rng, timer)) @@ -218,7 +229,9 @@ impl GameplayMode { commute::OptimizeCommute::new(ctx, app, *p, *goal) } GameplayMode::Tutorial(current) => Tutorial::make_gameplay(ctx, app, *current), - GameplayMode::Blog(_) => blog::Blog::new(ctx), + GameplayMode::Blog(_, ref maybe_scenario) => { + blog::Blog::new(ctx, maybe_scenario.clone()) + } } } }