Add a 'blog' gameplay mode, which disables going back to the title screen, switching maps, etc. cyipt/actdev#66

This commit is contained in:
Dustin Carlino 2021-02-10 09:52:26 -08:00
parent 7c0bac236a
commit b38b7da8bb
3 changed files with 105 additions and 14 deletions

View File

@ -109,6 +109,7 @@ pub fn main() {
};
flags.sim_flags.load = name.path();
flags.study_area = Some(site);
mode = Some(sandbox::GameplayMode::Blog(name));
}
args.done();
@ -143,7 +144,11 @@ fn setup_app(
// usually time is midnight, so save some effort and start with the correct color scheme. If
// we're loading a savestate and it's actually daytime, we'll pay a small penalty to switch
// colors.
if maybe_mode.is_some() {
if let Some(GameplayMode::PlayScenario(_, _, _))
| Some(GameplayMode::FixTrafficSignals)
| Some(GameplayMode::OptimizeCommute(_, _))
| Some(GameplayMode::Tutorial(_)) = maybe_mode
{
opts.color_scheme = map_gui::colors::ColorSchemeChoice::NightMode;
}
let cs = map_gui::colors::ColorScheme::new(ctx, opts.color_scheme);
@ -273,10 +278,23 @@ fn finish_app_setup(
crate::sandbox::gameplay::Tutorial::initialize(ctx, app);
}
let start_daytime = Box::new(|ctx: &mut EventCtx, app: &mut App| {
ctx.loading_screen("start in the daytime", |_, mut timer| {
app.primary
.sim
.timed_step(&app.primary.map, Duration::hours(6), &mut None, &mut timer);
});
vec![Transition::Keep]
});
let states: Vec<Box<dyn State<App>>> = if title {
vec![Box::new(TitleScreen::new(ctx, app))]
} else if let Some(mode) = maybe_mode {
vec![SandboxMode::simple_new(ctx, app, mode)]
if let GameplayMode::Blog(_) = mode {
vec![SandboxMode::async_new(ctx, app, mode, start_daytime)]
} else {
vec![SandboxMode::simple_new(ctx, app, mode)]
}
} else {
// We got here by just passing --dev and a map as flags; we're just looking at an empty
// map. Start in the daytime.
@ -284,17 +302,7 @@ fn finish_app_setup(
ctx,
app,
GameplayMode::Freeform(app.primary.map.get_name().clone()),
Box::new(|ctx, app| {
ctx.loading_screen("start in the daytime", |_, mut timer| {
app.primary.sim.timed_step(
&app.primary.map,
Duration::hours(6),
&mut None,
&mut timer,
);
});
vec![Transition::Keep]
}),
start_daytime,
)]
};
if let Some(ss) = savestate {

View File

@ -0,0 +1,78 @@
use map_gui::tools::nice_map_name;
use widgetry::{
lctrl, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, StyledButtons,
VerticalAlignment, Widget,
};
use crate::app::{App, Transition};
use crate::edit::EditMode;
use crate::sandbox::gameplay::freeform::ChangeScenario;
use crate::sandbox::gameplay::{GameplayMode, GameplayState};
use crate::sandbox::{Actions, SandboxControls};
pub struct Blog {
top_center: Panel,
}
impl Blog {
pub fn new(ctx: &mut EventCtx) -> Box<dyn GameplayState> {
Box::new(Blog {
top_center: Panel::empty(ctx),
})
}
}
impl GameplayState for Blog {
fn event(
&mut self,
ctx: &mut EventCtx,
app: &mut App,
_: &mut SandboxControls,
_: &mut Actions,
) -> Option<Transition> {
match self.top_center.event(ctx) {
Outcome::Clicked(x) => match x.as_ref() {
// TODO This'll bring us out of this GameplayMode.
"change scenario" => Some(Transition::Push(ChangeScenario::new(ctx, app, "none"))),
"edit map" => Some(Transition::Push(EditMode::new(
ctx,
app,
GameplayMode::Freeform(app.primary.map.get_name().clone()),
))),
_ => unreachable!(),
},
_ => None,
}
}
fn draw(&self, g: &mut GfxCtx, _: &App) {
self.top_center.draw(g);
}
fn recreate_panels(&mut self, ctx: &mut EventCtx, app: &App) {
let row = Widget::row(vec![
Line(nice_map_name(app.primary.map.get_name()))
.small_heading()
.draw(ctx),
Widget::vert_separator(ctx, 50.0),
ctx.style()
.btn_light_popup_icon_text("system/assets/tools/calendar.svg", "none")
.hotkey(Key::S)
.build_widget(ctx, "change scenario"),
ctx.style()
.btn_outline_light_icon_text("system/assets/tools/pencil.svg", "Edit map")
.hotkey(lctrl(Key::E))
.build_widget(ctx, "edit map"),
])
.centered();
self.top_center = Panel::new(row)
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
.build(ctx);
}
fn has_tool_panel(&self) -> bool {
// Get rid of the home button, which would allow escaping to the title screen
false
}
}

View File

@ -24,6 +24,7 @@ use crate::pregame::MainMenu;
use crate::sandbox::{Actions, SandboxControls, SandboxMode};
// TODO pub so challenges can grab cutscenes and SandboxMode can dispatch to actions. Weird?
mod blog;
pub mod commute;
pub mod fix_traffic_signals;
pub mod freeform;
@ -38,6 +39,7 @@ pub enum GameplayMode {
PlayScenario(MapName, String, Vec<ScenarioModifier>),
FixTrafficSignals,
OptimizeCommute(OrigPersonID, Duration),
Blog(MapName),
// current
Tutorial(TutorialPointer),
@ -102,13 +104,15 @@ impl GameplayMode {
GameplayMode::FixTrafficSignals => MapName::seattle("downtown"),
GameplayMode::OptimizeCommute(_, _) => MapName::seattle("montlake"),
GameplayMode::Tutorial(_) => MapName::seattle("montlake"),
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 {
GameplayMode::Freeform(_) => {
// TODO Start with a scenario in blog mode, once all the actdev scenarios are imported.
GameplayMode::Freeform(_) | GameplayMode::Blog(_) => {
let mut s = Scenario::empty(map, "empty");
s.only_seed_buses = None;
return LoadScenario::Scenario(s);
@ -214,6 +218,7 @@ impl GameplayMode {
commute::OptimizeCommute::new(ctx, app, *p, *goal)
}
GameplayMode::Tutorial(current) => Tutorial::make_gameplay(ctx, app, *current),
GameplayMode::Blog(_) => blog::Blog::new(ctx),
}
}
}