diff --git a/main_game/assets/maps/building1_player_floor.ron b/main_game/assets/maps/building1_player_floor.ron index 85d98fe8..1cac84c3 100644 --- a/main_game/assets/maps/building1_player_floor.ron +++ b/main_game/assets/maps/building1_player_floor.ron @@ -1,6 +1,6 @@ ( zones: ( - inner: {Zone(Bed): (zone_group: (6), zone_size: 30, zone_successors: [Zone(PlayerApartment)]), Zone(BottomLeftApartmentBathroomDoor): (zone_group: (7), zone_size: 42, zone_successors: [Zone(BottomLeftApartment)]), Zone(BottomLeftApartmentDoor): (zone_group: (7), zone_size: 37, zone_successors: [Zone(BottomLeftApartment), Zone(Hallway)]), Zone(BottomLeftApartment): (zone_group: (7), zone_size: 2187, zone_successors: [Zone(BottomLeftApartmentBathroomDoor), Zone(BottomLeftApartmentDoor), Zone(BottomRightApartment), Zone(Hallway)]), Zone(BottomRightApartmentDoor): (zone_group: (7), zone_size: 35, zone_successors: [Zone(BottomRightApartment), Zone(Hallway)]), Zone(BottomRightApartment): (zone_group: (7), zone_size: 1050, zone_successors: [Zone(BottomLeftApartment), Zone(BottomRightApartmentDoor), Zone(Hallway)]), Zone(Elevator): (zone_group: (7), zone_size: 68, zone_successors: [Zone(Hallway)]), Zone(Hallway): (zone_group: (6), zone_size: 1550, zone_successors: [Zone(BottomLeftApartmentDoor), Zone(BottomLeftApartment), Zone(BottomRightApartmentDoor), Zone(BottomRightApartment), Zone(Elevator), Zone(PlayerApartment), Zone(PlayerDoor)]), Zone(Meditation): (zone_group: (6), zone_size: 125, zone_successors: [Zone(PlayerApartment)]), Zone(PlayerApartment): (zone_group: (6), zone_size: 2725, zone_successors: [Zone(Bed), Zone(Hallway), Zone(Meditation), Zone(PlayerDoor), Zone(Tea)]), Zone(PlayerDoor): (zone_group: (6), zone_size: 64, zone_successors: [Zone(Hallway), Zone(PlayerApartment)]), Zone(Tea): (zone_group: (6), zone_size: 45, zone_successors: [Zone(PlayerApartment)])}, + inner: {Zone(Bed): (zone_group: (5), zone_size: 30, zone_successors: [Zone(PlayerApartment)]), Zone(BottomLeftApartmentBathroomDoor): (zone_group: (6), zone_size: 42, zone_successors: [Zone(BottomLeftApartment)]), Zone(BottomLeftApartmentDoor): (zone_group: (6), zone_size: 37, zone_successors: [Zone(BottomLeftApartment), Zone(Hallway)]), Zone(BottomLeftApartment): (zone_group: (6), zone_size: 2187, zone_successors: [Zone(BottomLeftApartmentBathroomDoor), Zone(BottomLeftApartmentDoor), Zone(BottomRightApartment), Zone(Hallway)]), Zone(BottomRightApartmentDoor): (zone_group: (6), zone_size: 35, zone_successors: [Zone(BottomRightApartment), Zone(Hallway)]), Zone(BottomRightApartment): (zone_group: (6), zone_size: 1050, zone_successors: [Zone(BottomLeftApartment), Zone(BottomRightApartmentDoor), Zone(Hallway)]), Zone(Elevator): (zone_group: (6), zone_size: 68, zone_successors: [Zone(Hallway)]), Zone(Hallway): (zone_group: (5), zone_size: 1550, zone_successors: [Zone(BottomLeftApartmentDoor), Zone(BottomLeftApartment), Zone(BottomRightApartmentDoor), Zone(BottomRightApartment), Zone(Elevator), Zone(PlayerApartment), Zone(PlayerDoor)]), Zone(Meditation): (zone_group: (5), zone_size: 125, zone_successors: [Zone(PlayerApartment)]), Zone(PlayerApartment): (zone_group: (5), zone_size: 2725, zone_successors: [Zone(Bed), Zone(Hallway), Zone(Meditation), Zone(PlayerDoor), Zone(Tea)]), Zone(PlayerDoor): (zone_group: (5), zone_size: 64, zone_successors: [Zone(Hallway), Zone(PlayerApartment)]), Zone(Tea): (zone_group: (5), zone_size: 45, zone_successors: [Zone(PlayerApartment)])}, ), squares: { (x: -81, y: -59): [Wall, Empty, Zone(BottomLeftApartment)], diff --git a/main_game/src/new_game.rs b/main_game/src/new_game.rs index 80768186..7adeef98 100644 --- a/main_game/src/new_game.rs +++ b/main_game/src/new_game.rs @@ -4,7 +4,10 @@ use bevy::{ }; use common_store::{DialogStore, GlobalStore}; use common_story::Character; -use main_game_lib::{dialog, state::GlobalGameState}; +use main_game_lib::{ + dialog, + state::{GlobalGameState, WhichTopDownScene}, +}; pub(crate) fn on_enter( mut next_state: ResMut>, @@ -37,5 +40,5 @@ pub(crate) fn on_enter( dialog::TypedNamespace::InitialPhoebe, ); - next_state.set(GlobalGameState::LoadingBuilding1PlayerFloor); + next_state.set(WhichTopDownScene::Building1PlayerFloor.loading()); } diff --git a/main_game_lib/src/cutscene/enter_an_elevator.rs b/main_game_lib/src/cutscene/enter_an_elevator.rs index 805179c2..ce677b65 100644 --- a/main_game_lib/src/cutscene/enter_an_elevator.rs +++ b/main_game_lib/src/cutscene/enter_an_elevator.rs @@ -240,17 +240,16 @@ pub fn spawn( fn on_took_the_elevator(cmd: &mut Commands, store: &GlobalStore) { // get current state, from that infer quitting state cmd.add(|w: &mut World| { - let quitting_state = w - .get_resource::>() - .unwrap() // SAFETY: always present - .state_semantics() - .unwrap() // SAFETY: used in topdown scenes - .quitting; + let current_top_down_scene = **w + .get_resource::>() + .expect("Elevator can only be used in top down scenes"); // SAFETY: always present let mut next_state = w.get_resource_mut::>().unwrap(); - next_state.set(quitting_state); + next_state.set(GlobalGameState::LeavingTopDownScene( + current_top_down_scene, + )); }); match store @@ -307,11 +306,8 @@ pub fn start_with_open_elevator_and_close_it( elevator.get_mut::().unwrap().index = last_frame; // start the animation as soon as we are in running state fn is_in_running_global_state(w: &World, _: Entity) -> bool { - // SAFETY: GlobalGameState always present - let current_state = w.get_resource::>().unwrap(); - current_state - .state_semantics() - .is_some_and(|sem| sem.running == **current_state) + w.get_resource::>() + .is_some_and(|scene| scene.is_running()) } elevator.insert(common_visuals::BeginAtlasAnimation::run( is_in_running_global_state, diff --git a/main_game_lib/src/lib.rs b/main_game_lib/src/lib.rs index 3be14f99..e498a182 100644 --- a/main_game_lib/src/lib.rs +++ b/main_game_lib/src/lib.rs @@ -72,10 +72,12 @@ pub fn windowed_app() -> App { info!("Initializing Don't Count The Sheep"); app.init_state::() + .add_computed_state::() + .add_computed_state::() + .init_resource::() // TODO: load from save file .init_resource::() .insert_resource(ClearColor(PRIMARY_COLOR)) - .init_resource::() .init_asset::() .init_asset_loader::() .init_asset_loader::(); diff --git a/main_game_lib/src/state.rs b/main_game_lib/src/state.rs index bb8a0726..1a702321 100644 --- a/main_game_lib/src/state.rs +++ b/main_game_lib/src/state.rs @@ -26,43 +26,6 @@ pub enum GlobalGameState { RunningTopDownScene(WhichTopDownScene), LeavingTopDownScene(WhichTopDownScene), - /// Sets up the floor with player's first apartment - LoadingBuilding1PlayerFloor, - AtBuilding1PlayerFloor, - QuittingBuilding1PlayerFloor, - - LoadingBuilding1Basement1, - AtBuilding1Basement1, - QuittingBuilding1Basement1, - - LoadingBuilding1Basement2, - AtBuilding1Basement2, - QuittingBuilding1Basement2, - - LoadingClinic, - AtClinic, - QuittingClinic, - - LoadingClinicWard, - AtClinicWard, - QuittingClinicWard, - - LoadingPlantShop, - AtPlantShop, - QuittingPlantShop, - - LoadingSewers, - AtSewers, - QuittingSewers, - - LoadingTwinpeaksApartment, - AtTwinpeaksApartment, - QuittingTwinpeaksApartment, - - LoadingMall, - AtMall, - QuittingMall, - /// Change the game state to this state to run systems that setup the /// meditation game in the background. /// Nothing is shown to the player yet. @@ -76,18 +39,6 @@ pub enum GlobalGameState { /// meditation game in the background. QuittingMeditation, - LoadingDowntown, - AtDowntown, - QuittingDowntown, - - LoadingCompound, - AtCompound, - QuittingCompound, - - LoadingCompoundTower, - AtCompoundTower, - QuittingCompoundTower, - /// Performs all necessary cleanup and exits the game. Exit, } @@ -95,11 +46,11 @@ pub enum GlobalGameState { /// Will be present as a resource if the game is in any top-down scene which /// is our 2D game's most ubiquitous scene kind. /// We use [`ComputedStates`] for this. -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct InTopDownScene(TopDownSceneState); +#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)] +pub struct InTopDownScene(pub TopDownSceneState); /// What is the current state of the top-down scene? -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)] pub enum TopDownSceneState { /// Scene is being prepared. /// This entails loading assets and setting up the scene. @@ -195,20 +146,6 @@ pub enum GlobalGameStateTransition { DowntownToClinicWard, } -/// Typical scene has several states with standard semantics. -pub struct StandardStateSemantics { - /// The state when the scene is loading. - /// Setups up resources. - pub loading: GlobalGameState, - /// The state when the scene is running. - pub running: GlobalGameState, - /// The state when the scene is quitting. - /// Cleans up resources. - pub quitting: GlobalGameState, - /// Some scenes have a paused state. - pub paused: Option, -} - /// Helper params that are used in transitions. /// Use [`TransitionParams::begin`] to start a transition. #[derive(SystemParam)] @@ -223,157 +160,50 @@ pub struct TransitionParams<'w, 's> { pub next_loading_screen_state: ResMut<'w, NextState>, } -/// Typical scene has several states with standard semantics. -pub trait WithStandardStateSemantics { - /// The state when the scene is loading. - fn loading() -> GlobalGameState; - /// The state when the scene is running. - fn running() -> GlobalGameState; - /// The state when the scene is quitting. - fn quitting() -> GlobalGameState; - - /// Some scenes have a paused state. - fn paused() -> Option { - None - } - - /// Converts these methods into a struct - fn semantics() -> StandardStateSemantics { - StandardStateSemantics { - loading: Self::loading(), - running: Self::running(), - quitting: Self::quitting(), - paused: Self::paused(), - } - } - - /// Helper to check if the state is in the loading state. - fn in_loading_state( - ) -> impl FnMut(Option>>) -> bool + Clone { - in_state(Self::loading()) - } - - /// Helper to check if the state is in the running state. - fn in_running_state( - ) -> impl FnMut(Option>>) -> bool + Clone { - in_state(Self::running()) - } - - /// Helper to check if the state is in the quitting state. - fn in_quitting_state( - ) -> impl FnMut(Option>>) -> bool + Clone { - in_state(Self::quitting()) - } +/// Helper to check if the state is in specific top down scene loading state. +pub fn in_scene_loading_state( + scene: WhichTopDownScene, +) -> impl FnMut(Option>>) -> bool + Clone { + in_state(GlobalGameState::LoadingTopDownScene(scene)) } -impl GlobalGameState { - /// Many scenes have a standard state semantics: loading, running, quitting - /// and paused. - pub fn state_semantics(self) -> Option { - use GlobalGameState::*; - - let (loading, running, quitting, paused) = match self { - LoadingBuilding1PlayerFloor - | AtBuilding1PlayerFloor - | QuittingBuilding1PlayerFloor => ( - LoadingBuilding1PlayerFloor, - AtBuilding1PlayerFloor, - QuittingBuilding1PlayerFloor, - None, - ), - - LoadingMall | AtMall | QuittingMall => { - (LoadingMall, AtMall, QuittingMall, None) - } - - LoadingBuilding1Basement1 - | AtBuilding1Basement1 - | QuittingBuilding1Basement1 => ( - LoadingBuilding1Basement1, - AtBuilding1Basement1, - QuittingBuilding1Basement1, - None, - ), - - LoadingBuilding1Basement2 - | AtBuilding1Basement2 - | QuittingBuilding1Basement2 => ( - LoadingBuilding1Basement2, - AtBuilding1Basement2, - QuittingBuilding1Basement2, - None, - ), - - LoadingClinic | AtClinic | QuittingClinic => { - (LoadingClinic, AtClinic, QuittingClinic, None) - } - - LoadingClinicWard | AtClinicWard | QuittingClinicWard => { - (LoadingClinicWard, AtClinicWard, QuittingClinicWard, None) - } - - LoadingPlantShop | AtPlantShop | QuittingPlantShop => { - (LoadingPlantShop, AtPlantShop, QuittingPlantShop, None) - } +/// Helper to check if the state is in specific top down scene running state. +pub fn in_scene_running_state( + scene: WhichTopDownScene, +) -> impl FnMut(Option>>) -> bool + Clone { + in_state(GlobalGameState::RunningTopDownScene(scene)) +} - LoadingSewers | AtSewers | QuittingSewers => { - (LoadingSewers, AtSewers, QuittingSewers, None) - } +/// Helper to check if the state is in specific top down scene leaving state. +pub fn in_scene_leaving_state( + scene: WhichTopDownScene, +) -> impl FnMut(Option>>) -> bool + Clone { + in_state(GlobalGameState::LeavingTopDownScene(scene)) +} - LoadingTwinpeaksApartment - | AtTwinpeaksApartment - | QuittingTwinpeaksApartment => ( - LoadingTwinpeaksApartment, - AtTwinpeaksApartment, - QuittingTwinpeaksApartment, - None, - ), - - LoadingMeditation | InGameMeditation | MeditationInMenu - | QuittingMeditation => ( - LoadingMeditation, - InGameMeditation, - QuittingMeditation, - Some(MeditationInMenu), - ), - - LoadingDowntown | AtDowntown | QuittingDowntown => { - (LoadingDowntown, AtDowntown, QuittingDowntown, None) - } +/// Helper to check if the state is in _any_ top down scene loading state. +pub fn in_top_down_loading_state( +) -> impl FnMut(Option>>) -> bool + Clone { + in_state(InTopDownScene(TopDownSceneState::Loading)) +} - LoadingCompound | AtCompound | QuittingCompound => { - (LoadingCompound, AtCompound, QuittingCompound, None) - } +/// Helper to check if the state is in _any_ top down scene running state. +pub fn in_top_down_running_state( +) -> impl FnMut(Option>>) -> bool + Clone { + in_state(InTopDownScene(TopDownSceneState::Running)) +} - LoadingCompoundTower | AtCompoundTower | QuittingCompoundTower => ( - LoadingCompoundTower, - AtCompoundTower, - QuittingCompoundTower, - None, - ), - - LoadingTopDownScene(_) - | RunningTopDownScene(_) - | LeavingTopDownScene(_) => { - // TODO - return None; - } - Blank | Exit | NewGame => return None, - }; - - Some(StandardStateSemantics { - loading, - running, - quitting, - paused, - }) - } +/// Helper to check if the state is in _any_ top down scene leaving state. +pub fn in_top_down_leaving_state( +) -> impl FnMut(Option>>) -> bool + Clone { + in_state(InTopDownScene(TopDownSceneState::Leaving)) } impl GlobalGameStateTransition { /// We expect the transition to start at this state. pub fn from_state(self) -> GlobalGameState { use GlobalGameStateTransition::*; + use WhichTopDownScene::*; match self { BlankToNewGame => GlobalGameState::Blank, @@ -385,17 +215,11 @@ impl GlobalGameStateTransition { Building1PlayerFloorToMeditation | Building1PlayerFloorToBuilding1Basement1 | Sleeping - | Building1PlayerFloorToDowntown => { - GlobalGameState::QuittingBuilding1PlayerFloor - } + | Building1PlayerFloorToDowntown => Building1PlayerFloor.leaving(), Building1Basement1ToBasement2 | Building1Basement1ToPlayerFloor - | Building1Basement1ToDowntown => { - GlobalGameState::QuittingBuilding1Basement1 - } - Building1Basement2ToBasement1 => { - GlobalGameState::QuittingBuilding1Basement2 - } + | Building1Basement1ToDowntown => Building1Basement1.leaving(), + Building1Basement2ToBasement1 => Building1Basement2.leaving(), DowntownToBuilding1PlayerFloor | DowntownToClinic | DowntownToClinicWard @@ -403,18 +227,16 @@ impl GlobalGameStateTransition { | DowntownToMall | DowntownToPlantShop | DowntownToSewers - | DowntownToTwinpeaksApartment => GlobalGameState::QuittingDowntown, - ClinicToDowntown => GlobalGameState::QuittingClinic, - ClinicWardToDowntown => GlobalGameState::QuittingClinicWard, - PlantShopToDowntown => GlobalGameState::QuittingPlantShop, - SewersToDowntown => GlobalGameState::QuittingSewers, - CompoundToDowntown => GlobalGameState::QuittingCompound, - CompoundToTower => GlobalGameState::QuittingCompound, - TwinpeaksApartmentToDowntown => { - GlobalGameState::QuittingTwinpeaksApartment - } - MallToDowntown => GlobalGameState::QuittingMall, - TowerToCompound => GlobalGameState::QuittingCompoundTower, + | DowntownToTwinpeaksApartment => Downtown.leaving(), + ClinicToDowntown => Clinic.leaving(), + ClinicWardToDowntown => ClinicWard.leaving(), + PlantShopToDowntown => PlantShop.leaving(), + SewersToDowntown => Sewers.leaving(), + CompoundToDowntown => Compound.leaving(), + CompoundToTower => Compound.leaving(), + TwinpeaksApartmentToDowntown => TwinpeaksApartment.leaving(), + MallToDowntown => Mall.leaving(), + TowerToCompound => CompoundTower.leaving(), } } } @@ -479,3 +301,27 @@ impl ComputedStates for WhichTopDownScene { } } } + +impl InTopDownScene { + /// Is the scene in the [`TopDownSceneState::Running`] state? + pub fn is_running(self) -> bool { + matches!(self.0, TopDownSceneState::Running) + } +} + +impl WhichTopDownScene { + /// Instance of the scene in the loading state. + pub fn loading(self) -> GlobalGameState { + GlobalGameState::LoadingTopDownScene(self) + } + + /// Instance of the scene in the running state. + pub fn running(self) -> GlobalGameState { + GlobalGameState::RunningTopDownScene(self) + } + + /// Instance of the scene in the leaving state. + pub fn leaving(self) -> GlobalGameState { + GlobalGameState::LeavingTopDownScene(self) + } +} diff --git a/main_game_lib/src/top_down.rs b/main_game_lib/src/top_down.rs index 45717bc4..af8ffac5 100644 --- a/main_game_lib/src/top_down.rs +++ b/main_game_lib/src/top_down.rs @@ -28,9 +28,10 @@ use leafwing_input_manager::plugin::InputManagerSystem; use self::inspect_and_interact::ChangeHighlightedInspectLabelEvent; use crate::{ - cutscene::in_cutscene, + cutscene::in_cutscene, in_scene_loading_state, in_scene_running_state, + in_top_down_running_state, top_down::inspect_and_interact::ChangeHighlightedInspectLabelEventConsumer, - StandardStateSemantics, WithStandardStateSemantics, + InTopDownScene, TopDownSceneState, WhichTopDownScene, }; /// Does not add any systems, only registers generic-less types. @@ -40,7 +41,109 @@ impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_event::() .add_event::() - .add_event::(); + .add_event::() + .add_event::(); + + // + // Assets + // + + app.add_systems( + OnEnter(InTopDownScene(TopDownSceneState::Loading)), + common_assets::store::insert_as_resource::, + ) + .add_systems( + OnExit(InTopDownScene(TopDownSceneState::Leaving)), + common_assets::store::remove_as_resource::, + ); + + // + // Camera + // + + app.add_systems( + OnEnter(InTopDownScene(TopDownSceneState::Loading)), + common_visuals::camera::spawn, + ) + .add_systems( + OnExit(InTopDownScene(TopDownSceneState::Leaving)), + common_visuals::camera::despawn, + ); + + // + // Inspect and interact systems + // + + app.add_systems( + Update, + ( + inspect_and_interact::highlight_what_would_be_interacted_with, + inspect_and_interact::change_highlighted_label + .in_set(ChangeHighlightedInspectLabelEventConsumer) + .run_if(on_event::()), + inspect_and_interact::show_all_in_vicinity + .run_if(common_action::inspect_pressed()), + ) + .chain() // easier to reason about + .run_if(in_top_down_running_state()), + ) + .add_systems( + Update, + inspect_and_interact::schedule_hide_all + .run_if(in_top_down_running_state()) + .run_if(common_action::inspect_just_released()), + ); + app.add_systems( + PreUpdate, + inspect_and_interact::interact + .run_if(in_top_down_running_state()) + .run_if(common_action::interaction_just_pressed()) + // Without this condition, the dialog will start when the player + // exists the previous one because: + // 1. The interact system runs, interact is just pressed, and so + // emits the event. + // 2. Player finishes the dialog by pressing interaction. This + // consumes the interact action. + // 3. Consuming the action did fuck all because the event was + // already emitted earlier. Since the commands to remove the + // dialog resource were applied, the condition to not run the + // begin_dialog system will not prevent rerun + .run_if(not(crate::dialog::fe::portrait::in_portrait_dialog())) + .after(InputManagerSystem::Update), + ) + .add_systems( + Update, + ( + actor::npc::mark_nearby_as_ready_for_interaction, + actor::npc::begin_dialog + .run_if(on_event::()) + .run_if(not( + crate::dialog::fe::portrait::in_portrait_dialog(), + )), + ) + .run_if(in_top_down_running_state()), + ); + + // + // HUD + // + + app.add_systems( + OnEnter(InTopDownScene(TopDownSceneState::Running)), + (crate::hud::daybar::spawn, crate::hud::notification::spawn), + ) + .add_systems( + OnExit(InTopDownScene(TopDownSceneState::Running)), + ( + crate::hud::daybar::despawn, + crate::hud::notification::despawn, + ), + ) + .add_systems( + Update, + (crate::hud::notification::update) + .run_if(in_top_down_running_state()), + ); #[cfg(feature = "devtools")] { @@ -69,168 +172,82 @@ impl bevy::app::Plugin for Plugin { /// Registers unique `T` types, asset loader for the map RON file, and systems /// including from other packages: -/// - [`common_assets::store::insert_as_resource`] -/// - [`common_assets::store::remove_as_resource`] /// - [`crate::top_down::actor::animate_movement`] /// - [`crate::top_down::actor::emit_movement_events`] /// - [`crate::top_down::actor::npc::drive_behavior`] /// - [`crate::top_down::actor::npc::plan_path`] /// - [`crate::top_down::actor::npc::run_path`] /// - [`crate::top_down::actor::player::move_around`] -pub fn default_setup_for_scene(app: &mut App) +pub fn default_setup_for_scene(app: &mut App, scene: WhichTopDownScene) where - T: TopDownScene + WithStandardStateSemantics, + T: TopDownScene, { - debug!("Adding assets for {}", T::type_path()); - - let StandardStateSemantics { - running, - loading, - quitting, - .. - } = T::semantics(); - - app.add_systems( - OnEnter(loading), - common_assets::store::insert_as_resource::, - ) - .add_systems( - OnExit(quitting), - common_assets::store::remove_as_resource::, - ); - debug!("Adding map layout for {}", T::type_path()); - app.add_event::() - .init_asset_loader::>>() + app.init_asset_loader::>>() .init_asset::>(); - app.add_systems(OnEnter(loading), layout::systems::start_loading_map::) - .add_systems( - First, - layout::systems::try_insert_map_as_resource:: - .run_if(in_state(loading)), - ) - .add_systems( - FixedUpdate, - actor::animate_movement::.run_if(in_state(running)), - ) - .add_systems( - Update, - actor::emit_movement_events:: - .run_if(in_state(running)) - // so that we can emit this event on current frame - .after(actor::player::move_around::), - ) - .add_systems( - Update, - actor::player::move_around:: - .run_if(in_state(running)) - .run_if(common_action::move_action_pressed()) - .run_if(not(crate::dialog::fe::portrait::in_portrait_dialog())), - ) - .add_systems( - Update, - ( - actor::npc::drive_behavior, - actor::npc::plan_path:: - .run_if(on_event::()), - actor::npc::run_path::, - ) - .chain() - .run_if(in_state(running)), - ) - .add_systems(OnExit(running), layout::systems::remove_resources::); - - debug!("Adding inspect ability for {}", T::type_path()); - app.add_systems( + OnEnter(scene.loading()), + layout::systems::start_loading_map::, + ) + .add_systems( + First, + layout::systems::try_insert_map_as_resource:: + .run_if(in_scene_loading_state(scene)), + ) + .add_systems( + FixedUpdate, + actor::animate_movement::.run_if(in_scene_running_state(scene)), + ) + .add_systems( Update, - ( - inspect_and_interact::highlight_what_would_be_interacted_with, - inspect_and_interact::change_highlighted_label - .in_set(ChangeHighlightedInspectLabelEventConsumer) - .run_if(on_event::()), - inspect_and_interact::show_all_in_vicinity - .run_if(common_action::inspect_pressed()), - ) - .chain() // easier to reason about - .run_if(in_state(running)), + actor::emit_movement_events:: + .run_if(in_scene_running_state(scene)) + // so that we can emit this event on current frame + .after(actor::player::move_around::), ) .add_systems( Update, - inspect_and_interact::schedule_hide_all - .run_if(in_state(running)) - .run_if(common_action::inspect_just_released()), - ); - - debug!("Adding interaction systems for {}", T::type_path()); - - app.add_systems( - PreUpdate, - inspect_and_interact::interact - .run_if(in_state(running)) - .run_if(common_action::interaction_just_pressed()) - // Without this condition, the dialog will start when the player - // exists the previous one because: - // 1. The interact system runs, interact is just pressed, and so - // emits the event. - // 2. Player finishes the dialog by pressing interaction. This - // consumes the interact action. - // 3. Consuming the action did fuck all because the event was - // already emitted earlier. Since the commands to remove the - // dialog resource were applied, the condition to not run the - // begin_dialog system will not prevent rerun - .run_if(not(crate::dialog::fe::portrait::in_portrait_dialog())) - .after(InputManagerSystem::Update), + actor::player::move_around:: + .run_if(in_scene_running_state(scene)) + .run_if(common_action::move_action_pressed()) + .run_if(not(crate::dialog::fe::portrait::in_portrait_dialog())), ) .add_systems( Update, ( - actor::npc::mark_nearby_as_ready_for_interaction, - actor::npc::begin_dialog - .run_if(on_event::()) - .run_if(not(crate::dialog::fe::portrait::in_portrait_dialog())), + actor::npc::drive_behavior, + actor::npc::plan_path:: + .run_if(on_event::()), + actor::npc::run_path::, ) - .run_if(in_state(running)), + .chain() + .run_if(in_scene_running_state(scene)), ) .add_systems( + OnExit(scene.running()), + layout::systems::remove_resources::, + ); + + debug!("Adding interaction systems for {}", T::type_path()); + app.add_systems( Update, inspect_and_interact::match_interact_label_with_action_event - .run_if(in_state(running)) + .run_if(in_scene_running_state(scene)) .run_if(on_event::()) .after(emit_movement_events::), ); debug!("Adding camera"); - app.add_systems(OnEnter(loading), common_visuals::camera::spawn) - .add_systems(OnExit(quitting), common_visuals::camera::despawn) - .add_systems( - FixedUpdate, - cameras::track_player_with_main_camera - .after(actor::animate_movement::) - .run_if(in_state(running)) - .run_if(not(in_cutscene())) - .run_if(not(crate::dialog::fe::portrait::in_portrait_dialog())), - ); - - debug!("Adding HUD"); - app.add_systems( - OnEnter(running), - (crate::hud::daybar::spawn, crate::hud::notification::spawn), - ) - .add_systems( - OnExit(running), - ( - crate::hud::daybar::despawn, - crate::hud::notification::despawn, - ), - ) - .add_systems( - Update, - (crate::hud::notification::update).run_if(in_state(running)), + FixedUpdate, + cameras::track_player_with_main_camera + .after(actor::animate_movement::) + .run_if(in_scene_running_state(scene)) + .run_if(not(in_cutscene())) + .run_if(not(crate::dialog::fe::portrait::in_portrait_dialog())), ); } @@ -239,24 +256,20 @@ where /// We draw an overlay with tiles that you can edit with left and right mouse /// buttons. #[cfg(feature = "devtools")] -pub fn dev_default_setup_for_scene(app: &mut App) +pub fn dev_default_setup_for_scene(app: &mut App, scene: WhichTopDownScene) where - T: TopDownScene + WithStandardStateSemantics, + T: TopDownScene, { - let StandardStateSemantics { - running, quitting, .. - } = T::semantics(); - app.register_type::>(); app.add_systems( - OnEnter(running), + OnEnter(scene.running()), layout::map_maker::spawn_debug_grid_root::, ) .add_systems( Update, layout::map_maker::show_tiles_around_cursor:: - .run_if(in_state(running)), + .run_if(in_scene_running_state(scene)), ) .add_systems( Update, @@ -265,8 +278,8 @@ where layout::map_maker::recolor_squares::, layout::map_maker::update_ui::, ) - .run_if(in_state(running)) + .run_if(in_scene_running_state(scene)) .chain(), ) - .add_systems(OnExit(quitting), layout::map_maker::destroy_map::); + .add_systems(OnExit(scene.leaving()), layout::map_maker::destroy_map::); } diff --git a/main_game_lib/src/top_down/layout/build_pathfinding_graph.rs b/main_game_lib/src/top_down/layout/build_pathfinding_graph.rs index 30326199..dee5dcc7 100644 --- a/main_game_lib/src/top_down/layout/build_pathfinding_graph.rs +++ b/main_game_lib/src/top_down/layout/build_pathfinding_graph.rs @@ -180,7 +180,7 @@ impl ZoneTileKindGraph { // are in the same group. // the index is going to be the zone group unique value in the end - let mut zone_groups: Vec> = default(); + let mut zone_groups: Vec> = default(); let mut successors: HashMap> = default(); for zone in TileKind::zones_iter() { diff --git a/main_game_lib/src/top_down/layout/systems.rs b/main_game_lib/src/top_down/layout/systems.rs index 7c7de932..bdb04598 100644 --- a/main_game_lib/src/top_down/layout/systems.rs +++ b/main_game_lib/src/top_down/layout/systems.rs @@ -3,7 +3,10 @@ use common_ext::QueryExt; #[cfg(feature = "devtools")] use crate::top_down::layout::map_maker; -use crate::top_down::{TileMap, TopDownScene}; +use crate::{ + top_down::{TileMap, TopDownScene}, + WhichTopDownScene, +}; /// Tells the game to start loading the map. /// We need to keep checking for this to be done by calling @@ -11,11 +14,13 @@ use crate::top_down::{TileMap, TopDownScene}; pub(crate) fn start_loading_map( mut cmd: Commands, assets: Res, + scene: Res>, ) { - let asset_path = format!("maps/{}.ron", T::name()); - debug!("Loading map {} from {}", T::type_path(), asset_path); + let scene_name = scene.snake_case(); + let asset_path = format!("maps/{scene_name}.ron"); + debug!("Loading map {scene_name} from {asset_path}"); let handle: Handle> = assets.load(asset_path); - cmd.spawn((Name::new(format!("TileMap<{}>", T::type_path())), handle)); + cmd.spawn((Name::new(format!("TileMap for {scene_name}")), handle)); } /// Run this to wait for the map to be loaded and insert it as a resource. diff --git a/scenes/building1_basement1/src/layout.rs b/scenes/building1_basement1/src/layout.rs index 49b7be09..ea1738ea 100644 --- a/scenes/building1_basement1/src/layout.rs +++ b/scenes/building1_basement1/src/layout.rs @@ -35,23 +35,23 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(Building1Basement1::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(Building1Basement1::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if( rscn::tscn_loaded_but_not_spawned::(), ), ) - .add_systems(OnExit(Building1Basement1::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, environmental_objects::door::toggle:: - .run_if(Building1Basement1::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(movement_event_emitted()) .after(actor::emit_movement_events::), ) @@ -61,7 +61,7 @@ impl bevy::app::Plugin for Plugin { .run_if(on_event_variant( Building1Basement1Action::EnterElevator, )) - .run_if(Building1Basement1::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ) .add_systems( @@ -70,13 +70,13 @@ impl bevy::app::Plugin for Plugin { .run_if(on_event_variant( Building1Basement1Action::EnterBasement2, )) - .run_if(Building1Basement1::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ) .add_systems( Update, watch_entry_to_apartment::system - .run_if(Building1Basement1::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(movement_event_emitted()) .after(actor::emit_movement_events::), ); @@ -307,7 +307,7 @@ fn enter_basement2( player, door: door.single(), door_entrance, - change_global_state_to: Building1Basement1::quitting(), + change_global_state_to: THIS_SCENE.leaving(), transition: GlobalGameStateTransition::Building1Basement1ToBasement2, loading_screen: LoadingScreenSettings { ..default() }, } diff --git a/scenes/building1_basement1/src/lib.rs b/scenes/building1_basement1/src/lib.rs index 77fbf388..c16b0c3d 100644 --- a/scenes/building1_basement1/src/lib.rs +++ b/scenes/building1_basement1/src/lib.rs @@ -23,20 +23,6 @@ impl TopDownScene for Building1Basement1 { } } -impl WithStandardStateSemantics for Building1Basement1 { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingBuilding1Basement1 - } - - fn running() -> GlobalGameState { - GlobalGameState::AtBuilding1Basement1 - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingBuilding1Basement1 - } -} - #[derive(Event, Reflect, Clone, strum::EnumString, Eq, PartialEq)] pub enum Building1Basement1Action { EnterElevator, @@ -44,14 +30,16 @@ pub enum Building1Basement1Action { } pub fn add(app: &mut App) { - info!("Adding {Building1Basement1:?} to app"); + info!("Adding {THIS_SCENE} to app"); app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::( + app, THIS_SCENE, + ); debug!("Adding plugins"); @@ -64,20 +52,20 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(Building1Basement1::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(|q: Query<(), With>| !q.is_empty()) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(Building1Basement1::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(Building1Basement1::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); @@ -86,10 +74,10 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(Building1Basement1::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); - info!("Added {Building1Basement1:?} to app"); + info!("Added {THIS_SCENE} to app"); } fn finish_when_everything_loaded( @@ -106,8 +94,8 @@ fn finish_when_everything_loaded( } fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {Building1Basement1:?}"); - next_state.set(Building1Basement1::running()); + info!("Entering {THIS_SCENE}"); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -115,7 +103,7 @@ fn exit( mut next_state: ResMut>, mut controls: ResMut>, ) { - info!("Leaving {Building1Basement1:?}"); + info!("Leaving {THIS_SCENE}"); // be a good guy and don't invade other game loops with "Enter" controls.consume(&GlobalAction::Interact); @@ -123,18 +111,16 @@ fn exit( use GlobalGameStateTransition::*; match *transition { Building1Basement1ToPlayerFloor => { - next_state.set(GlobalGameState::LoadingBuilding1PlayerFloor); + next_state.set(WhichTopDownScene::Building1PlayerFloor.loading()); } Building1Basement1ToDowntown => { - next_state.set(GlobalGameState::LoadingDowntown); + next_state.set(WhichTopDownScene::Downtown.loading()); } Building1Basement1ToBasement2 => { - next_state.set(GlobalGameState::LoadingBuilding1Basement2); + next_state.set(WhichTopDownScene::Building1Basement2.loading()); } _ => { - unreachable!( - "Invalid {Building1Basement1:?} transition {transition:?}" - ); + unreachable!("Invalid {THIS_SCENE} transition {transition:?}"); } } } diff --git a/scenes/building1_basement1/src/prelude.rs b/scenes/building1_basement1/src/prelude.rs index cd60c5e6..98936762 100644 --- a/scenes/building1_basement1/src/prelude.rs +++ b/scenes/building1_basement1/src/prelude.rs @@ -1,3 +1,6 @@ pub(crate) use main_game_lib::prelude::*; pub(crate) use crate::{Building1Basement1, Building1Basement1Action}; + +pub(crate) const THIS_SCENE: WhichTopDownScene = + WhichTopDownScene::Building1Basement1; diff --git a/scenes/building1_basement2/src/layout.rs b/scenes/building1_basement2/src/layout.rs index 6f12c178..452b0c5b 100644 --- a/scenes/building1_basement2/src/layout.rs +++ b/scenes/building1_basement2/src/layout.rs @@ -19,23 +19,23 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(Building1Basement2::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(Building1Basement2::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if( rscn::tscn_loaded_but_not_spawned::(), ), ) - .add_systems(OnExit(Building1Basement2::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, exit.run_if(on_event::()) - .run_if(Building1Basement2::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ); } @@ -180,7 +180,7 @@ fn exit( player, door: door.single(), door_entrance, - change_global_state_to: Building1Basement2::quitting(), + change_global_state_to: THIS_SCENE.leaving(), transition: GlobalGameStateTransition::Building1Basement2ToBasement1, loading_screen: default(), diff --git a/scenes/building1_basement2/src/lib.rs b/scenes/building1_basement2/src/lib.rs index 57eb7d98..cad606b8 100644 --- a/scenes/building1_basement2/src/lib.rs +++ b/scenes/building1_basement2/src/lib.rs @@ -23,34 +23,22 @@ impl TopDownScene for Building1Basement2 { } } -impl WithStandardStateSemantics for Building1Basement2 { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingBuilding1Basement2 - } - - fn running() -> GlobalGameState { - GlobalGameState::AtBuilding1Basement2 - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingBuilding1Basement2 - } -} - #[derive(Event, Reflect, Clone, strum::EnumString)] pub enum Building1Basement2Action { Exit, } pub fn add(app: &mut App) { - info!("Adding {Building1Basement2:?} to app"); + info!("Adding {THIS_SCENE} to app"); app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::( + app, THIS_SCENE, + ); debug!("Adding plugins"); @@ -63,20 +51,20 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(Building1Basement2::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(|q: Query<(), With>| !q.is_empty()) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(Building1Basement2::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(Building1Basement2::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); @@ -85,10 +73,10 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(Building1Basement2::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); - info!("Added {Building1Basement2:?} to app"); + info!("Added {THIS_SCENE} to app"); } fn finish_when_everything_loaded( @@ -105,8 +93,8 @@ fn finish_when_everything_loaded( } fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {Building1Basement2:?}"); - next_state.set(Building1Basement2::running()); + info!("Entering {THIS_SCENE}"); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -114,7 +102,7 @@ fn exit( mut next_state: ResMut>, mut controls: ResMut>, ) { - info!("Leaving {Building1Basement2:?}"); + info!("Leaving {THIS_SCENE}"); // be a good guy and don't invade other game loops with "Enter" controls.consume(&GlobalAction::Interact); @@ -122,12 +110,10 @@ fn exit( use GlobalGameStateTransition::*; match *transition { Building1Basement2ToBasement1 => { - next_state.set(GlobalGameState::LoadingBuilding1Basement1); + next_state.set(WhichTopDownScene::Building1Basement1.loading()); } _ => { - unreachable!( - "Invalid {Building1Basement2:?} transition {transition:?}" - ); + unreachable!("Invalid {THIS_SCENE} transition {transition:?}"); } } } diff --git a/scenes/building1_basement2/src/prelude.rs b/scenes/building1_basement2/src/prelude.rs index d9eb0307..0f976685 100644 --- a/scenes/building1_basement2/src/prelude.rs +++ b/scenes/building1_basement2/src/prelude.rs @@ -1,3 +1,6 @@ pub(crate) use main_game_lib::prelude::*; pub(crate) use crate::{Building1Basement2, Building1Basement2Action}; + +pub(crate) const THIS_SCENE: WhichTopDownScene = + WhichTopDownScene::Building1Basement2; diff --git a/scenes/building1_player_floor/src/actor.rs b/scenes/building1_player_floor/src/actor.rs index fbf234de..dc52a861 100644 --- a/scenes/building1_player_floor/src/actor.rs +++ b/scenes/building1_player_floor/src/actor.rs @@ -48,14 +48,14 @@ impl bevy::app::Plugin for Plugin { ) .before(DisplayEmojiEventConsumer) .before(ChangeHighlightedInspectLabelEventConsumer) - .run_if(Building1PlayerFloor::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ) .add_systems( Update, toggle_zone_hints .run_if(movement_event_emitted()) - .run_if(Building1PlayerFloor::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .after(emit_movement_events::), ); } @@ -106,7 +106,7 @@ fn start_meditation_minigame( vec![ CutsceneStep::TakeAwayPlayerControl(player), CutsceneStep::ChangeGlobalState { - to: Building1PlayerFloor::quitting(), + to: THIS_SCENE.leaving(), with: GlobalGameStateTransition::Building1PlayerFloorToMeditation, }, @@ -209,7 +209,7 @@ fn sleep(mut cmd: Commands, player: Query>) { vec![ CutsceneStep::TakeAwayPlayerControl(player), CutsceneStep::ChangeGlobalState { - to: Building1PlayerFloor::quitting(), + to: THIS_SCENE.leaving(), with: GlobalGameStateTransition::Sleeping, }, CutsceneStep::StartLoadingScreen { diff --git a/scenes/building1_player_floor/src/layout.rs b/scenes/building1_player_floor/src/layout.rs index f17860ec..65102050 100644 --- a/scenes/building1_player_floor/src/layout.rs +++ b/scenes/building1_player_floor/src/layout.rs @@ -33,26 +33,26 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(Building1PlayerFloor::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(Building1PlayerFloor::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if(rscn::tscn_loaded_but_not_spawned::< Building1PlayerFloor, >()), ) - .add_systems(OnExit(Building1PlayerFloor::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, ( watch_entry_to_hallway::system, environmental_objects::door::toggle::, ) - .run_if(Building1PlayerFloor::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(movement_event_emitted()) .after(actor::emit_movement_events::), ); diff --git a/scenes/building1_player_floor/src/lib.rs b/scenes/building1_player_floor/src/lib.rs index 934a7093..de339ee1 100644 --- a/scenes/building1_player_floor/src/lib.rs +++ b/scenes/building1_player_floor/src/lib.rs @@ -25,20 +25,6 @@ impl TopDownScene for Building1PlayerFloor { } } -impl WithStandardStateSemantics for Building1PlayerFloor { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingBuilding1PlayerFloor - } - - fn running() -> GlobalGameState { - GlobalGameState::AtBuilding1PlayerFloor - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingBuilding1PlayerFloor - } -} - #[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] pub enum Building1PlayerFloorAction { EnterElevator, @@ -48,14 +34,16 @@ pub enum Building1PlayerFloorAction { } pub fn add(app: &mut App) { - info!("Adding {Building1PlayerFloor:?} to app"); + info!("Adding {THIS_SCENE} to app"); app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::( + app, THIS_SCENE, + ); debug!("Adding plugins"); @@ -68,20 +56,20 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(Building1PlayerFloor::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(|q: Query<(), With>| !q.is_empty()) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(Building1PlayerFloor::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(Building1PlayerFloor::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(common_loading_screen::wait_state())), ); @@ -90,10 +78,10 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(Building1PlayerFloor::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); - info!("Added {Building1PlayerFloor:?} to app"); + info!("Added {THIS_SCENE} to app"); } fn finish_when_everything_loaded( @@ -110,8 +98,8 @@ fn finish_when_everything_loaded( } fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {Building1PlayerFloor:?}"); - next_state.set(Building1PlayerFloor::running()); + info!("Entering {THIS_SCENE}"); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -119,7 +107,7 @@ fn exit( mut next_state: ResMut>, mut controls: ResMut>, ) { - info!("Leaving {Building1PlayerFloor:?}"); + info!("Leaving {THIS_SCENE}"); // be a good guy and don't invade other game loops with "Enter" controls.consume(&GlobalAction::Interact); @@ -127,21 +115,19 @@ fn exit( use GlobalGameStateTransition::*; match *transition { Building1PlayerFloorToBuilding1Basement1 => { - next_state.set(GlobalGameState::LoadingBuilding1Basement1); + next_state.set(WhichTopDownScene::Building1Basement1.loading()); } Building1PlayerFloorToMeditation => { - next_state.set(GlobalGameState::LoadingMeditation); + next_state.set(WhichTopDownScene::Meditation.loading()); } Building1PlayerFloorToDowntown => { - next_state.set(GlobalGameState::LoadingDowntown); + next_state.set(WhichTopDownScene::Downtown.loading()); } Sleeping => { - next_state.set(GlobalGameState::LoadingBuilding1PlayerFloor); + next_state.set(WhichTopDownScene::Building1PlayerFloor.loading()); } _ => { - unreachable!( - "Invalid {Building1PlayerFloor:?} transition {transition:?}" - ); + unreachable!("Invalid {THIS_SCENE} transition {transition:?}"); } } } diff --git a/scenes/building1_player_floor/src/prelude.rs b/scenes/building1_player_floor/src/prelude.rs index 1baec2eb..db3176d6 100644 --- a/scenes/building1_player_floor/src/prelude.rs +++ b/scenes/building1_player_floor/src/prelude.rs @@ -13,3 +13,6 @@ pub(crate) const WINNIE_IN_BATHROOM_TRANSITION_FOR_AT_LEAST: Duration = /// Walk down slowly otherwise it'll happen before the player even sees it. pub(crate) const STEP_TIME_ONLOAD_FROM_MEDITATION: Duration = from_millis(750); + +pub(crate) const THIS_SCENE: WhichTopDownScene = + WhichTopDownScene::Building1PlayerFloor; diff --git a/scenes/clinic/src/layout.rs b/scenes/clinic/src/layout.rs index 91387855..5454dacb 100644 --- a/scenes/clinic/src/layout.rs +++ b/scenes/clinic/src/layout.rs @@ -24,27 +24,27 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(Clinic::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(Clinic::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if(rscn::tscn_loaded_but_not_spawned::()), ) - .add_systems(OnExit(Clinic::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, exit.run_if(on_event::()) - .run_if(Clinic::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ) .add_systems( Update, environmental_objects::door::toggle:: - .run_if(Clinic::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(movement_event_emitted()) .after(actor::emit_movement_events::), ); diff --git a/scenes/clinic/src/lib.rs b/scenes/clinic/src/lib.rs index 08a8f83a..8b11aa53 100644 --- a/scenes/clinic/src/lib.rs +++ b/scenes/clinic/src/lib.rs @@ -23,20 +23,6 @@ impl TopDownScene for Clinic { } } -impl WithStandardStateSemantics for Clinic { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingClinic - } - - fn running() -> GlobalGameState { - GlobalGameState::AtClinic - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingClinic - } -} - #[derive(Event, Reflect, Clone, strum::EnumString)] pub enum ClinicAction { ExitScene, @@ -47,10 +33,10 @@ pub fn add(app: &mut App) { app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::(app, THIS_SCENE); debug!("Adding plugins"); @@ -63,20 +49,20 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(Clinic::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(|q: Query<(), With>| !q.is_empty()) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(Clinic::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(Clinic::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); @@ -85,7 +71,7 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(Clinic::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); info!("Added {Clinic:?} to app"); @@ -106,7 +92,7 @@ fn finish_when_everything_loaded( fn enter_the_scene(mut next_state: ResMut>) { info!("Entering {Clinic:?}"); - next_state.set(Clinic::running()); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -122,7 +108,7 @@ fn exit( use GlobalGameStateTransition::*; match *transition { ClinicToDowntown => { - next_state.set(GlobalGameState::LoadingDowntown); + next_state.set(WhichTopDownScene::Downtown.loading()); } _ => { unreachable!("Invalid {Clinic:?} transition {transition:?}"); diff --git a/scenes/clinic/src/prelude.rs b/scenes/clinic/src/prelude.rs index a085abef..8c0e8cb7 100644 --- a/scenes/clinic/src/prelude.rs +++ b/scenes/clinic/src/prelude.rs @@ -1,3 +1,5 @@ pub(crate) use main_game_lib::prelude::*; pub(crate) use crate::{Clinic, ClinicAction}; + +pub(crate) const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Clinic; diff --git a/scenes/clinic_ward/src/layout.rs b/scenes/clinic_ward/src/layout.rs index 80691f65..ae6ca1bd 100644 --- a/scenes/clinic_ward/src/layout.rs +++ b/scenes/clinic_ward/src/layout.rs @@ -18,21 +18,21 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(ClinicWard::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(ClinicWard::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if(rscn::tscn_loaded_but_not_spawned::()), ) - .add_systems(OnExit(ClinicWard::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, exit.run_if(on_event_variant(ClinicWardAction::ExitScene)) - .run_if(ClinicWard::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ); } diff --git a/scenes/clinic_ward/src/lib.rs b/scenes/clinic_ward/src/lib.rs index 07842be5..b5ff1b4a 100644 --- a/scenes/clinic_ward/src/lib.rs +++ b/scenes/clinic_ward/src/lib.rs @@ -23,20 +23,6 @@ impl TopDownScene for ClinicWard { } } -impl WithStandardStateSemantics for ClinicWard { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingClinicWard - } - - fn running() -> GlobalGameState { - GlobalGameState::AtClinicWard - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingClinicWard - } -} - #[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] pub enum ClinicWardAction { ExitScene, @@ -47,10 +33,10 @@ pub fn add(app: &mut App) { app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::(app, THIS_SCENE); debug!("Adding plugins"); @@ -63,20 +49,20 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(ClinicWard::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(|q: Query<(), With>| !q.is_empty()) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(ClinicWard::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(ClinicWard::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); @@ -85,7 +71,7 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(ClinicWard::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); info!("Added {ClinicWard:?} to app"); @@ -106,7 +92,7 @@ fn finish_when_everything_loaded( fn enter_the_scene(mut next_state: ResMut>) { info!("Entering {ClinicWard:?}"); - next_state.set(ClinicWard::running()); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -122,7 +108,7 @@ fn exit( use GlobalGameStateTransition::*; match *transition { ClinicWardToDowntown => { - next_state.set(GlobalGameState::LoadingDowntown); + next_state.set(WhichTopDownScene::Downtown.loading()); } _ => { unreachable!("Invalid {ClinicWard:?} transition {transition:?}"); diff --git a/scenes/clinic_ward/src/prelude.rs b/scenes/clinic_ward/src/prelude.rs index 2751fc6b..7aa5edf7 100644 --- a/scenes/clinic_ward/src/prelude.rs +++ b/scenes/clinic_ward/src/prelude.rs @@ -1,3 +1,5 @@ pub(crate) use main_game_lib::prelude::*; pub(crate) use crate::{ClinicWard, ClinicWardAction}; + +pub(crate) const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::ClinicWard; diff --git a/scenes/compound/src/layout.rs b/scenes/compound/src/layout.rs index 46ad59c1..7906d673 100644 --- a/scenes/compound/src/layout.rs +++ b/scenes/compound/src/layout.rs @@ -22,17 +22,17 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(Compound::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(Compound::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if(rscn::tscn_loaded_but_not_spawned::()), ) - .add_systems(OnExit(Compound::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, ( @@ -41,7 +41,7 @@ impl bevy::app::Plugin for Plugin { enter_tower .run_if(on_event_variant(CompoundAction::EnterTower)), ) - .run_if(Compound::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ); } diff --git a/scenes/compound/src/lib.rs b/scenes/compound/src/lib.rs index af0a0a10..98ffec2a 100644 --- a/scenes/compound/src/lib.rs +++ b/scenes/compound/src/lib.rs @@ -24,20 +24,6 @@ impl TopDownScene for Compound { } } -impl WithStandardStateSemantics for Compound { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingCompound - } - - fn running() -> GlobalGameState { - GlobalGameState::AtCompound - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingCompound - } -} - #[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] pub enum CompoundAction { GoToDowntown, @@ -49,10 +35,10 @@ pub fn add(app: &mut App) { app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::(app, THIS_SCENE); debug!("Adding plugins"); @@ -65,20 +51,20 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(Compound::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(|q: Query<(), With>| !q.is_empty()) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(Compound::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(Compound::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); @@ -87,7 +73,7 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(Compound::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); info!("Added {Compound:?} to app"); @@ -108,7 +94,7 @@ fn finish_when_everything_loaded( fn enter_the_scene(mut next_state: ResMut>) { info!("Entering {Compound:?}"); - next_state.set(Compound::running()); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -124,10 +110,10 @@ fn exit( use GlobalGameStateTransition::*; match *transition { CompoundToDowntown => { - next_state.set(GlobalGameState::LoadingDowntown); + next_state.set(WhichTopDownScene::Downtown.loading()); } CompoundToTower => { - next_state.set(GlobalGameState::LoadingCompoundTower); + next_state.set(WhichTopDownScene::CompoundTower.loading()); } _ => { unreachable!("Invalid {Compound:?} transition {transition:?}"); diff --git a/scenes/compound/src/prelude.rs b/scenes/compound/src/prelude.rs index 9614608b..f363bd01 100644 --- a/scenes/compound/src/prelude.rs +++ b/scenes/compound/src/prelude.rs @@ -1,3 +1,5 @@ pub(crate) use main_game_lib::prelude::*; pub(crate) use crate::{Compound, CompoundAction}; + +pub(crate) const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Compound; diff --git a/scenes/compound_tower/src/layout.rs b/scenes/compound_tower/src/layout.rs index 73d4b5c1..afb694dc 100644 --- a/scenes/compound_tower/src/layout.rs +++ b/scenes/compound_tower/src/layout.rs @@ -18,21 +18,21 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(CompoundTower::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(CompoundTower::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if(rscn::tscn_loaded_but_not_spawned::()), ) - .add_systems(OnExit(CompoundTower::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, exit.run_if(on_event_variant(CompoundTowerAction::ExitScene)) - .run_if(CompoundTower::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ); } diff --git a/scenes/compound_tower/src/lib.rs b/scenes/compound_tower/src/lib.rs index 2af823c6..e70878f9 100644 --- a/scenes/compound_tower/src/lib.rs +++ b/scenes/compound_tower/src/lib.rs @@ -23,20 +23,6 @@ impl TopDownScene for CompoundTower { } } -impl WithStandardStateSemantics for CompoundTower { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingCompoundTower - } - - fn running() -> GlobalGameState { - GlobalGameState::AtCompoundTower - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingCompoundTower - } -} - #[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] pub enum CompoundTowerAction { ExitScene, @@ -47,10 +33,10 @@ pub fn add(app: &mut App) { app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::(app, THIS_SCENE); debug!("Adding plugins"); @@ -63,20 +49,20 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(CompoundTower::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(|q: Query<(), With>| !q.is_empty()) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(CompoundTower::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(CompoundTower::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); @@ -85,7 +71,7 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(CompoundTower::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); info!("Added {CompoundTower:?} to app"); @@ -106,7 +92,7 @@ fn finish_when_everything_loaded( fn enter_the_scene(mut next_state: ResMut>) { info!("Entering {CompoundTower:?}"); - next_state.set(CompoundTower::running()); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -122,7 +108,7 @@ fn exit( use GlobalGameStateTransition::*; match *transition { TowerToCompound => { - next_state.set(GlobalGameState::LoadingCompound); + next_state.set(WhichTopDownScene::Compound.loading()); } _ => { unreachable!("Invalid {CompoundTower:?} transition {transition:?}"); diff --git a/scenes/compound_tower/src/prelude.rs b/scenes/compound_tower/src/prelude.rs index e1b6ca6a..18c620b8 100644 --- a/scenes/compound_tower/src/prelude.rs +++ b/scenes/compound_tower/src/prelude.rs @@ -1,3 +1,6 @@ pub(crate) use main_game_lib::prelude::*; pub(crate) use crate::{CompoundTower, CompoundTowerAction}; + +pub(crate) const THIS_SCENE: WhichTopDownScene = + WhichTopDownScene::CompoundTower; diff --git a/scenes/downtown/src/layout.rs b/scenes/downtown/src/layout.rs index d36ce8b7..2fc6d94f 100644 --- a/scenes/downtown/src/layout.rs +++ b/scenes/downtown/src/layout.rs @@ -33,18 +33,18 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(Downtown::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(Downtown::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if(any_with_component::) .run_if(rscn::tscn_loaded_but_not_spawned::()), ) - .add_systems(OnExit(Downtown::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, ( @@ -66,7 +66,7 @@ impl bevy::app::Plugin for Plugin { .run_if(on_event_variant(DowntownAction::EnterCompound)), ) .before(ChangeHighlightedInspectLabelEventConsumer) - .run_if(Downtown::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ); } diff --git a/scenes/downtown/src/lib.rs b/scenes/downtown/src/lib.rs index 8acac39c..0f4ba24d 100644 --- a/scenes/downtown/src/lib.rs +++ b/scenes/downtown/src/lib.rs @@ -21,20 +21,6 @@ impl TopDownScene for Downtown { } } -impl WithStandardStateSemantics for Downtown { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingDowntown - } - - fn running() -> GlobalGameState { - GlobalGameState::AtDowntown - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingDowntown - } -} - #[derive(Event, Reflect, Clone, strum::EnumString, Eq, PartialEq)] pub enum DowntownAction { EnterBuilding1, @@ -52,10 +38,10 @@ pub fn add(app: &mut App) { app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::(app, THIS_SCENE); debug!("Adding plugins"); @@ -68,19 +54,19 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(Downtown::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(Downtown::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(Downtown::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); @@ -89,7 +75,7 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(Downtown::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); info!("Added downtown to app"); @@ -110,7 +96,7 @@ fn finish_when_everything_loaded( fn enter_the_scene(mut next_state: ResMut>) { info!("Entering downtown"); - next_state.set(Downtown::running()); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -126,28 +112,28 @@ fn exit( use GlobalGameStateTransition::*; match *transition { DowntownToBuilding1PlayerFloor => { - next_state.set(GlobalGameState::LoadingBuilding1PlayerFloor); + next_state.set(WhichTopDownScene::Building1PlayerFloor.loading()); } DowntownToMall => { - next_state.set(GlobalGameState::LoadingMall); + next_state.set(WhichTopDownScene::Mall.loading()); } DowntownToCompound => { - next_state.set(GlobalGameState::LoadingCompound); + next_state.set(WhichTopDownScene::Compound.loading()); } DowntownToClinic => { - next_state.set(GlobalGameState::LoadingClinic); + next_state.set(WhichTopDownScene::Clinic.loading()); } DowntownToClinicWard => { - next_state.set(GlobalGameState::LoadingClinicWard); + next_state.set(WhichTopDownScene::ClinicWard.loading()); } DowntownToPlantShop => { - next_state.set(GlobalGameState::LoadingPlantShop); + next_state.set(WhichTopDownScene::PlantShop.loading()); } DowntownToSewers => { - next_state.set(GlobalGameState::LoadingSewers); + next_state.set(WhichTopDownScene::Sewers.loading()); } DowntownToTwinpeaksApartment => { - next_state.set(GlobalGameState::LoadingTwinpeaksApartment); + next_state.set(WhichTopDownScene::TwinpeaksApartment.loading()); } _ => { unreachable!("Invalid Downtown transition {transition:?}"); diff --git a/scenes/downtown/src/prelude.rs b/scenes/downtown/src/prelude.rs index e8a89b74..450c3ce2 100644 --- a/scenes/downtown/src/prelude.rs +++ b/scenes/downtown/src/prelude.rs @@ -1,3 +1,5 @@ pub(crate) use main_game_lib::prelude::*; pub(crate) use crate::{Downtown, DowntownAction}; + +pub(crate) const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Downtown; diff --git a/scenes/mall/src/layout.rs b/scenes/mall/src/layout.rs index 96dc18ff..8bb6636f 100644 --- a/scenes/mall/src/layout.rs +++ b/scenes/mall/src/layout.rs @@ -26,22 +26,22 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(Mall::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(Mall::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if(rscn::tscn_loaded_but_not_spawned::()), ) - .add_systems(OnExit(Mall::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, (exit, talk_to_ginger_cat) .run_if(on_event::()) - .run_if(Mall::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ); } diff --git a/scenes/mall/src/lib.rs b/scenes/mall/src/lib.rs index f13deec8..13be1131 100644 --- a/scenes/mall/src/lib.rs +++ b/scenes/mall/src/lib.rs @@ -23,20 +23,6 @@ impl TopDownScene for Mall { } } -impl WithStandardStateSemantics for Mall { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingMall - } - - fn running() -> GlobalGameState { - GlobalGameState::AtMall - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingMall - } -} - #[derive(Event, Reflect, Clone, strum::EnumString)] pub enum MallAction { ExitScene, @@ -48,10 +34,10 @@ pub fn add(app: &mut App) { app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::(app, THIS_SCENE); debug!("Adding plugins"); @@ -64,20 +50,20 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(Mall::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(|q: Query<(), With>| !q.is_empty()) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(Mall::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(Mall::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); @@ -86,7 +72,7 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(Mall::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); info!("Added {Mall:?} to app"); @@ -107,7 +93,7 @@ fn finish_when_everything_loaded( fn enter_the_scene(mut next_state: ResMut>) { info!("Entering {Mall:?}"); - next_state.set(Mall::running()); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -123,7 +109,7 @@ fn exit( use GlobalGameStateTransition::*; match *transition { MallToDowntown => { - next_state.set(GlobalGameState::LoadingDowntown); + next_state.set(WhichTopDownScene::Downtown.loading()); } _ => { unreachable!("Invalid {Mall:?} transition {transition:?}"); diff --git a/scenes/mall/src/prelude.rs b/scenes/mall/src/prelude.rs index 33be9ad8..41f6fe6c 100644 --- a/scenes/mall/src/prelude.rs +++ b/scenes/mall/src/prelude.rs @@ -1,3 +1,5 @@ pub(crate) use main_game_lib::prelude::*; pub(crate) use crate::{Mall, MallAction}; + +pub(crate) const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Mall; diff --git a/scenes/meditation/src/lib.rs b/scenes/meditation/src/lib.rs index f36d700c..a5c44651 100644 --- a/scenes/meditation/src/lib.rs +++ b/scenes/meditation/src/lib.rs @@ -187,7 +187,7 @@ fn all_cleaned_up( next_state.set(GlobalGameState::LoadingMeditation); } MeditationToBuilding1PlayerFloor => { - next_state.set(GlobalGameState::LoadingBuilding1PlayerFloor); + next_state.set(WhichTopDownScene::Building1PlayerFloor.loading()); } _ => { unreachable!("Invalid meditation transition {transition:?}"); diff --git a/scenes/plant_shop/src/layout.rs b/scenes/plant_shop/src/layout.rs index 5f47f9c1..8b9f6f59 100644 --- a/scenes/plant_shop/src/layout.rs +++ b/scenes/plant_shop/src/layout.rs @@ -18,21 +18,21 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(PlantShop::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(PlantShop::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if(rscn::tscn_loaded_but_not_spawned::()), ) - .add_systems(OnExit(PlantShop::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, exit.run_if(on_event_variant(PlantShopAction::ExitScene)) - .run_if(PlantShop::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ); } diff --git a/scenes/plant_shop/src/lib.rs b/scenes/plant_shop/src/lib.rs index 0bcb6f21..acda8a46 100644 --- a/scenes/plant_shop/src/lib.rs +++ b/scenes/plant_shop/src/lib.rs @@ -23,20 +23,6 @@ impl TopDownScene for PlantShop { } } -impl WithStandardStateSemantics for PlantShop { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingPlantShop - } - - fn running() -> GlobalGameState { - GlobalGameState::AtPlantShop - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingPlantShop - } -} - #[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] pub enum PlantShopAction { ExitScene, @@ -47,10 +33,10 @@ pub fn add(app: &mut App) { app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::(app, THIS_SCENE); debug!("Adding plugins"); @@ -63,20 +49,20 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(PlantShop::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(|q: Query<(), With>| !q.is_empty()) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(PlantShop::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(PlantShop::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); @@ -85,7 +71,7 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(PlantShop::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); info!("Added {PlantShop:?} to app"); @@ -106,7 +92,7 @@ fn finish_when_everything_loaded( fn enter_the_scene(mut next_state: ResMut>) { info!("Entering {PlantShop:?}"); - next_state.set(PlantShop::running()); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -122,7 +108,7 @@ fn exit( use GlobalGameStateTransition::*; match *transition { PlantShopToDowntown => { - next_state.set(GlobalGameState::LoadingDowntown); + next_state.set(WhichTopDownScene::Downtown.loading()); } _ => { unreachable!("Invalid {PlantShop:?} transition {transition:?}"); diff --git a/scenes/plant_shop/src/prelude.rs b/scenes/plant_shop/src/prelude.rs index c785e92b..09a8cd56 100644 --- a/scenes/plant_shop/src/prelude.rs +++ b/scenes/plant_shop/src/prelude.rs @@ -1,3 +1,5 @@ pub(crate) use main_game_lib::prelude::*; pub(crate) use crate::{PlantShop, PlantShopAction}; + +pub(crate) const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::PlantShop; diff --git a/scenes/sewers/src/layout.rs b/scenes/sewers/src/layout.rs index 856e464f..5c8c49ca 100644 --- a/scenes/sewers/src/layout.rs +++ b/scenes/sewers/src/layout.rs @@ -18,21 +18,21 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(Sewers::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(Sewers::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if(rscn::tscn_loaded_but_not_spawned::()), ) - .add_systems(OnExit(Sewers::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, exit.run_if(on_event::()) - .run_if(Sewers::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ); } diff --git a/scenes/sewers/src/lib.rs b/scenes/sewers/src/lib.rs index 41a749d7..ddb68936 100644 --- a/scenes/sewers/src/lib.rs +++ b/scenes/sewers/src/lib.rs @@ -23,20 +23,6 @@ impl TopDownScene for Sewers { } } -impl WithStandardStateSemantics for Sewers { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingSewers - } - - fn running() -> GlobalGameState { - GlobalGameState::AtSewers - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingSewers - } -} - #[derive(Event, Reflect, Clone, strum::EnumString)] pub enum SewersAction { ExitScene, @@ -47,10 +33,10 @@ pub fn add(app: &mut App) { app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::(app, THIS_SCENE); debug!("Adding plugins"); @@ -63,20 +49,20 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(Sewers::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(|q: Query<(), With>| !q.is_empty()) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(Sewers::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(Sewers::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); @@ -85,7 +71,7 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(Sewers::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); info!("Added {Sewers:?} to app"); @@ -106,7 +92,7 @@ fn finish_when_everything_loaded( fn enter_the_scene(mut next_state: ResMut>) { info!("Entering {Sewers:?}"); - next_state.set(Sewers::running()); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -122,7 +108,7 @@ fn exit( use GlobalGameStateTransition::*; match *transition { SewersToDowntown => { - next_state.set(GlobalGameState::LoadingDowntown); + next_state.set(WhichTopDownScene::Downtown.loading()); } _ => { unreachable!("Invalid {Sewers:?} transition {transition:?}"); diff --git a/scenes/sewers/src/prelude.rs b/scenes/sewers/src/prelude.rs index dc9bc351..e9064cbb 100644 --- a/scenes/sewers/src/prelude.rs +++ b/scenes/sewers/src/prelude.rs @@ -1,3 +1,5 @@ pub(crate) use main_game_lib::prelude::*; pub(crate) use crate::{Sewers, SewersAction}; + +pub(crate) const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Sewers; diff --git a/scenes/twinpeaks_apartment/src/layout.rs b/scenes/twinpeaks_apartment/src/layout.rs index f468e30c..34f9a8e7 100644 --- a/scenes/twinpeaks_apartment/src/layout.rs +++ b/scenes/twinpeaks_apartment/src/layout.rs @@ -18,23 +18,23 @@ pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { app.add_systems( - OnEnter(TwinpeaksApartment::loading()), + OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, ) .add_systems( Update, spawn - .run_if(TwinpeaksApartment::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(resource_exists::>) .run_if( rscn::tscn_loaded_but_not_spawned::(), ), ) - .add_systems(OnExit(TwinpeaksApartment::quitting()), despawn) + .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, exit.run_if(on_event::()) - .run_if(TwinpeaksApartment::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), ); } @@ -175,6 +175,6 @@ fn exit( next_loading_screen_state.set(common_loading_screen::start_state()); *transition = GlobalGameStateTransition::TwinpeaksApartmentToDowntown; - next_state.set(TwinpeaksApartment::quitting()); + next_state.set(THIS_SCENE.leaving()); } } diff --git a/scenes/twinpeaks_apartment/src/lib.rs b/scenes/twinpeaks_apartment/src/lib.rs index 33e9d5ec..ce503227 100644 --- a/scenes/twinpeaks_apartment/src/lib.rs +++ b/scenes/twinpeaks_apartment/src/lib.rs @@ -23,20 +23,6 @@ impl TopDownScene for TwinpeaksApartment { } } -impl WithStandardStateSemantics for TwinpeaksApartment { - fn loading() -> GlobalGameState { - GlobalGameState::LoadingTwinpeaksApartment - } - - fn running() -> GlobalGameState { - GlobalGameState::AtTwinpeaksApartment - } - - fn quitting() -> GlobalGameState { - GlobalGameState::QuittingTwinpeaksApartment - } -} - #[derive(Event, Reflect, Clone, strum::EnumString)] pub enum TwinpeaksApartmentAction { ExitScene, @@ -47,10 +33,12 @@ pub fn add(app: &mut App) { app.add_event::(); - top_down::default_setup_for_scene::(app); + top_down::default_setup_for_scene::(app, THIS_SCENE); #[cfg(feature = "devtools")] - top_down::dev_default_setup_for_scene::(app); + top_down::dev_default_setup_for_scene::( + app, THIS_SCENE, + ); debug!("Adding plugins"); @@ -63,20 +51,20 @@ pub fn add(app: &mut App) { app.add_systems( Last, finish_when_everything_loaded - .run_if(TwinpeaksApartment::in_loading_state()) + .run_if(in_scene_loading_state(THIS_SCENE)) .run_if(|q: Query<(), With>| !q.is_empty()) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); // ready to enter the game when the loading screen is completely gone app.add_systems( OnEnter(LoadingScreenState::DespawnLoadingScreen), - enter_the_scene.run_if(TwinpeaksApartment::in_loading_state()), + enter_the_scene.run_if(in_scene_loading_state(THIS_SCENE)), ); app.add_systems( Update, common_loading_screen::finish - .run_if(TwinpeaksApartment::in_running_state()) + .run_if(in_scene_running_state(THIS_SCENE)) .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), ); @@ -85,7 +73,7 @@ pub fn add(app: &mut App) { // wait for the loading screen to fade in before changing state, // otherwise the player might see a flicker exit.run_if(in_state(common_loading_screen::wait_state())) - .run_if(TwinpeaksApartment::in_quitting_state()), + .run_if(in_scene_leaving_state(THIS_SCENE)), ); info!("Added {TwinpeaksApartment:?} to app"); @@ -106,7 +94,7 @@ fn finish_when_everything_loaded( fn enter_the_scene(mut next_state: ResMut>) { info!("Entering {TwinpeaksApartment:?}"); - next_state.set(TwinpeaksApartment::running()); + next_state.set(THIS_SCENE.running()); } fn exit( @@ -122,7 +110,7 @@ fn exit( use GlobalGameStateTransition::*; match *transition { TwinpeaksApartmentToDowntown => { - next_state.set(GlobalGameState::LoadingDowntown); + next_state.set(WhichTopDownScene::Downtown.loading()); } _ => { unreachable!( diff --git a/scenes/twinpeaks_apartment/src/prelude.rs b/scenes/twinpeaks_apartment/src/prelude.rs index 035896bd..1ed325ec 100644 --- a/scenes/twinpeaks_apartment/src/prelude.rs +++ b/scenes/twinpeaks_apartment/src/prelude.rs @@ -1,3 +1,6 @@ pub(crate) use main_game_lib::prelude::*; pub(crate) use crate::{TwinpeaksApartment, TwinpeaksApartmentAction}; + +pub(crate) const THIS_SCENE: WhichTopDownScene = + WhichTopDownScene::TwinpeaksApartment;