collapsing load/create scenario options directly into mission mode

This commit is contained in:
Dustin Carlino 2019-06-18 06:18:04 -07:00
parent a6aa46dd61
commit a7b10b7ec5
2 changed files with 79 additions and 86 deletions

View File

@ -11,8 +11,11 @@ use crate::render::DrawOptions;
use crate::sandbox::SandboxMode; use crate::sandbox::SandboxMode;
use crate::ui::ShowEverything; use crate::ui::ShowEverything;
use crate::ui::UI; use crate::ui::UI;
use abstutil::Timer;
use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard}; use ezgui::{hotkey, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
use geom::Duration; use geom::Duration;
use map_model::Map;
use sim::Scenario;
pub struct MissionEditMode { pub struct MissionEditMode {
state: State, state: State,
@ -21,7 +24,9 @@ pub struct MissionEditMode {
enum State { enum State {
Exploring(ModalMenu), Exploring(ModalMenu),
Neighborhood(neighborhood::NeighborhoodEditor), Neighborhood(neighborhood::NeighborhoodEditor),
Scenario(scenario::ScenarioEditor), LoadScenario(Wizard),
CreateNewScenario(Wizard),
EditScenario(scenario::ScenarioEditor),
DataViz(dataviz::DataVisualizer), DataViz(dataviz::DataVisualizer),
IndividualTrips(individ_trips::TripsVisualizer), IndividualTrips(individ_trips::TripsVisualizer),
AllTrips(all_trips::TripsVisualizer), AllTrips(all_trips::TripsVisualizer),
@ -44,7 +49,8 @@ impl MissionEditMode {
(hotkey(Key::S), "set up simulation with PSRC trips"), (hotkey(Key::S), "set up simulation with PSRC trips"),
(hotkey(Key::Q), "create scenario from PSRC trips"), (hotkey(Key::Q), "create scenario from PSRC trips"),
(hotkey(Key::N), "manage neighborhoods"), (hotkey(Key::N), "manage neighborhoods"),
(hotkey(Key::W), "manage scenarios"), (hotkey(Key::W), "load scenario"),
(None, "create new scenario"),
], ],
ctx, ctx,
)), )),
@ -98,10 +104,10 @@ impl MissionEditMode {
mode.state = State::Neighborhood( mode.state = State::Neighborhood(
neighborhood::NeighborhoodEditor::PickNeighborhood(Wizard::new()), neighborhood::NeighborhoodEditor::PickNeighborhood(Wizard::new()),
); );
} else if menu.action("manage scenarios") { } else if menu.action("load scenario") {
mode.state = State::Scenario(scenario::ScenarioEditor::PickScenario( mode.state = State::LoadScenario(Wizard::new());
Wizard::new(), } else if menu.action("create new scenario") {
)); mode.state = State::CreateNewScenario(Wizard::new());
} }
} }
State::DataViz(ref mut viz) => { State::DataViz(ref mut viz) => {
@ -134,7 +140,35 @@ impl MissionEditMode {
mode.state = MissionEditMode::new(ctx, &mut state.ui).state; mode.state = MissionEditMode::new(ctx, &mut state.ui).state;
} }
} }
State::Scenario(ref mut editor) => { State::LoadScenario(ref mut wizard) => {
if let Some(scenario) =
load_scenario(&state.ui.primary.map, &mut wizard.wrap(ctx))
{
mode.state =
State::EditScenario(scenario::ScenarioEditor::new(scenario, ctx));
} else if wizard.aborted() {
mode.state = MissionEditMode::new(ctx, &mut state.ui).state;
}
}
State::CreateNewScenario(ref mut wizard) => {
let mut wrapped = wizard.wrap(ctx);
if let Some(name) = wrapped.input_string("Name the scenario") {
mode.state = State::EditScenario(scenario::ScenarioEditor::new(
Scenario {
scenario_name: name,
map_name: state.ui.primary.map.get_name().to_string(),
seed_parked_cars: Vec::new(),
spawn_over_time: Vec::new(),
border_spawn_over_time: Vec::new(),
individ_trips: Vec::new(),
},
ctx,
));
} else if wizard.aborted() {
mode.state = MissionEditMode::new(ctx, &mut state.ui).state;
}
}
State::EditScenario(ref mut editor) => {
if let Some(new_mode) = editor.event(ctx, &mut state.ui) { if let Some(new_mode) = editor.event(ctx, &mut state.ui) {
state.mode = new_mode; state.mode = new_mode;
} }
@ -174,9 +208,12 @@ impl MissionEditMode {
State::Neighborhood(ref editor) => { State::Neighborhood(ref editor) => {
editor.draw(g, &state.ui); editor.draw(g, &state.ui);
} }
State::Scenario(ref editor) => { State::EditScenario(ref editor) => {
editor.draw(g, &state.ui); editor.draw(g, &state.ui);
} }
State::LoadScenario(ref wizard) | State::CreateNewScenario(ref wizard) => {
wizard.draw(g);
}
}, },
_ => unreachable!(), _ => unreachable!(),
} }
@ -186,3 +223,19 @@ impl MissionEditMode {
pub fn input_time(wizard: &mut WrappedWizard, query: &str) -> Option<Duration> { pub fn input_time(wizard: &mut WrappedWizard, query: &str) -> Option<Duration> {
wizard.input_something(query, None, Box::new(|line| Duration::parse(&line))) wizard.input_something(query, None, Box::new(|line| Duration::parse(&line)))
} }
fn load_scenario(map: &Map, wizard: &mut WrappedWizard) -> Option<Scenario> {
let map_name = map.get_name().to_string();
wizard
.choose_something_no_keys::<String>(
"Load which scenario?",
Box::new(move || abstutil::list_all_objects("scenarios", &map_name)),
)
.map(|(_, s)| {
abstutil::read_binary(
&format!("../data/scenarios/{}/{}.bin", map.get_name(), s),
&mut Timer::throwaway(),
)
.unwrap()
})
}

View File

@ -2,47 +2,38 @@ use crate::game::Mode;
use crate::mission::{input_time, MissionEditMode}; use crate::mission::{input_time, MissionEditMode};
use crate::sandbox::SandboxMode; use crate::sandbox::SandboxMode;
use crate::ui::UI; use crate::ui::UI;
use abstutil::{Timer, WeightedUsizeChoice}; use abstutil::WeightedUsizeChoice;
use ezgui::{hotkey, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard}; use ezgui::{hotkey, EventCtx, GfxCtx, Key, LogScroller, ModalMenu, Wizard, WrappedWizard};
use geom::Duration; use geom::Duration;
use map_model::{IntersectionID, Map, Neighborhood}; use map_model::{IntersectionID, Map, Neighborhood};
use sim::{BorderSpawnOverTime, OriginDestination, Scenario, SeedParkedCars, SpawnOverTime}; use sim::{BorderSpawnOverTime, OriginDestination, Scenario, SeedParkedCars, SpawnOverTime};
pub enum ScenarioEditor { pub enum ScenarioEditor {
PickScenario(Wizard),
ManageScenario(ModalMenu, Scenario, LogScroller), ManageScenario(ModalMenu, Scenario, LogScroller),
EditScenario(Scenario, Wizard), EditScenario(Scenario, Wizard),
} }
impl ScenarioEditor { impl ScenarioEditor {
fn modal_menu(name: &str, ctx: &EventCtx) -> ModalMenu { pub fn new(scenario: Scenario, ctx: &mut EventCtx) -> ScenarioEditor {
ModalMenu::new( let scroller = LogScroller::new(scenario.scenario_name.clone(), scenario.describe());
&format!("Scenario Editor for {}", name), ScenarioEditor::ManageScenario(
vec![ ModalMenu::new(
(hotkey(Key::Escape), "quit"), &format!("Scenario Editor for {}", scenario.scenario_name),
(hotkey(Key::S), "save"), vec![
(hotkey(Key::E), "edit"), (hotkey(Key::Escape), "quit"),
(hotkey(Key::I), "instantiate"), (hotkey(Key::S), "save"),
], (hotkey(Key::E), "edit"),
ctx, (hotkey(Key::I), "instantiate"),
],
ctx,
),
scenario,
scroller,
) )
} }
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Option<Mode> { pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Option<Mode> {
match self { match self {
ScenarioEditor::PickScenario(ref mut wizard) => {
if let Some(scenario) = pick_scenario(&ui.primary.map, wizard.wrap(ctx)) {
let scroller =
LogScroller::new(scenario.scenario_name.clone(), scenario.describe());
*self = ScenarioEditor::ManageScenario(
ScenarioEditor::modal_menu(&scenario.scenario_name, ctx),
scenario,
scroller,
);
} else if wizard.aborted() {
return Some(Mode::Mission(MissionEditMode::new(ctx, ui)));
}
}
ScenarioEditor::ManageScenario(ref mut menu, scenario, ref mut scroller) => { ScenarioEditor::ManageScenario(ref mut menu, scenario, ref mut scroller) => {
menu.handle_event(ctx, None); menu.handle_event(ctx, None);
ctx.canvas.handle_event(ctx.input); ctx.canvas.handle_event(ctx.input);
@ -67,22 +58,10 @@ impl ScenarioEditor {
} }
ScenarioEditor::EditScenario(ref mut scenario, ref mut wizard) => { ScenarioEditor::EditScenario(ref mut scenario, ref mut wizard) => {
if let Some(()) = edit_scenario(&ui.primary.map, scenario, wizard.wrap(ctx)) { if let Some(()) = edit_scenario(&ui.primary.map, scenario, wizard.wrap(ctx)) {
let scroller =
LogScroller::new(scenario.scenario_name.clone(), scenario.describe());
// TODO autosave, or at least make it clear there are unsaved edits // TODO autosave, or at least make it clear there are unsaved edits
*self = ScenarioEditor::ManageScenario( *self = ScenarioEditor::new(scenario.clone(), ctx);
ScenarioEditor::modal_menu(&scenario.scenario_name, ctx),
scenario.clone(),
scroller,
);
} else if wizard.aborted() { } else if wizard.aborted() {
let scroller = *self = ScenarioEditor::new(scenario.clone(), ctx);
LogScroller::new(scenario.scenario_name.clone(), scenario.describe());
*self = ScenarioEditor::ManageScenario(
ScenarioEditor::modal_menu(&scenario.scenario_name, ctx),
scenario.clone(),
scroller,
);
} }
} }
} }
@ -91,9 +70,6 @@ impl ScenarioEditor {
pub fn draw(&self, g: &mut GfxCtx, ui: &UI) { pub fn draw(&self, g: &mut GfxCtx, ui: &UI) {
match self { match self {
ScenarioEditor::PickScenario(wizard) => {
wizard.draw(g);
}
ScenarioEditor::ManageScenario(ref menu, _, scroller) => { ScenarioEditor::ManageScenario(ref menu, _, scroller) => {
scroller.draw(g); scroller.draw(g);
menu.draw(g); menu.draw(g);
@ -108,26 +84,6 @@ impl ScenarioEditor {
} }
} }
fn pick_scenario(map: &Map, mut wizard: WrappedWizard) -> Option<Scenario> {
let load_existing = "Load existing scenario";
let create_new = "Create new scenario";
if wizard.choose_string("What scenario to edit?", vec![load_existing, create_new])?
== load_existing
{
load_scenario(map, &mut wizard, "Load which scenario?")
} else {
let scenario_name = wizard.input_string("Name the scenario")?;
Some(Scenario {
scenario_name,
map_name: map.get_name().to_string(),
seed_parked_cars: Vec::new(),
spawn_over_time: Vec::new(),
border_spawn_over_time: Vec::new(),
individ_trips: Vec::new(),
})
}
}
fn edit_scenario(map: &Map, scenario: &mut Scenario, mut wizard: WrappedWizard) -> Option<()> { fn edit_scenario(map: &Map, scenario: &mut Scenario, mut wizard: WrappedWizard) -> Option<()> {
let seed_parked = "Seed parked cars"; let seed_parked = "Seed parked cars";
let spawn = "Spawn agents"; let spawn = "Spawn agents";
@ -224,22 +180,6 @@ fn choose_neighborhood(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Op
.map(|(n, _)| n) .map(|(n, _)| n)
} }
fn load_scenario(map: &Map, wizard: &mut WrappedWizard, query: &str) -> Option<Scenario> {
let map_name = map.get_name().to_string();
wizard
.choose_something_no_keys::<String>(
query,
Box::new(move || abstutil::list_all_objects("scenarios", &map_name)),
)
.map(|(_, s)| {
abstutil::read_binary(
&format!("../data/scenarios/{}/{}.bin", map.get_name(), s),
&mut Timer::throwaway(),
)
.unwrap()
})
}
fn input_weighted_usize(wizard: &mut WrappedWizard, query: &str) -> Option<WeightedUsizeChoice> { fn input_weighted_usize(wizard: &mut WrappedWizard, query: &str) -> Option<WeightedUsizeChoice> {
wizard.input_something( wizard.input_something(
query, query,