From f8ac0fc96b77349c4cf5a92b33b5c9b1e20df0a1 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Sat, 26 Dec 2020 20:10:17 -0800 Subject: [PATCH] Remember the upzoned buildings, and add a button to clear the choices. #431 --- abstutil/src/collections.rs | 13 +++++++++++ map_gui/src/lib.rs | 2 +- santa/src/before_level.rs | 44 ++++++++++++++++++++++++++++--------- santa/src/session.rs | 12 +++++++++- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/abstutil/src/collections.rs b/abstutil/src/collections.rs index 60e1bb39c0..fb1c2d9b08 100644 --- a/abstutil/src/collections.rs +++ b/abstutil/src/collections.rs @@ -50,6 +50,10 @@ where self.map.get(&key).unwrap_or(&self.empty) } + pub fn set(&mut self, key: K, values: BTreeSet) { + self.map.insert(key, values); + } + pub fn len(&self) -> usize { self.map.len() } @@ -62,6 +66,15 @@ where self.map } } +impl std::default::Default for MultiMap +where + K: Ord + PartialEq + Clone, + V: Ord + PartialEq + Clone, +{ + fn default() -> MultiMap { + MultiMap::new() + } +} #[derive(Clone)] pub struct Counter { diff --git a/map_gui/src/lib.rs b/map_gui/src/lib.rs index efa06b51dc..dc6c2da579 100644 --- a/map_gui/src/lib.rs +++ b/map_gui/src/lib.rs @@ -7,7 +7,7 @@ use abstutil::Timer; use geom::{Duration, Pt2D, Time}; use map_model::{AreaID, BuildingID, BusStopID, IntersectionID, LaneID, Map, ParkingLotID, RoadID}; use sim::{AgentID, CarID, PedestrianID, Sim}; -use widgetry::{Cached, EventCtx, GfxCtx, State}; +use widgetry::{EventCtx, GfxCtx, State}; pub use self::simple_app::SimpleApp; use crate::render::DrawOptions; diff --git a/santa/src/before_level.rs b/santa/src/before_level.rs index fe1dba898c..38e489f78f 100644 --- a/santa/src/before_level.rs +++ b/santa/src/before_level.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::collections::{BTreeSet, HashSet}; use rand::seq::SliceRandom; use rand::SeedableRng; @@ -30,7 +30,7 @@ pub struct Picker { upzone_panel: Panel, level: Level, bldgs: Buildings, - current_picks: HashSet, + current_picks: BTreeSet, draw_start: Drawable, } @@ -103,13 +103,20 @@ impl Picker { .color(RewriteColor::ChangeAll(Color::RED)) .centered_on(start); + let current_picks = app + .session + .upzones_per_level + .get(level.title.clone()) + .clone(); + let upzone_panel = make_upzone_panel(ctx, app, current_picks.len()); + Transition::Replace(Box::new(Picker { vehicle_panel: make_vehicle_panel(ctx, app), - upzone_panel: make_upzone_panel(ctx, app, 0), + upzone_panel, instructions_panel, level, bldgs, - current_picks: HashSet::new(), + current_picks, draw_start: ctx.upload(draw_start), })) }), @@ -166,18 +173,27 @@ impl State for Picker { Outcome::Clicked(x) => match x.as_ref() { "Start game" => { app.current_selection = None; + app.session + .upzones_per_level + .set(self.level.title.clone(), self.current_picks.clone()); + app.session.save(); + return Transition::Replace(Game::new( ctx, app, self.level.clone(), Vehicle::get(&app.session.current_vehicle), - self.current_picks.clone(), + self.current_picks.clone().into_iter().collect(), )); } "Randomly choose upzones" => { self.randomly_pick_upzones(app); self.upzone_panel = make_upzone_panel(ctx, app, self.current_picks.len()); } + "Clear upzones" => { + self.current_picks.clear(); + self.upzone_panel = make_upzone_panel(ctx, app, self.current_picks.len()); + } "help" => { return explain_upzoning(ctx); } @@ -306,11 +322,19 @@ fn make_upzone_panel(ctx: &mut EventCtx, app: &App, num_picked: usize) -> Panel "Upzones chosen:".draw_text(ctx), make_bar(ctx, Color::PINK, num_picked, app.session.upzones_unlocked), ]), - if num_picked == app.session.upzones_unlocked { - Btn::text_fg("Randomly choose upzones").inactive(ctx) - } else { - Btn::text_fg("Randomly choose upzones").build_def(ctx, None) - }, + Widget::row(vec![ + if num_picked == app.session.upzones_unlocked { + Btn::text_fg("Randomly choose upzones").inactive(ctx) + } else { + Btn::text_fg("Randomly choose upzones").build_def(ctx, None) + }, + if num_picked == 0 { + Btn::text_fg("Clear upzones").inactive(ctx) + } else { + Btn::text_fg("Clear upzones").build_def(ctx, None) + } + .align_right(), + ]), if num_picked == app.session.upzones_unlocked { Btn::text_bg2("Start game").build_def(ctx, Key::Enter) } else { diff --git a/santa/src/session.rs b/santa/src/session.rs index ecd8554316..efc5ae0938 100644 --- a/santa/src/session.rs +++ b/santa/src/session.rs @@ -2,7 +2,8 @@ use std::collections::{BTreeSet, HashMap}; use serde::{Deserialize, Serialize}; -use abstutil::Timer; +use abstutil::{deserialize_multimap, serialize_multimap, MultiMap, Timer}; +use map_model::BuildingID; use widgetry::{Color, EventCtx}; use crate::levels::Level; @@ -23,6 +24,14 @@ pub struct Session { pub vehicles_unlocked: BTreeSet, pub upzones_unlocked: usize, pub upzones_explained: bool, + // This was added after the main release, so keep old save files working by allowing it to be + // missing. + #[serde( + serialize_with = "serialize_multimap", + deserialize_with = "deserialize_multimap", + default + )] + pub upzones_per_level: MultiMap, #[serde(skip_serializing, skip_deserializing)] pub music: Music, @@ -84,6 +93,7 @@ impl Session { vehicles_unlocked: vec!["bike".to_string()].into_iter().collect(), upzones_unlocked: 0, upzones_explained: false, + upzones_per_level: MultiMap::new(), music: Music::empty(), play_music: true,