dont force reset from midnight in survivor mode!

This commit is contained in:
Dustin Carlino 2020-06-11 16:30:31 -07:00
parent 4e746cc033
commit 269bdc9171
6 changed files with 101 additions and 34 deletions

View File

@ -134,7 +134,12 @@ impl Btn {
pub fn plaintext<I: Into<String>>(label: I) -> BtnBuilder {
let label = label.into();
BtnBuilder::PlainText(label.clone(), Text::from(Line(label)), None)
BtnBuilder::PlainText {
label: label.clone(),
txt: Text::from(Line(label)),
maybe_tooltip: None,
pad: (15.0, 8.0),
}
}
pub fn text_fg<I: Into<String>>(label: I) -> BtnBuilder {
@ -205,7 +210,12 @@ pub enum BtnBuilder {
pad: usize,
},
TextFG(String, Text, Option<Text>),
PlainText(String, Text, Option<Text>),
PlainText {
label: String,
txt: Text,
maybe_tooltip: Option<Text>,
pad: (f64, f64),
},
TextBG {
label: String,
maybe_tooltip: Option<Text>,
@ -220,11 +230,14 @@ pub enum BtnBuilder {
impl BtnBuilder {
pub fn tooltip(mut self, tooltip: Text) -> BtnBuilder {
match self {
BtnBuilder::TextFG(_, _, ref mut t)
| BtnBuilder::PlainText(_, _, ref mut t)
| BtnBuilder::Custom(_, _, _, ref mut t) => {
assert!(t.is_none());
*t = Some(tooltip);
BtnBuilder::TextFG(_, _, ref mut maybe_tooltip)
| BtnBuilder::PlainText {
ref mut maybe_tooltip,
..
}
| BtnBuilder::Custom(_, _, _, ref mut maybe_tooltip) => {
assert!(maybe_tooltip.is_none());
*maybe_tooltip = Some(tooltip);
}
BtnBuilder::SVG {
ref mut maybe_tooltip,
@ -264,6 +277,10 @@ impl BtnBuilder {
*pad = new_pad;
self
}
BtnBuilder::PlainText { ref mut pad, .. } => {
*pad = (new_pad as f64, new_pad as f64);
self
}
_ => unreachable!(),
}
}
@ -336,25 +353,24 @@ impl BtnBuilder {
.outline(2.0, Color::WHITE)
}
// Same as TextFG without the outline
BtnBuilder::PlainText(_, normal_txt, maybe_t) => {
// TODO Padding here is unfortunate, but I don't understand when the flexbox padding
// actually works.
let horiz_padding = 15.0;
let vert_padding = 8.0;
BtnBuilder::PlainText {
txt,
maybe_tooltip,
pad,
..
} => {
let normal_txt = txt;
let unselected_batch = normal_txt.clone().render_ctx(ctx);
let dims = unselected_batch.get_dims();
let selected_batch = normal_txt.change_fg(Color::ORANGE).render_ctx(ctx);
assert_eq!(dims, selected_batch.get_dims());
let geom = Polygon::rectangle(
dims.width + 2.0 * horiz_padding,
dims.height + 2.0 * vert_padding,
);
let geom = Polygon::rectangle(dims.width + 2.0 * pad.0, dims.height + 2.0 * pad.1);
let mut normal = GeomBatch::new();
normal.append(unselected_batch.translate(horiz_padding, vert_padding));
normal.append(unselected_batch.translate(pad.0, pad.1));
let mut hovered = GeomBatch::new();
hovered.append(selected_batch.translate(horiz_padding, vert_padding));
hovered.append(selected_batch.translate(pad.0, pad.1));
Button::new(
ctx,
@ -362,7 +378,7 @@ impl BtnBuilder {
hovered,
key,
&action_tooltip.into(),
maybe_t,
maybe_tooltip,
geom,
)
}
@ -418,7 +434,7 @@ impl BtnBuilder {
BtnBuilder::SVG { .. } => panic!("Can't use build_def on an SVG button"),
BtnBuilder::Custom(_, _, _, _) => panic!("Can't use build_def on a custom button"),
BtnBuilder::TextFG(ref label, _, _)
| BtnBuilder::PlainText(ref label, _, _)
| BtnBuilder::PlainText { ref label, .. }
| BtnBuilder::TextBG { ref label, .. } => {
assert!(!label.is_empty());
let copy = label.clone();

View File

@ -509,6 +509,8 @@ pub struct PerMap {
pub current_flags: Flags,
pub last_warped_from: Option<(Pt2D, f64)>,
pub sim_cb: Option<Box<dyn SimCallback>>,
// If we ever left edit mode and resumed without restarting from midnight, this is true.
pub dirty_from_edits: bool,
}
impl PerMap {
@ -530,11 +532,13 @@ impl PerMap {
current_flags: flags.clone(),
last_warped_from: None,
sim_cb: None,
dirty_from_edits: false,
}
}
// Returns whatever was there
pub fn clear_sim(&mut self) -> Sim {
self.dirty_from_edits = false;
std::mem::replace(
&mut self.sim,
Sim::new(

View File

@ -33,6 +33,8 @@ use std::collections::BTreeSet;
pub struct EditMode {
tool_panel: WrappedComposite,
composite: Composite,
orig_edits: MapEdits,
orig_dirty: bool,
// Retained state from the SandboxMode that spawned us
mode: GameplayMode,
@ -44,12 +46,15 @@ pub struct EditMode {
impl EditMode {
pub fn new(ctx: &mut EventCtx, app: &mut App, mode: GameplayMode) -> EditMode {
let orig_dirty = app.primary.dirty_from_edits;
assert!(app.suspended_sim.is_none());
app.suspended_sim = Some(app.primary.clear_sim());
let edits = app.primary.map.get_edits();
EditMode {
tool_panel: tool_panel(ctx, app),
composite: make_topcenter(ctx, app, &mode),
orig_edits: edits.clone(),
orig_dirty,
mode,
top_panel_key: (edits.edits_name.clone(), edits.commands.len()),
once: true,
@ -57,10 +62,17 @@ impl EditMode {
}
fn quit(&self, ctx: &mut EventCtx, app: &mut App) -> Transition {
let time = app.suspended_sim.take().unwrap().time();
let old_sim = app.suspended_sim.take().unwrap();
app.layer = None;
ctx.loading_screen("apply edits", |ctx, mut timer| {
app.layer = None;
// If nothing changed, short-circuit
if app.primary.map.get_edits() == &self.orig_edits {
app.primary.sim = old_sim;
app.primary.dirty_from_edits = self.orig_dirty;
return Transition::Pop;
}
ctx.loading_screen("apply edits", move |ctx, mut timer| {
app.primary
.map
.recalculate_pathfinding_after_edits(&mut timer);
@ -71,10 +83,16 @@ impl EditMode {
app.primary.map.save_edits();
}
if app.opts.resume_after_edit {
Transition::PopThenReplaceThenPush(
Box::new(SandboxMode::new(ctx, app, self.mode.clone())),
TimeWarpScreen::new(ctx, app, time, false),
)
if self.mode.reset_after_edits() {
Transition::PopThenReplaceThenPush(
Box::new(SandboxMode::new(ctx, app, self.mode.clone())),
TimeWarpScreen::new(ctx, app, old_sim.time(), false),
)
} else {
app.primary.sim = old_sim;
app.primary.dirty_from_edits = true;
Transition::Pop
}
} else {
Transition::PopThenReplace(Box::new(SandboxMode::new(ctx, app, self.mode.clone())))
}

View File

@ -22,7 +22,6 @@ pub struct FixTrafficSignals {
top_center: Composite,
meter: Composite,
time: Time,
once: bool,
done: bool,
mode: GameplayMode,
}
@ -55,7 +54,6 @@ impl FixTrafficSignals {
.build(ctx),
meter: make_meter(ctx, app, None),
time: Time::START_OF_DAY,
once: true,
done: false,
mode: GameplayMode::FixTrafficSignals,
})
@ -109,9 +107,9 @@ impl GameplayState for FixTrafficSignals {
METER_HACK,
);
if self.once {
self.once = false;
assert!(app.primary.sim_cb.is_none());
// Normally we just do this once at the beginning, but because there are other paths to
// reseting (like jump-to-time), it's safest just to do this.
if app.primary.sim_cb.is_none() {
app.primary.sim_cb = Some(Box::new(FindDelayedIntersections {
halt_limit: THRESHOLD,
report_limit: Duration::minutes(1),
@ -252,6 +250,22 @@ impl GameplayState for FixTrafficSignals {
&mut app.primary,
)));
}
"explain score" => {
// TODO Adjust wording
return Some(Transition::Push(FYI::new(
ctx,
Text::from_multiline(vec![
Line("You changed some traffic signals in the middle of the day."),
Line(
"First see if you can survive for a full day, making changes \
along the way.",
),
Line("Then you should check if your changes work from midnight."),
])
.draw(ctx),
app.cs.panel_bg,
)));
}
_ => unreachable!(),
},
None => {}
@ -308,6 +322,14 @@ fn make_meter(
])
} else {
Widget::row(vec![
if app.primary.dirty_from_edits {
Btn::plaintext("(!)")
.pad(0)
.build(ctx, "explain score", None)
.margin_right(10)
} else {
Widget::nothing()
},
Text::from_all(vec![Line("Worst delay: "), Line("none!").secondary()])
.draw(ctx),
Widget::draw_svg_transform(

View File

@ -145,6 +145,13 @@ impl GameplayMode {
}
}
pub fn reset_after_edits(&self) -> bool {
match self {
GameplayMode::FixTrafficSignals => false,
_ => true,
}
}
pub fn allows(&self, edits: &MapEdits) -> bool {
for cmd in &edits.commands {
match cmd {

View File

@ -7,7 +7,7 @@ use geom::Speed;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct MapEdits {
pub edits_name: String,
pub commands: Vec<EditCmd>,
@ -29,7 +29,7 @@ pub enum EditIntersection {
Closed,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum EditCmd {
ChangeLaneType {
id: LaneID,