diff --git a/Cargo.lock b/Cargo.lock index f071301c..8f1ca065 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1637,7 +1637,6 @@ dependencies = [ "common_assets", "common_visuals", "rand", - "strum", ] [[package]] @@ -1656,7 +1655,6 @@ dependencies = [ "rusqlite_migration", "serde", "serde_json", - "strum", ] [[package]] @@ -1666,12 +1664,9 @@ dependencies = [ "bevy", "bevy-inspector-egui", "bevy_grid_squared", - "common_action", "common_assets", - "common_store", "common_visuals", "serde", - "serde_with", "strum", ] @@ -3140,19 +3135,8 @@ dependencies = [ "common_store", "common_story", "main_game_lib", - "scene_building1_basement1", - "scene_building1_basement2", - "scene_building1_player_floor", - "scene_clinic", - "scene_clinic_ward", - "scene_compound", - "scene_compound_tower", - "scene_downtown", - "scene_mall", "scene_meditation", - "scene_plant_shop", - "scene_sewers", - "scene_twinpeaks_apartment", + "scene_top_down", ] [[package]] @@ -4323,200 +4307,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scene_building1_basement1" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_grid_squared", - "bevy_pixel_camera", - "common_action", - "common_assets", - "common_loading_screen", - "common_store", - "common_story", - "common_visuals", - "itertools 0.13.0", - "lazy_static", - "main_game_lib", - "rand", - "serde", - "smallvec", - "strum", -] - -[[package]] -name = "scene_building1_basement2" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_grid_squared", - "bevy_pixel_camera", - "common_action", - "common_assets", - "common_loading_screen", - "common_store", - "common_story", - "common_visuals", - "itertools 0.13.0", - "lazy_static", - "main_game_lib", - "rand", - "serde", - "smallvec", - "strum", -] - -[[package]] -name = "scene_building1_player_floor" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_grid_squared", - "bevy_pixel_camera", - "common_action", - "common_assets", - "common_loading_screen", - "common_store", - "common_story", - "common_visuals", - "itertools 0.13.0", - "lazy_static", - "main_game_lib", - "rand", - "serde", - "smallvec", - "strum", -] - -[[package]] -name = "scene_clinic" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_grid_squared", - "bevy_pixel_camera", - "common_action", - "common_assets", - "common_loading_screen", - "common_store", - "common_story", - "common_visuals", - "itertools 0.13.0", - "lazy_static", - "main_game_lib", - "rand", - "serde", - "smallvec", - "strum", -] - -[[package]] -name = "scene_clinic_ward" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_grid_squared", - "bevy_pixel_camera", - "common_action", - "common_assets", - "common_loading_screen", - "common_store", - "common_story", - "common_visuals", - "itertools 0.13.0", - "lazy_static", - "main_game_lib", - "rand", - "serde", - "smallvec", - "strum", -] - -[[package]] -name = "scene_compound" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_grid_squared", - "bevy_pixel_camera", - "common_action", - "common_assets", - "common_loading_screen", - "common_store", - "common_story", - "common_visuals", - "itertools 0.13.0", - "lazy_static", - "main_game_lib", - "rand", - "serde", - "smallvec", - "strum", -] - -[[package]] -name = "scene_compound_tower" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_grid_squared", - "bevy_pixel_camera", - "common_action", - "common_assets", - "common_loading_screen", - "common_store", - "common_story", - "common_visuals", - "itertools 0.13.0", - "lazy_static", - "main_game_lib", - "rand", - "serde", - "smallvec", - "strum", -] - -[[package]] -name = "scene_downtown" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_grid_squared", - "bevy_pixel_camera", - "common_assets", - "common_loading_screen", - "common_store", - "common_story", - "common_visuals", - "lazy_static", - "main_game_lib", - "serde", - "strum", -] - -[[package]] -name = "scene_mall" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_grid_squared", - "bevy_pixel_camera", - "common_action", - "common_assets", - "common_loading_screen", - "common_store", - "common_story", - "common_visuals", - "itertools 0.13.0", - "lazy_static", - "main_game_lib", - "rand", - "serde", - "smallvec", - "strum", -] - [[package]] name = "scene_meditation" version = "0.1.0" @@ -4537,68 +4327,16 @@ dependencies = [ ] [[package]] -name = "scene_plant_shop" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_grid_squared", - "bevy_pixel_camera", - "common_action", - "common_assets", - "common_loading_screen", - "common_store", - "common_story", - "common_visuals", - "itertools 0.13.0", - "lazy_static", - "main_game_lib", - "rand", - "serde", - "smallvec", - "strum", -] - -[[package]] -name = "scene_sewers" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_grid_squared", - "bevy_pixel_camera", - "common_action", - "common_assets", - "common_loading_screen", - "common_store", - "common_story", - "common_visuals", - "itertools 0.13.0", - "lazy_static", - "main_game_lib", - "rand", - "serde", - "smallvec", - "strum", -] - -[[package]] -name = "scene_twinpeaks_apartment" +name = "scene_top_down" version = "0.1.0" dependencies = [ "bevy", "bevy_grid_squared", - "bevy_pixel_camera", - "common_action", - "common_assets", "common_loading_screen", - "common_store", "common_story", "common_visuals", - "itertools 0.13.0", - "lazy_static", "main_game_lib", "rand", - "serde", - "smallvec", "strum", ] diff --git a/Cargo.toml b/Cargo.toml index 23180c27..7f2dc22e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,19 +14,8 @@ members = [ "common/visuals", "main_game_lib", "main_game", - "scenes/building1_basement1", - "scenes/building1_basement2", - "scenes/building1_player_floor", - "scenes/clinic_ward", - "scenes/clinic", - "scenes/compound_tower", - "scenes/compound", - "scenes/downtown", - "scenes/mall", "scenes/meditation", - "scenes/plant_shop", - "scenes/sewers", - "scenes/twinpeaks_apartment", + "scenes/top_down", ] @@ -61,19 +50,8 @@ bevy-inspector-egui = { version = "0.25", default-features = false, features = [ leafwing-input-manager = "0.14" bevy_egui = "0.28" -scene_building1_basement1 = { path = "scenes/building1_basement1" } -scene_building1_basement2 = { path = "scenes/building1_basement2" } -scene_building1_player_floor = { path = "scenes/building1_player_floor" } -scene_clinic = { path = "scenes/clinic" } -scene_clinic_ward = { path = "scenes/clinic_ward" } -scene_compound = { path = "scenes/compound" } -scene_compound_tower = { path = "scenes/compound_tower" } -scene_downtown = { path = "scenes/downtown" } -scene_mall = { path = "scenes/mall" } +scene_top_down = { path = "scenes/top_down" } scene_meditation = { path = "scenes/meditation" } -scene_plant_shop = { path = "scenes/plant_shop" } -scene_sewers = { path = "scenes/sewers" } -scene_twinpeaks_apartment = { path = "scenes/twinpeaks_apartment" } bevy_grid_squared = { path = "bevy_grid_squared", features = ["serde"] } common_action = { path = "common/action" } diff --git a/README.md b/README.md index 526c1f21..1f573a75 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,6 @@ With every extra dependency that also depends on Bevy it potentially takes longe - [`bevy_webp_anim`][bevy_webp_anim] is a crate we maintain so not a problem - [`bevy-inspector-egui`][bevy-inspector-egui] - [`leafwing-input-manager`][leafwing-input-manager] is maintained by a core Bevy contributor -- [`bevy_magic_light`](bevy_magic_light/) is a fork of [this][original-bevy_magic_light] we maintain but ideally we'd like to remove it in favor of Bevy's official 2D lighting solution - [`bevy_egui`][bevy_egui] [bevy_pixel_camera]: https://github.com/drakmaniso/bevy_pixel_camera diff --git a/common/loading_screen/Cargo.toml b/common/loading_screen/Cargo.toml index b7bde8ae..70d8bffc 100644 --- a/common/loading_screen/Cargo.toml +++ b/common/loading_screen/Cargo.toml @@ -14,4 +14,3 @@ bevy.workspace = true common_assets.workspace = true common_visuals.workspace = true rand.workspace = true -strum.workspace = true diff --git a/common/store/Cargo.toml b/common/store/Cargo.toml index 2928681b..f7816d9c 100644 --- a/common/store/Cargo.toml +++ b/common/store/Cargo.toml @@ -9,4 +9,3 @@ rusqlite_migration.workspace = true rusqlite.workspace = true serde_json.workspace = true serde.workspace = true -strum.workspace = true diff --git a/common/store/src/lib.rs b/common/store/src/lib.rs index 3c6891e0..f1d982cd 100644 --- a/common/store/src/lib.rs +++ b/common/store/src/lib.rs @@ -1,4 +1,5 @@ //! A way to communicate between scenes and across time (save/load). + #![deny(missing_docs)] use std::{ diff --git a/common/story/Cargo.toml b/common/story/Cargo.toml index 4504a972..b97e9b34 100644 --- a/common/story/Cargo.toml +++ b/common/story/Cargo.toml @@ -12,10 +12,7 @@ devtools = ["bevy-inspector-egui"] bevy_grid_squared.workspace = true bevy-inspector-egui = { workspace = true, optional = true } bevy.workspace = true -common_action.workspace = true common_assets.workspace = true -common_store.workspace = true common_visuals.workspace = true serde = { workspace = true, features = ["derive"] } -serde_with.workspace = true strum.workspace = true diff --git a/main_game/Cargo.toml b/main_game/Cargo.toml index 64ef38fb..1ed75526 100644 --- a/main_game/Cargo.toml +++ b/main_game/Cargo.toml @@ -13,19 +13,8 @@ path = "src/main.rs" [features] devtools = [ "main_game_lib/devtools", - "scene_building1_basement1/devtools", - "scene_building1_basement2/devtools", - "scene_building1_player_floor/devtools", - "scene_clinic_ward/devtools", - "scene_clinic/devtools", - "scene_compound_tower/devtools", - "scene_compound/devtools", - "scene_downtown/devtools", - "scene_mall/devtools", + "scene_top_down/devtools", "scene_meditation/devtools", - "scene_plant_shop/devtools", - "scene_sewers/devtools", - "scene_twinpeaks_apartment/devtools", ] @@ -35,16 +24,5 @@ common_loading_screen.workspace = true common_store.workspace = true common_story.workspace = true main_game_lib.workspace = true -scene_building1_basement1.workspace = true -scene_building1_basement2.workspace = true -scene_building1_player_floor.workspace = true -scene_clinic_ward.workspace = true -scene_clinic.workspace = true -scene_compound_tower.workspace = true -scene_compound.workspace = true -scene_downtown.workspace = true -scene_mall.workspace = true +scene_top_down.workspace = true scene_meditation.workspace = true -scene_plant_shop.workspace = true -scene_sewers.workspace = true -scene_twinpeaks_apartment.workspace = true diff --git a/main_game/src/main.rs b/main_game/src/main.rs index d7bfad1d..6f150858 100644 --- a/main_game/src/main.rs +++ b/main_game/src/main.rs @@ -48,19 +48,8 @@ fn main() { info!("Adding scenes"); - scene_building1_basement1::add(&mut app); - scene_building1_basement2::add(&mut app); - scene_building1_player_floor::add(&mut app); - scene_clinic_ward::add(&mut app); - scene_clinic::add(&mut app); - scene_compound_tower::add(&mut app); - scene_compound::add(&mut app); - scene_downtown::add(&mut app); - scene_mall::add(&mut app); scene_meditation::add(&mut app); - scene_plant_shop::add(&mut app); - scene_sewers::add(&mut app); - scene_twinpeaks_apartment::add(&mut app); + scene_top_down::add(&mut app); info!("Starting Don't Count The Sheep"); app.run(); diff --git a/main_game_lib/src/lib.rs b/main_game_lib/src/lib.rs index e145571d..ce736b01 100644 --- a/main_game_lib/src/lib.rs +++ b/main_game_lib/src/lib.rs @@ -49,6 +49,7 @@ pub fn windowed_app() -> App { main_game_lib::top_down::cameras=debug,\ main_game_lib::top_down::layout=debug,\ main_game_lib::rscn=debug,\ + scene_top_down=trace,\ " .to_string(), ..default() diff --git a/main_game_lib/src/prelude.rs b/main_game_lib/src/prelude.rs index 1df7b508..4347c88b 100644 --- a/main_game_lib/src/prelude.rs +++ b/main_game_lib/src/prelude.rs @@ -14,7 +14,7 @@ pub use common_visuals::PRIMARY_COLOR; pub use crate::{ rscn, state::*, - top_down::{self, Player, TopDownScene}, + top_down::{self, Player}, }; /// A convenience function to create a [`Duration`] from milliseconds. diff --git a/main_game_lib/src/state.rs b/main_game_lib/src/state.rs index fe2f114f..7d12f022 100644 --- a/main_game_lib/src/state.rs +++ b/main_game_lib/src/state.rs @@ -82,7 +82,6 @@ pub enum WhichTopDownScene { Sewers, TwinpeaksApartment, Mall, - Meditation, Downtown, Compound, CompoundTower, diff --git a/main_game_lib/src/top_down.rs b/main_game_lib/src/top_down.rs index 06952dfa..00161d53 100644 --- a/main_game_lib/src/top_down.rs +++ b/main_game_lib/src/top_down.rs @@ -23,7 +23,7 @@ use actor::{emit_movement_events, BeginDialogEvent}; pub use actor::{npc, player::Player, Actor, ActorMovementEvent, ActorTarget}; use bevy::prelude::*; pub use inspect_and_interact::{InspectLabel, InspectLabelCategory}; -pub use layout::{TileKind, TileMap, TopDownScene}; +pub use layout::{TileKind, TileMap}; use leafwing_input_manager::plugin::InputManagerSystem; use self::inspect_and_interact::ChangeHighlightedInspectLabelEvent; @@ -44,6 +44,8 @@ impl bevy::app::Plugin for Plugin { .add_event::() .add_event::(); + app.add_plugins(environmental_objects::Plugin); + // // Assets // diff --git a/main_game_lib/src/top_down/environmental_objects.rs b/main_game_lib/src/top_down/environmental_objects.rs index b81e76ee..74276149 100644 --- a/main_game_lib/src/top_down/environmental_objects.rs +++ b/main_game_lib/src/top_down/environmental_objects.rs @@ -1,3 +1,23 @@ //! Different things that the top down map can have. +use bevy::{app::Update, ecs::schedule::IntoSystemConfigs}; + +use super::actor::{self, movement_event_emitted}; +use crate::in_top_down_running_state; + pub mod door; + +/// Adds systems related to the top down map's environmental objects. +pub struct Plugin; + +impl bevy::app::Plugin for Plugin { + fn build(&self, app: &mut bevy::app::App) { + app.add_systems( + Update, + door::toggle + .run_if(in_top_down_running_state()) + .run_if(movement_event_emitted()) + .after(actor::emit_movement_events), + ); + } +} diff --git a/main_game_lib/src/top_down/environmental_objects/door.rs b/main_game_lib/src/top_down/environmental_objects/door.rs index 05553f5d..d585596a 100644 --- a/main_game_lib/src/top_down/environmental_objects/door.rs +++ b/main_game_lib/src/top_down/environmental_objects/door.rs @@ -2,8 +2,6 @@ //! There are different [`DoorOpenCriteria`] that can be used to open the door. //! Optionally, the door can have an obstacle that's inserted into the map when //! the door is closed. -//! -//! You must register the `environmental_objects::door::toggle` system. use bevy::prelude::*; use bevy_grid_squared::Square; diff --git a/main_game_lib/src/top_down/layout.rs b/main_game_lib/src/top_down/layout.rs index 642188cb..faa96ccf 100644 --- a/main_game_lib/src/top_down/layout.rs +++ b/main_game_lib/src/top_down/layout.rs @@ -14,7 +14,7 @@ use bevy::{ log::{trace, warn}, math::{vec2, Vec2}, prelude::ReflectDefault, - reflect::{Reflect, TypePath}, + reflect::Reflect, utils::hashbrown::HashMap, }; use bevy_grid_squared::{Square, SquareLayout}; @@ -36,11 +36,6 @@ pub const LAYOUT: SquareLayout = SquareLayout { /// A tile is uniquely identified by (`x`, `y`) of the square and a layer index. pub type TileIndex = (Square, usize); -/// Some map. -pub trait TopDownScene: 'static + Send + Sync + TypePath + Default { - // -} - /// Holds the tiles in a hash map. #[derive(Asset, Resource, Serialize, Deserialize, Reflect, Clone, Debug)] pub struct TileMap { diff --git a/scenes/building1_basement1/Cargo.toml b/scenes/building1_basement1/Cargo.toml deleted file mode 100644 index 5d1df8f8..00000000 --- a/scenes/building1_basement1/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "scene_building1_basement1" -version.workspace = true -edition.workspace = true - - -[features] -devtools = [ - "main_game_lib/devtools", - "common_story/devtools", - "common_visuals/devtools", -] - - -[dependencies] -bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true -bevy.workspace = true -common_action.workspace = true -common_assets.workspace = true -common_loading_screen.workspace = true -common_store.workspace = true -common_story.workspace = true -common_visuals.workspace = true -itertools.workspace = true -lazy_static.workspace = true -main_game_lib.workspace = true -rand.workspace = true -serde.workspace = true -smallvec.workspace = true -strum.workspace = true diff --git a/scenes/building1_basement1/README.md b/scenes/building1_basement1/README.md deleted file mode 100644 index b16ce70c..00000000 --- a/scenes/building1_basement1/README.md +++ /dev/null @@ -1,3 +0,0 @@ -An intermediary zone between the actual basement and the rest of the building. - -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/building1_basement1/src/layout/watch_entry_to_apartment.rs b/scenes/building1_basement1/src/layout/watch_entry_to_apartment.rs deleted file mode 100644 index 97dbabd5..00000000 --- a/scenes/building1_basement1/src/layout/watch_entry_to_apartment.rs +++ /dev/null @@ -1,66 +0,0 @@ -use common_visuals::BeginInterpolationEvent; -use main_game_lib::top_down::scene_configs::ZoneTileKind; -use top_down::{actor::Who, ActorMovementEvent, TileKind}; - -use super::ApartmentWall; -use crate::prelude::*; - -/// How long does it take for the entity to go transparent -const WALL_FADE_OUT_TRANSITION_DURATION: Duration = from_millis(500); -/// How long does it take for the entity to go to its full color. -const WALL_FADE_IN_TRANSITION_DURATION: Duration = from_millis(1500); - -/// Listens to events about entering the -/// [`ZoneTileKind::UpperApartmentWallHidden`]. -/// -/// When entered, the [`ApartmentWall`] entity is hidden. -pub(super) fn system( - mut movement_events: EventReader, - mut lerp_event: EventWriter, - - wall: Query>, -) { - use ZoneTileKind::UpperApartmentWallHidden as TheZone; - - for event in movement_events.read() { - match event { - ActorMovementEvent::ZoneEntered { - who: - Who { - is_player: true, .. - }, - zone: TileKind::Zone(TheZone), - } => { - trace!("Hiding apartment wall"); - lerp_event.send( - BeginInterpolationEvent::of_color( - wall.single(), - None, - Color::NONE, - ) - .over(WALL_FADE_OUT_TRANSITION_DURATION), - ); - } - ActorMovementEvent::ZoneLeft { - who: - Who { - is_player: true, .. - }, - zone: TileKind::Zone(TheZone), - } => { - trace!("Showing apartment wall"); - lerp_event.send( - BeginInterpolationEvent::of_color( - wall.single(), - None, - Color::WHITE, - ) - .over(WALL_FADE_IN_TRANSITION_DURATION), - ); - } - - // we don't care about other events - _ => {} - } - } -} diff --git a/scenes/building1_basement1/src/lib.rs b/scenes/building1_basement1/src/lib.rs deleted file mode 100644 index 45c8f0bf..00000000 --- a/scenes/building1_basement1/src/lib.rs +++ /dev/null @@ -1,134 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![feature(trivial_bounds)] -#![feature(let_chains)] - -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -use crate::layout::LayoutEntity; - -/// Important scene struct. -/// We use it as identifiable generic in common logic. -#[derive(TypePath, Default, Debug)] -pub struct Building1Basement1; - -impl TopDownScene for Building1Basement1 {} - -impl main_game_lib::rscn::TscnInBevy for Building1Basement1 { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString, Eq, PartialEq)] -pub enum Building1Basement1Action { - EnterElevator, - EnterBasement2, -} - -pub fn add(app: &mut App) { - info!("Adding {THIS_SCENE} to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins(layout::Plugin); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added {THIS_SCENE} to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {THIS_SCENE}"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving {THIS_SCENE}"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - Building1Basement1ToPlayerFloor => { - next_state.set(WhichTopDownScene::Building1PlayerFloor.loading()); - } - Building1Basement1ToDowntown => { - next_state.set(WhichTopDownScene::Downtown.loading()); - } - Building1Basement1ToBasement2 => { - next_state.set(WhichTopDownScene::Building1Basement2.loading()); - } - _ => { - unreachable!("Invalid {THIS_SCENE} transition {transition:?}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = include_str!( - "../../../main_game/assets/scenes/building1_basement1.tscn", - ); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/building1_basement1/src/prelude.rs b/scenes/building1_basement1/src/prelude.rs deleted file mode 100644 index 98936762..00000000 --- a/scenes/building1_basement1/src/prelude.rs +++ /dev/null @@ -1,6 +0,0 @@ -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/Cargo.toml b/scenes/building1_basement2/Cargo.toml deleted file mode 100644 index 6395fede..00000000 --- a/scenes/building1_basement2/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "scene_building1_basement2" -version.workspace = true -edition.workspace = true - - -[features] -devtools = [ - "main_game_lib/devtools", - "common_story/devtools", - "common_visuals/devtools", -] - - -[dependencies] -bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true -bevy.workspace = true -common_action.workspace = true -common_assets.workspace = true -common_loading_screen.workspace = true -common_store.workspace = true -common_story.workspace = true -common_visuals.workspace = true -itertools.workspace = true -lazy_static.workspace = true -main_game_lib.workspace = true -rand.workspace = true -serde.workspace = true -smallvec.workspace = true -strum.workspace = true diff --git a/scenes/building1_basement2/README.md b/scenes/building1_basement2/README.md deleted file mode 100644 index 15c8a1b3..00000000 --- a/scenes/building1_basement2/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Storage space. - -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/building1_basement2/src/lib.rs b/scenes/building1_basement2/src/lib.rs deleted file mode 100644 index cf555866..00000000 --- a/scenes/building1_basement2/src/lib.rs +++ /dev/null @@ -1,127 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![feature(trivial_bounds)] -#![feature(let_chains)] - -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -use crate::layout::LayoutEntity; - -/// Important scene struct. -/// We use it as identifiable generic in common logic. -#[derive(TypePath, Default, Debug)] -pub struct Building1Basement2; - -impl TopDownScene for Building1Basement2 {} - -impl main_game_lib::rscn::TscnInBevy for Building1Basement2 { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString)] -pub enum Building1Basement2Action { - Exit, -} - -pub fn add(app: &mut App) { - info!("Adding {THIS_SCENE} to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins(layout::Plugin); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added {THIS_SCENE} to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {THIS_SCENE}"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving {THIS_SCENE}"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - Building1Basement2ToBasement1 => { - next_state.set(WhichTopDownScene::Building1Basement1.loading()); - } - _ => { - unreachable!("Invalid {THIS_SCENE} transition {transition:?}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = include_str!( - "../../../main_game/assets/scenes/building1_basement2.tscn" - ); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/building1_basement2/src/prelude.rs b/scenes/building1_basement2/src/prelude.rs deleted file mode 100644 index 0f976685..00000000 --- a/scenes/building1_basement2/src/prelude.rs +++ /dev/null @@ -1,6 +0,0 @@ -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/Cargo.toml b/scenes/building1_player_floor/Cargo.toml deleted file mode 100644 index 41ab83da..00000000 --- a/scenes/building1_player_floor/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "scene_building1_player_floor" -version.workspace = true -edition.workspace = true - - -[features] -devtools = [ - "main_game_lib/devtools", - "common_story/devtools", - "common_visuals/devtools", -] - - -[dependencies] -bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true -bevy.workspace = true -common_action.workspace = true -common_assets.workspace = true -common_loading_screen.workspace = true -common_store.workspace = true -common_story.workspace = true -common_visuals.workspace = true -itertools.workspace = true -lazy_static.workspace = true -main_game_lib.workspace = true -rand.workspace = true -serde.workspace = true -smallvec.workspace = true -strum.workspace = true diff --git a/scenes/building1_player_floor/README.md b/scenes/building1_player_floor/README.md deleted file mode 100644 index 797a9a6b..00000000 --- a/scenes/building1_player_floor/README.md +++ /dev/null @@ -1,9 +0,0 @@ -Main protagonist's apartment is a place where several minigames can be played. - -- We have the [meditation](../meditation) minigame where the player controls Hoshi. -- We have the not yet implemented tea brewing minigame. -- When the player goes to sleep, there will be the a dream minigame most likely. - -There's a hallway with an elevator that leads to the downtown area or other floors. - -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/building1_player_floor/src/actor.rs b/scenes/building1_player_floor/src/actor.rs deleted file mode 100644 index b1f8c700..00000000 --- a/scenes/building1_player_floor/src/actor.rs +++ /dev/null @@ -1,228 +0,0 @@ -//! Player and NPCs. - -use common_loading_screen::LoadingScreenSettings; -use common_story::emoji::{ - DisplayEmojiEvent, DisplayEmojiEventConsumer, EmojiKind, -}; -use common_visuals::camera::MainCamera; -use main_game_lib::{ - common_ext::QueryExt, - cutscene::{self, in_cutscene, CutsceneStep, IntoCutscene}, - dialog::DialogGraph, - hud::daybar::DayBar, - top_down::{ - inspect_and_interact::{ - ChangeHighlightedInspectLabelEvent, - ChangeHighlightedInspectLabelEventConsumer, - SpawnLabelBgAndTextParams, ZoneToInspectLabelEntity, LIGHT_RED, - }, - scene_configs::ZoneTileKind, - }, -}; -use top_down::{ - actor::{emit_movement_events, movement_event_emitted}, - ActorMovementEvent, TileKind, -}; - -use crate::{ - layout::{Elevator, MeditatingHint, SleepingHint}, - prelude::*, -}; - -pub(crate) struct Plugin; - -impl bevy::app::Plugin for Plugin { - fn build(&self, app: &mut App) { - app.add_systems( - Update, - ( - start_meditation_minigame.run_if(on_event_variant( - Building1PlayerFloorAction::StartMeditation, - )), - sleep.run_if(on_event_variant( - Building1PlayerFloorAction::Sleep, - )), - enter_the_elevator.run_if(on_event_variant( - Building1PlayerFloorAction::EnterElevator, - )), - ) - .before(DisplayEmojiEventConsumer) - .before(ChangeHighlightedInspectLabelEventConsumer) - .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(in_scene_running_state(THIS_SCENE)) - .after(emit_movement_events), - ); - } -} - -/// Will change the game state to meditation minigame. -fn start_meditation_minigame( - mut cmd: Commands, - mut emoji_events: EventWriter, - mut inspect_label_events: EventWriter, - zone_to_inspect_label_entity: Res, - daybar: Res, - - player: Query>, -) { - if daybar.is_depleted() { - if let Some(entity) = zone_to_inspect_label_entity - .get(ZoneTileKind::Meditation) - .copied() - { - inspect_label_events.send(ChangeHighlightedInspectLabelEvent { - entity, - spawn_params: SpawnLabelBgAndTextParams { - highlighted: true, - overwrite_font_color: Some(LIGHT_RED), - // LOCALIZATION - overwrite_display_text: Some("(too tired)".to_string()), - }, - }); - } else { - error!("Cannot find meditation zone inspect label entity"); - } - - if let Some(on_parent) = player.get_single_or_none() { - emoji_events.send(DisplayEmojiEvent { - emoji: EmojiKind::Tired, - on_parent, - offset_for: common_story::Character::Winnie, - }); - } else { - error!("Cannot find player entity"); - } - } else { - let Some(player) = player.get_single_or_none() else { - return; - }; - - vec![ - CutsceneStep::TakeAwayPlayerControl(player), - CutsceneStep::ChangeGlobalState { - to: THIS_SCENE.leaving(), - with: - GlobalGameStateTransition::Building1PlayerFloorToMeditation, - }, - CutsceneStep::StartLoadingScreen { - settings: Some(LoadingScreenSettings { - atlas: Some(common_loading_screen::LoadingScreenAtlas::Space), - stare_at_loading_screen_for_at_least: Some( - WHEN_ENTERING_MEDITATION_SHOW_LOADING_IMAGE_FOR_AT_LEAST, - ), - ..default() - }) - } - ].spawn(&mut cmd); - } -} - -/// By entering the elevator, the player can leave this scene. -fn enter_the_elevator( - mut cmd: Commands, - mut assets: ResMut>, - - player: Query>, - elevator: Query>, - camera: Query>, - points: Query<(&Name, &rscn::Point)>, -) { - use GlobalGameStateTransition::*; - - if let Some(player) = player.get_single_or_none() { - let point_in_elevator = { - let (_, rscn::Point(pos)) = points - .iter() - .find(|(name, _)| **name == Name::new("InElevator")) - .expect("InElevator point not found"); - - *pos - }; - - cutscene::enter_an_elevator::spawn( - &mut cmd, - &mut assets, - player, - elevator.single(), - camera.single(), - point_in_elevator, - // LOCALIZATION - &[ - (Building1PlayerFloorToDowntown, "go to downtown"), - (Building1PlayerFloorToBuilding1Basement1, "go to basement"), - ], - ); - } -} - -/// Shows hint for bed or for meditating when player is in the zone to actually -/// interact with those objects. -fn toggle_zone_hints( - mut events: EventReader, - - mut sleeping: Query< - &mut Visibility, - (With, Without), - >, - mut meditating: Query< - &mut Visibility, - (With, Without), - >, -) { - use ZoneTileKind::{Bed, Meditation}; - - for event in events.read().filter(|event| event.is_player()) { - match event { - ActorMovementEvent::ZoneEntered { zone, .. } => match *zone { - TileKind::Zone(Meditation) => { - *meditating.single_mut() = Visibility::Visible; - } - TileKind::Zone(Bed) => { - *sleeping.single_mut() = Visibility::Visible; - } - _ => {} - }, - ActorMovementEvent::ZoneLeft { zone, .. } => match *zone { - TileKind::Zone(Meditation) => { - *meditating.single_mut() = Visibility::Hidden; - } - TileKind::Zone(Bed) => { - *sleeping.single_mut() = Visibility::Hidden; - } - _ => {} - }, - } - } -} - -fn sleep(mut cmd: Commands, player: Query>) { - let Some(player) = player.get_single_or_none() else { - return; - }; - - vec![ - CutsceneStep::TakeAwayPlayerControl(player), - CutsceneStep::ChangeGlobalState { - to: THIS_SCENE.leaving(), - with: GlobalGameStateTransition::Sleeping, - }, - CutsceneStep::StartLoadingScreen { - settings: Some(LoadingScreenSettings { - atlas: Some( - common_loading_screen::LoadingScreenAtlas::WinnieInBathroom, - ), - stare_at_loading_screen_for_at_least: Some( - WINNIE_IN_BATHROOM_TRANSITION_FOR_AT_LEAST, - ), - ..default() - }), - }, - ] - .spawn(&mut cmd); -} diff --git a/scenes/building1_player_floor/src/lib.rs b/scenes/building1_player_floor/src/lib.rs deleted file mode 100644 index b3f4d3e3..00000000 --- a/scenes/building1_player_floor/src/lib.rs +++ /dev/null @@ -1,141 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![feature(trivial_bounds)] -#![feature(let_chains)] -#![allow(clippy::too_many_arguments)] - -mod actor; -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -use crate::layout::LayoutEntity; - -/// Important scene struct. -/// We use it as identifiable generic in common logic. -#[derive(TypePath, Default, Debug)] -pub struct Building1PlayerFloor; - -impl TopDownScene for Building1PlayerFloor {} - -impl main_game_lib::rscn::TscnInBevy for Building1PlayerFloor { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] -pub enum Building1PlayerFloorAction { - EnterElevator, - StartMeditation, - Sleep, - BrewTea, -} - -pub fn add(app: &mut App) { - info!("Adding {THIS_SCENE} to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins((layout::Plugin, actor::Plugin)); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(common_loading_screen::wait_state())), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added {THIS_SCENE} to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {THIS_SCENE}"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving {THIS_SCENE}"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - Building1PlayerFloorToBuilding1Basement1 => { - next_state.set(WhichTopDownScene::Building1Basement1.loading()); - } - Building1PlayerFloorToMeditation => { - next_state.set(WhichTopDownScene::Meditation.loading()); - } - Building1PlayerFloorToDowntown => { - next_state.set(WhichTopDownScene::Downtown.loading()); - } - Sleeping => { - next_state.set(WhichTopDownScene::Building1PlayerFloor.loading()); - } - _ => { - unreachable!("Invalid {THIS_SCENE} transition {transition:?}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = include_str!( - "../../../main_game/assets/scenes/building1_player_floor.tscn", - ); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/building1_player_floor/src/prelude.rs b/scenes/building1_player_floor/src/prelude.rs deleted file mode 100644 index db3176d6..00000000 --- a/scenes/building1_player_floor/src/prelude.rs +++ /dev/null @@ -1,18 +0,0 @@ -pub(crate) use main_game_lib::prelude::*; - -pub(crate) use crate::{Building1PlayerFloor, Building1PlayerFloorAction}; - -/// This means that the meditation game will not start until the loading screen -/// has been shown for at least this long, plus it takes some time for the -/// fading to happen. -pub(crate) const WHEN_ENTERING_MEDITATION_SHOW_LOADING_IMAGE_FOR_AT_LEAST: - Duration = from_millis(1500); -/// Hard coded to make the animation play out. -pub(crate) const WINNIE_IN_BATHROOM_TRANSITION_FOR_AT_LEAST: Duration = - from_millis(3500); - -/// 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/Cargo.toml b/scenes/clinic/Cargo.toml deleted file mode 100644 index dbcbf962..00000000 --- a/scenes/clinic/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "scene_clinic" -version.workspace = true -edition.workspace = true - - -[features] -devtools = [ - "main_game_lib/devtools", - "common_story/devtools", - "common_visuals/devtools", -] - - -[dependencies] -bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true -bevy.workspace = true -common_action.workspace = true -common_assets.workspace = true -common_loading_screen.workspace = true -common_store.workspace = true -common_story.workspace = true -common_visuals.workspace = true -itertools.workspace = true -lazy_static.workspace = true -main_game_lib.workspace = true -rand.workspace = true -serde.workspace = true -smallvec.workspace = true -strum.workspace = true diff --git a/scenes/clinic/README.md b/scenes/clinic/README.md deleted file mode 100644 index d4f7d2d2..00000000 --- a/scenes/clinic/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Indoors clinic scene. - -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/clinic/src/lib.rs b/scenes/clinic/src/lib.rs deleted file mode 100644 index 22a66bc8..00000000 --- a/scenes/clinic/src/lib.rs +++ /dev/null @@ -1,126 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![feature(trivial_bounds)] -#![feature(let_chains)] - -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -use crate::layout::LayoutEntity; - -/// Important scene struct. -/// We use it as identifiable generic in common logic. -#[derive(TypePath, Default, Debug)] -pub struct Clinic; - -impl TopDownScene for Clinic {} - -impl main_game_lib::rscn::TscnInBevy for Clinic { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString)] -pub enum ClinicAction { - ExitScene, -} - -pub fn add(app: &mut App) { - info!("Adding {Clinic:?} to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins(layout::Plugin); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added {Clinic:?} to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {Clinic:?}"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving {Clinic:?}"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - ClinicToDowntown => { - next_state.set(WhichTopDownScene::Downtown.loading()); - } - _ => { - unreachable!("Invalid {Clinic:?} transition {transition:?}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = - include_str!("../../../main_game/assets/scenes/clinic.tscn"); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/clinic/src/prelude.rs b/scenes/clinic/src/prelude.rs deleted file mode 100644 index 8c0e8cb7..00000000 --- a/scenes/clinic/src/prelude.rs +++ /dev/null @@ -1,5 +0,0 @@ -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/Cargo.toml b/scenes/clinic_ward/Cargo.toml deleted file mode 100644 index 9abaa305..00000000 --- a/scenes/clinic_ward/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "scene_clinic_ward" -version.workspace = true -edition.workspace = true - - -[features] -devtools = [ - "main_game_lib/devtools", - "common_story/devtools", - "common_visuals/devtools", -] - - -[dependencies] -bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true -bevy.workspace = true -common_action.workspace = true -common_assets.workspace = true -common_loading_screen.workspace = true -common_store.workspace = true -common_story.workspace = true -common_visuals.workspace = true -itertools.workspace = true -lazy_static.workspace = true -main_game_lib.workspace = true -rand.workspace = true -serde.workspace = true -smallvec.workspace = true -strum.workspace = true diff --git a/scenes/clinic_ward/README.md b/scenes/clinic_ward/README.md deleted file mode 100644 index ddbd3136..00000000 --- a/scenes/clinic_ward/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Bottom floor of the clinic building. - -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/clinic_ward/src/lib.rs b/scenes/clinic_ward/src/lib.rs deleted file mode 100644 index b78dead8..00000000 --- a/scenes/clinic_ward/src/lib.rs +++ /dev/null @@ -1,126 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![feature(trivial_bounds)] -#![feature(let_chains)] - -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -use crate::layout::LayoutEntity; - -/// Important scene struct. -/// We use it as identifiable generic in common logic. -#[derive(TypePath, Default, Debug)] -pub struct ClinicWard; - -impl TopDownScene for ClinicWard {} - -impl main_game_lib::rscn::TscnInBevy for ClinicWard { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] -pub enum ClinicWardAction { - ExitScene, -} - -pub fn add(app: &mut App) { - info!("Adding {ClinicWard:?} to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins(layout::Plugin); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added {ClinicWard:?} to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {ClinicWard:?}"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving {ClinicWard:?}"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - ClinicWardToDowntown => { - next_state.set(WhichTopDownScene::Downtown.loading()); - } - _ => { - unreachable!("Invalid {ClinicWard:?} transition {transition:?}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = - include_str!("../../../main_game/assets/scenes/clinic_ward.tscn"); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/clinic_ward/src/prelude.rs b/scenes/clinic_ward/src/prelude.rs deleted file mode 100644 index 7aa5edf7..00000000 --- a/scenes/clinic_ward/src/prelude.rs +++ /dev/null @@ -1,5 +0,0 @@ -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/Cargo.toml b/scenes/compound/Cargo.toml deleted file mode 100644 index 4ce8fd8b..00000000 --- a/scenes/compound/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "scene_compound" -version.workspace = true -edition.workspace = true - - -[features] -devtools = [ - "main_game_lib/devtools", - "common_story/devtools", - "common_visuals/devtools", -] - - -[dependencies] -bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true -bevy.workspace = true -common_action.workspace = true -common_assets.workspace = true -common_loading_screen.workspace = true -common_store.workspace = true -common_story.workspace = true -common_visuals.workspace = true -itertools.workspace = true -lazy_static.workspace = true -main_game_lib.workspace = true -rand.workspace = true -serde.workspace = true -smallvec.workspace = true -strum.workspace = true diff --git a/scenes/compound/README.md b/scenes/compound/README.md deleted file mode 100644 index 55a43732..00000000 --- a/scenes/compound/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Compound outdoors scene. - -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/compound/src/lib.rs b/scenes/compound/src/lib.rs deleted file mode 100644 index 79254e24..00000000 --- a/scenes/compound/src/lib.rs +++ /dev/null @@ -1,131 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![allow(clippy::too_many_arguments)] -#![feature(trivial_bounds)] -#![feature(let_chains)] - -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -use crate::layout::LayoutEntity; - -/// Important scene struct. -/// We use it as identifiable generic in common logic. -#[derive(TypePath, Default, Debug)] -pub struct Compound; - -impl TopDownScene for Compound {} - -impl main_game_lib::rscn::TscnInBevy for Compound { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] -pub enum CompoundAction { - GoToDowntown, - EnterTower, -} - -pub fn add(app: &mut App) { - info!("Adding {Compound:?} to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins(layout::Plugin); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added {Compound:?} to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {Compound:?}"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving {Compound:?}"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - CompoundToDowntown => { - next_state.set(WhichTopDownScene::Downtown.loading()); - } - CompoundToTower => { - next_state.set(WhichTopDownScene::CompoundTower.loading()); - } - _ => { - unreachable!("Invalid {Compound:?} transition {transition:?}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = - include_str!("../../../main_game/assets/scenes/clinic_ward.tscn"); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/compound/src/prelude.rs b/scenes/compound/src/prelude.rs deleted file mode 100644 index f363bd01..00000000 --- a/scenes/compound/src/prelude.rs +++ /dev/null @@ -1,5 +0,0 @@ -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/Cargo.toml b/scenes/compound_tower/Cargo.toml deleted file mode 100644 index 974da3d7..00000000 --- a/scenes/compound_tower/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "scene_compound_tower" -version.workspace = true -edition.workspace = true - - -[features] -devtools = [ - "main_game_lib/devtools", - "common_story/devtools", - "common_visuals/devtools", -] - - -[dependencies] -bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true -bevy.workspace = true -common_action.workspace = true -common_assets.workspace = true -common_loading_screen.workspace = true -common_store.workspace = true -common_story.workspace = true -common_visuals.workspace = true -itertools.workspace = true -lazy_static.workspace = true -main_game_lib.workspace = true -rand.workspace = true -serde.workspace = true -smallvec.workspace = true -strum.workspace = true diff --git a/scenes/compound_tower/README.md b/scenes/compound_tower/README.md deleted file mode 100644 index 84d33f14..00000000 --- a/scenes/compound_tower/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Indoors tower in the compound. - -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/compound_tower/src/lib.rs b/scenes/compound_tower/src/lib.rs deleted file mode 100644 index 8ff28432..00000000 --- a/scenes/compound_tower/src/lib.rs +++ /dev/null @@ -1,127 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![feature(trivial_bounds)] -#![feature(let_chains)] - -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -use crate::layout::LayoutEntity; - -/// Important scene struct. -/// We use it as identifiable generic in common logic. -#[derive(TypePath, Default, Debug)] -pub struct CompoundTower; - -impl TopDownScene for CompoundTower {} - -impl main_game_lib::rscn::TscnInBevy for CompoundTower { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] -pub enum CompoundTowerAction { - ExitScene, -} - -pub fn add(app: &mut App) { - info!("Adding {CompoundTower:?} to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins(layout::Plugin); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added {CompoundTower:?} to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {CompoundTower:?}"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving {CompoundTower:?}"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - TowerToCompound => { - next_state.set(WhichTopDownScene::Compound.loading()); - } - _ => { - unreachable!("Invalid {CompoundTower:?} transition {transition:?}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = include_str!( - "../../../main_game/assets/scenes/compound_tower.tscn" - ); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/compound_tower/src/prelude.rs b/scenes/compound_tower/src/prelude.rs deleted file mode 100644 index 18c620b8..00000000 --- a/scenes/compound_tower/src/prelude.rs +++ /dev/null @@ -1,6 +0,0 @@ -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/README.md b/scenes/downtown/README.md deleted file mode 100644 index a0344fbb..00000000 --- a/scenes/downtown/README.md +++ /dev/null @@ -1 +0,0 @@ -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/downtown/src/lib.rs b/scenes/downtown/src/lib.rs deleted file mode 100644 index d3d16a98..00000000 --- a/scenes/downtown/src/lib.rs +++ /dev/null @@ -1,151 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![allow(clippy::too_many_arguments)] - -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -/// Important scene struct. -/// We use it as identifiable generic in some common logic such as layout or -/// asset. -#[derive(TypePath, Default)] -pub(crate) struct Downtown; - -impl TopDownScene for Downtown {} - -impl main_game_lib::rscn::TscnInBevy for Downtown { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString, Eq, PartialEq)] -pub enum DowntownAction { - EnterBuilding1, - EnterTwinpeaksApartment, - EnterSewers, - EnterMall, - EnterCompound, - EnterClinic, - EnterClinicWard, - EnterPlantShop, -} - -pub fn add(app: &mut App) { - info!("Adding downtown to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins(layout::Plugin); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added downtown to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering downtown"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving downtown"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - DowntownToBuilding1PlayerFloor => { - next_state.set(WhichTopDownScene::Building1PlayerFloor.loading()); - } - DowntownToMall => { - next_state.set(WhichTopDownScene::Mall.loading()); - } - DowntownToCompound => { - next_state.set(WhichTopDownScene::Compound.loading()); - } - DowntownToClinic => { - next_state.set(WhichTopDownScene::Clinic.loading()); - } - DowntownToClinicWard => { - next_state.set(WhichTopDownScene::ClinicWard.loading()); - } - DowntownToPlantShop => { - next_state.set(WhichTopDownScene::PlantShop.loading()); - } - DowntownToSewers => { - next_state.set(WhichTopDownScene::Sewers.loading()); - } - DowntownToTwinpeaksApartment => { - next_state.set(WhichTopDownScene::TwinpeaksApartment.loading()); - } - _ => { - unreachable!("Invalid Downtown transition {transition:?}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = - include_str!("../../../main_game/assets/scenes/downtown.tscn",); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/downtown/src/prelude.rs b/scenes/downtown/src/prelude.rs deleted file mode 100644 index 450c3ce2..00000000 --- a/scenes/downtown/src/prelude.rs +++ /dev/null @@ -1,5 +0,0 @@ -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/Cargo.toml b/scenes/mall/Cargo.toml deleted file mode 100644 index 2f20c6ad..00000000 --- a/scenes/mall/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "scene_mall" -version.workspace = true -edition.workspace = true - - -[features] -devtools = [ - "main_game_lib/devtools", - "common_story/devtools", - "common_visuals/devtools", -] - - -[dependencies] -bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true -bevy.workspace = true -common_action.workspace = true -common_assets.workspace = true -common_loading_screen.workspace = true -common_store.workspace = true -common_story.workspace = true -common_visuals.workspace = true -itertools.workspace = true -lazy_static.workspace = true -main_game_lib.workspace = true -rand.workspace = true -serde.workspace = true -smallvec.workspace = true -strum.workspace = true diff --git a/scenes/mall/README.md b/scenes/mall/README.md deleted file mode 100644 index 1ab5f232..00000000 --- a/scenes/mall/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Mall is a scene where we only allow cat NPCs. - -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/mall/src/lib.rs b/scenes/mall/src/lib.rs deleted file mode 100644 index 1b0b56e7..00000000 --- a/scenes/mall/src/lib.rs +++ /dev/null @@ -1,127 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![feature(trivial_bounds)] -#![feature(let_chains)] - -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -use crate::layout::LayoutEntity; - -/// Important scene struct. -/// We use it as identifiable generic in common logic. -#[derive(TypePath, Default, Debug)] -pub struct Mall; - -impl TopDownScene for Mall {} - -impl main_game_lib::rscn::TscnInBevy for Mall { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString)] -pub enum MallAction { - ExitScene, - StartGingerCatDialog, -} - -pub fn add(app: &mut App) { - info!("Adding {Mall:?} to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins(layout::Plugin); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added {Mall:?} to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {Mall:?}"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving {Mall:?}"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - MallToDowntown => { - next_state.set(WhichTopDownScene::Downtown.loading()); - } - _ => { - unreachable!("Invalid {Mall:?} transition {transition:?}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = - include_str!("../../../main_game/assets/scenes/mall.tscn",); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/mall/src/prelude.rs b/scenes/mall/src/prelude.rs deleted file mode 100644 index 41f6fe6c..00000000 --- a/scenes/mall/src/prelude.rs +++ /dev/null @@ -1,5 +0,0 @@ -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/plant_shop/Cargo.toml b/scenes/plant_shop/Cargo.toml deleted file mode 100644 index ee54f3d2..00000000 --- a/scenes/plant_shop/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "scene_plant_shop" -version.workspace = true -edition.workspace = true - - -[features] -devtools = [ - "main_game_lib/devtools", - "common_story/devtools", - "common_visuals/devtools", -] - - -[dependencies] -bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true -bevy.workspace = true -common_action.workspace = true -common_assets.workspace = true -common_loading_screen.workspace = true -common_store.workspace = true -common_story.workspace = true -common_visuals.workspace = true -itertools.workspace = true -lazy_static.workspace = true -main_game_lib.workspace = true -rand.workspace = true -serde.workspace = true -smallvec.workspace = true -strum.workspace = true diff --git a/scenes/plant_shop/README.md b/scenes/plant_shop/README.md deleted file mode 100644 index b4060e13..00000000 --- a/scenes/plant_shop/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Indoors plant shop scene. - -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/plant_shop/src/lib.rs b/scenes/plant_shop/src/lib.rs deleted file mode 100644 index 238272a9..00000000 --- a/scenes/plant_shop/src/lib.rs +++ /dev/null @@ -1,126 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![feature(trivial_bounds)] -#![feature(let_chains)] - -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -use crate::layout::LayoutEntity; - -/// Important scene struct. -/// We use it as identifiable generic in common logic. -#[derive(TypePath, Default, Debug)] -pub struct PlantShop; - -impl TopDownScene for PlantShop {} - -impl main_game_lib::rscn::TscnInBevy for PlantShop { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] -pub enum PlantShopAction { - ExitScene, -} - -pub fn add(app: &mut App) { - info!("Adding {PlantShop:?} to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins(layout::Plugin); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added {PlantShop:?} to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {PlantShop:?}"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving {PlantShop:?}"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - PlantShopToDowntown => { - next_state.set(WhichTopDownScene::Downtown.loading()); - } - _ => { - unreachable!("Invalid {PlantShop:?} transition {transition:?}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = - include_str!("../../../main_game/assets/scenes/plant_shop.tscn"); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/plant_shop/src/prelude.rs b/scenes/plant_shop/src/prelude.rs deleted file mode 100644 index 09a8cd56..00000000 --- a/scenes/plant_shop/src/prelude.rs +++ /dev/null @@ -1,5 +0,0 @@ -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/Cargo.toml b/scenes/sewers/Cargo.toml deleted file mode 100644 index 1073104a..00000000 --- a/scenes/sewers/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "scene_sewers" -version.workspace = true -edition.workspace = true - - -[features] -devtools = [ - "main_game_lib/devtools", - "common_story/devtools", - "common_visuals/devtools", -] - - -[dependencies] -bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true -bevy.workspace = true -common_action.workspace = true -common_assets.workspace = true -common_loading_screen.workspace = true -common_store.workspace = true -common_story.workspace = true -common_visuals.workspace = true -itertools.workspace = true -lazy_static.workspace = true -main_game_lib.workspace = true -rand.workspace = true -serde.workspace = true -smallvec.workspace = true -strum.workspace = true diff --git a/scenes/sewers/README.md b/scenes/sewers/README.md deleted file mode 100644 index e93af424..00000000 --- a/scenes/sewers/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Sewers are accessible through manholes. - -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/sewers/src/lib.rs b/scenes/sewers/src/lib.rs deleted file mode 100644 index 2cbb8075..00000000 --- a/scenes/sewers/src/lib.rs +++ /dev/null @@ -1,126 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![feature(trivial_bounds)] -#![feature(let_chains)] - -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -use crate::layout::LayoutEntity; - -/// Important scene struct. -/// We use it as identifiable generic in common logic. -#[derive(TypePath, Default, Debug)] -pub struct Sewers; - -impl TopDownScene for Sewers {} - -impl main_game_lib::rscn::TscnInBevy for Sewers { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString)] -pub enum SewersAction { - ExitScene, -} - -pub fn add(app: &mut App) { - info!("Adding {Sewers:?} to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins(layout::Plugin); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added {Sewers:?} to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {Sewers:?}"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving {Sewers:?}"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - SewersToDowntown => { - next_state.set(WhichTopDownScene::Downtown.loading()); - } - _ => { - unreachable!("Invalid {Sewers:?} transition {transition:?}"); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = - include_str!("../../../main_game/assets/scenes/sewers.tscn"); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/sewers/src/prelude.rs b/scenes/sewers/src/prelude.rs deleted file mode 100644 index e9064cbb..00000000 --- a/scenes/sewers/src/prelude.rs +++ /dev/null @@ -1,5 +0,0 @@ -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/downtown/Cargo.toml b/scenes/top_down/Cargo.toml similarity index 70% rename from scenes/downtown/Cargo.toml rename to scenes/top_down/Cargo.toml index a12cfad9..c6586cd2 100644 --- a/scenes/downtown/Cargo.toml +++ b/scenes/top_down/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "scene_downtown" +name = "scene_top_down" version.workspace = true edition.workspace = true @@ -14,14 +14,10 @@ devtools = [ [dependencies] bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true bevy.workspace = true -common_assets.workspace = true common_loading_screen.workspace = true -common_store.workspace = true common_story.workspace = true common_visuals.workspace = true -lazy_static.workspace = true main_game_lib.workspace = true -serde.workspace = true +rand.workspace = true strum.workspace = true diff --git a/scenes/top_down/README.md b/scenes/top_down/README.md new file mode 100644 index 00000000..b1872911 --- /dev/null +++ b/scenes/top_down/README.md @@ -0,0 +1,3 @@ +Adds all top down scenes to the game. +Lots of the top down scene logic is in the `main_game_lib` crate because it tends to be referenced also by other systems. +In package we have scene specific logic rather than the shared one. diff --git a/scenes/building1_basement1/src/layout.rs b/scenes/top_down/src/building1_basement1.rs similarity index 75% rename from scenes/building1_basement1/src/layout.rs rename to scenes/top_down/src/building1_basement1.rs index 007254ac..14aa86fd 100644 --- a/scenes/building1_basement1/src/layout.rs +++ b/scenes/top_down/src/building1_basement1.rs @@ -1,39 +1,42 @@ -mod watch_entry_to_apartment; - -use bevy::render::view::RenderLayers; -use bevy_grid_squared::sq; -use common_loading_screen::LoadingScreenSettings; -use common_visuals::camera::{render_layer, MainCamera}; +use common_visuals::BeginInterpolationEvent; use main_game_lib::{ - common_ext::QueryExt, cutscene::{ - self, enter_an_elevator::{ start_with_open_elevator_and_close_it, STEP_TIME_ON_EXIT_ELEVATOR, }, enter_dark_door::EnterDarkDoor, - in_cutscene, IntoCutscene, }, - dialog::DialogGraph, top_down::{ - actor::{self, movement_event_emitted, player::TakeAwayPlayerControl}, - environmental_objects::{self, door::DoorBuilder}, - scene_configs::ZoneTileKind, + actor::Who, environmental_objects::door::DoorBuilder, + ActorMovementEvent, }, }; -use rscn::{NodeName, TscnSpawner, TscnTree, TscnTreeHandle}; -use top_down::{ - actor::{CharacterBundleBuilder, CharacterExt}, - inspect_and_interact::ZoneToInspectLabelEntity, - TileMap, -}; use crate::prelude::*; +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Building1Basement1; + pub(crate) struct Plugin; +#[derive(TypePath, Default, Debug)] +struct Building1Basement1; + +impl main_game_lib::rscn::TscnInBevy for Building1Basement1 { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString, Eq, PartialEq)] +enum Building1Basement1Action { + EnterElevator, + EnterBasement2, +} + impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -48,13 +51,6 @@ impl bevy::app::Plugin for Plugin { ), ) .add_systems(OnExit(THIS_SCENE.leaving()), despawn) - .add_systems( - Update, - environmental_objects::door::toggle - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(movement_event_emitted()) - .after(actor::emit_movement_events), - ) .add_systems( Update, enter_the_elevator @@ -75,7 +71,7 @@ impl bevy::app::Plugin for Plugin { ) .add_systems( Update, - watch_entry_to_apartment::system + watch_entry_to_apartment .run_if(in_scene_running_state(THIS_SCENE)) .run_if(movement_event_emitted()) .after(actor::emit_movement_events), @@ -83,22 +79,18 @@ impl bevy::app::Plugin for Plugin { } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; /// Elevator is a special entity that has a sprite sheet with several frames. /// It opens when an actor is near it and closes when the actor leaves or /// enters. #[derive(Component)] -pub(crate) struct Elevator; +struct Elevator; /// The door sprite that leads to the storage basement. #[derive(Component)] -pub(crate) struct DoorToStorageBasement; +struct DoorToStorageBasement; /// There's a wall that separates an apartment from the hallway. /// This door gets hidden when the player is near or in the apartment. #[derive(Component)] -pub(crate) struct ApartmentWall; +struct ApartmentWall; struct Spawner<'a> { transition: GlobalGameStateTransition, @@ -313,3 +305,63 @@ fn enter_basement2( } .spawn(&mut cmd); } + +/// How long does it take for the entity to go transparent +const WALL_FADE_OUT_TRANSITION_DURATION: Duration = from_millis(500); +/// How long does it take for the entity to go to its full color. +const WALL_FADE_IN_TRANSITION_DURATION: Duration = from_millis(1500); + +/// Listens to events about entering the +/// [`ZoneTileKind::UpperApartmentWallHidden`]. +/// +/// When entered, the [`ApartmentWall`] entity is hidden. +fn watch_entry_to_apartment( + mut movement_events: EventReader, + mut lerp_event: EventWriter, + + wall: Query>, +) { + use ZoneTileKind::UpperApartmentWallHidden as TheZone; + + for event in movement_events.read() { + match event { + ActorMovementEvent::ZoneEntered { + who: + Who { + is_player: true, .. + }, + zone: TileKind::Zone(TheZone), + } => { + trace!("Hiding apartment wall"); + lerp_event.send( + BeginInterpolationEvent::of_color( + wall.single(), + None, + Color::NONE, + ) + .over(WALL_FADE_OUT_TRANSITION_DURATION), + ); + } + ActorMovementEvent::ZoneLeft { + who: + Who { + is_player: true, .. + }, + zone: TileKind::Zone(TheZone), + } => { + trace!("Showing apartment wall"); + lerp_event.send( + BeginInterpolationEvent::of_color( + wall.single(), + None, + Color::WHITE, + ) + .over(WALL_FADE_IN_TRANSITION_DURATION), + ); + } + + // we don't care about other events + _ => {} + } + } +} diff --git a/scenes/building1_basement2/src/layout.rs b/scenes/top_down/src/building1_basement2.rs similarity index 91% rename from scenes/building1_basement2/src/layout.rs rename to scenes/top_down/src/building1_basement2.rs index 91ffb9c7..64429639 100644 --- a/scenes/building1_basement2/src/layout.rs +++ b/scenes/top_down/src/building1_basement2.rs @@ -14,10 +14,28 @@ use top_down::{ use crate::prelude::*; +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Building1Basement2; + +#[derive(TypePath, Default, Debug)] +struct Building1Basement2; + +impl main_game_lib::rscn::TscnInBevy for Building1Basement2 { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString)] +enum Building1Basement2Action { + Exit, +} + pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -41,13 +59,9 @@ impl bevy::app::Plugin for Plugin { } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; /// The door sprite that leads to the storage basement. #[derive(Component)] -pub(crate) struct DoorToStorageBasement; +struct DoorToStorageBasement; struct Spawner<'a> { player_entity: Entity, diff --git a/scenes/building1_player_floor/src/layout.rs b/scenes/top_down/src/building1_player_floor.rs similarity index 53% rename from scenes/building1_player_floor/src/layout.rs rename to scenes/top_down/src/building1_player_floor.rs index 89429f84..d7467c4d 100644 --- a/scenes/building1_player_floor/src/layout.rs +++ b/scenes/top_down/src/building1_player_floor.rs @@ -2,14 +2,27 @@ mod watch_entry_to_hallway; use bevy::render::view::RenderLayers; use bevy_grid_squared::{sq, GridDirection}; +use common_story::emoji::{ + DisplayEmojiEvent, DisplayEmojiEventConsumer, EmojiKind, +}; use common_visuals::camera::render_layer; use main_game_lib::{ - cutscene::enter_an_elevator::{ - start_with_open_elevator_and_close_it, STEP_TIME_ON_EXIT_ELEVATOR, + cutscene::{ + enter_an_elevator::{ + start_with_open_elevator_and_close_it, STEP_TIME_ON_EXIT_ELEVATOR, + }, + CutsceneStep, }, - hud::daybar::UpdateDayBarEvent, + hud::daybar::{DayBar, UpdateDayBarEvent}, top_down::{ - actor::player::TakeAwayPlayerControl, scene_configs::ZoneTileKind, + actor::{emit_movement_events, player::TakeAwayPlayerControl}, + inspect_and_interact::{ + ChangeHighlightedInspectLabelEvent, + ChangeHighlightedInspectLabelEventConsumer, + SpawnLabelBgAndTextParams, LIGHT_RED, + }, + scene_configs::ZoneTileKind, + ActorMovementEvent, }, }; use rscn::{NodeName, TscnSpawner, TscnTree, TscnTreeHandle}; @@ -17,10 +30,7 @@ use top_down::{ actor::{ self, movement_event_emitted, CharacterBundleBuilder, CharacterExt, }, - environmental_objects::{ - self, - door::{DoorBuilder, DoorOpenCriteria, DoorState}, - }, + environmental_objects::door::{DoorBuilder, DoorOpenCriteria, DoorState}, inspect_and_interact::ZoneToInspectLabelEntity, layout::LAYOUT, ActorTarget, TileMap, @@ -28,10 +38,68 @@ use top_down::{ use crate::prelude::*; +/// This means that the meditation game will not start until the loading screen +/// has been shown for at least this long, plus it takes some time for the +/// fading to happen. +const WHEN_ENTERING_MEDITATION_SHOW_LOADING_IMAGE_FOR_AT_LEAST: Duration = + from_millis(1500); +/// Hard coded to make the animation play out. +const WINNIE_IN_BATHROOM_TRANSITION_FOR_AT_LEAST: Duration = from_millis(3500); + +/// Walk down slowly otherwise it'll happen before the player even sees it. +const STEP_TIME_ONLOAD_FROM_MEDITATION: Duration = from_millis(750); + +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Building1PlayerFloor; + +#[derive(TypePath, Default, Debug)] +struct Building1PlayerFloor; + +impl main_game_lib::rscn::TscnInBevy for Building1PlayerFloor { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] +enum Building1PlayerFloorAction { + EnterElevator, + StartMeditation, + Sleep, + BrewTea, +} + pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + + app.add_systems( + Update, + ( + start_meditation_minigame.run_if(on_event_variant( + Building1PlayerFloorAction::StartMeditation, + )), + sleep.run_if(on_event_variant( + Building1PlayerFloorAction::Sleep, + )), + enter_the_elevator.run_if(on_event_variant( + Building1PlayerFloorAction::EnterElevator, + )), + ) + .before(DisplayEmojiEventConsumer) + .before(ChangeHighlightedInspectLabelEventConsumer) + .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(in_scene_running_state(THIS_SCENE)) + .after(emit_movement_events), + ); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -48,10 +116,7 @@ impl bevy::app::Plugin for Plugin { .add_systems(OnExit(THIS_SCENE.leaving()), despawn) .add_systems( Update, - ( - watch_entry_to_hallway::system, - environmental_objects::door::toggle, - ) + watch_entry_to_hallway::system .run_if(in_scene_running_state(THIS_SCENE)) .run_if(movement_event_emitted()) .after(actor::emit_movement_events), @@ -59,26 +124,22 @@ impl bevy::app::Plugin for Plugin { } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; /// Hallway is darkened when the player is in the apartment but once the player /// approaches the door or is in the hallway, it's lit up. #[derive(Component)] -pub(crate) struct HallwayEntity; +struct HallwayEntity; /// Elevator is a special entity that has a sprite sheet with several frames. /// It opens when an actor is near it and closes when the actor leaves or /// enters. #[derive(Component)] -pub(crate) struct Elevator; +struct Elevator; /// Assigned to a sprite that shows Winnie meditating in the chair. /// This sprite is hidden by default. #[derive(Component)] -pub(crate) struct MeditatingHint; +struct MeditatingHint; /// Same as [`MeditatingHint`] but for the bed. #[derive(Component)] -pub(crate) struct SleepingHint; +struct SleepingHint; struct Spawner<'a> { transition: GlobalGameStateTransition, @@ -93,6 +154,7 @@ struct Spawner<'a> { /// The names are stored in the scene file. /// See Godot scene file for details. +#[allow(clippy::too_many_arguments)] fn spawn( mut cmd: Commands, transition: Res, @@ -297,3 +359,169 @@ impl<'a> TscnSpawner for Spawner<'a> { self.zone_to_inspect_label_entity.insert(zone, entity); } } + +/// Will change the game state to meditation minigame. +fn start_meditation_minigame( + mut cmd: Commands, + mut emoji_events: EventWriter, + mut inspect_label_events: EventWriter, + zone_to_inspect_label_entity: Res, + daybar: Res, + + player: Query>, +) { + if daybar.is_depleted() { + if let Some(entity) = zone_to_inspect_label_entity + .get(ZoneTileKind::Meditation) + .copied() + { + inspect_label_events.send(ChangeHighlightedInspectLabelEvent { + entity, + spawn_params: SpawnLabelBgAndTextParams { + highlighted: true, + overwrite_font_color: Some(LIGHT_RED), + // LOCALIZATION + overwrite_display_text: Some("(too tired)".to_string()), + }, + }); + } else { + error!("Cannot find meditation zone inspect label entity"); + } + + if let Some(on_parent) = player.get_single_or_none() { + emoji_events.send(DisplayEmojiEvent { + emoji: EmojiKind::Tired, + on_parent, + offset_for: common_story::Character::Winnie, + }); + } else { + error!("Cannot find player entity"); + } + } else { + let Some(player) = player.get_single_or_none() else { + return; + }; + + vec![ + CutsceneStep::TakeAwayPlayerControl(player), + CutsceneStep::ChangeGlobalState { + to: THIS_SCENE.leaving(), + with: + GlobalGameStateTransition::Building1PlayerFloorToMeditation, + }, + CutsceneStep::StartLoadingScreen { + settings: Some(LoadingScreenSettings { + atlas: Some(common_loading_screen::LoadingScreenAtlas::Space), + stare_at_loading_screen_for_at_least: Some( + WHEN_ENTERING_MEDITATION_SHOW_LOADING_IMAGE_FOR_AT_LEAST, + ), + ..default() + }) + } + ].spawn(&mut cmd); + } +} + +/// By entering the elevator, the player can leave this scene. +fn enter_the_elevator( + mut cmd: Commands, + mut assets: ResMut>, + + player: Query>, + elevator: Query>, + camera: Query>, + points: Query<(&Name, &rscn::Point)>, +) { + use GlobalGameStateTransition::*; + + if let Some(player) = player.get_single_or_none() { + let point_in_elevator = { + let (_, rscn::Point(pos)) = points + .iter() + .find(|(name, _)| **name == Name::new("InElevator")) + .expect("InElevator point not found"); + + *pos + }; + + cutscene::enter_an_elevator::spawn( + &mut cmd, + &mut assets, + player, + elevator.single(), + camera.single(), + point_in_elevator, + // LOCALIZATION + &[ + (Building1PlayerFloorToDowntown, "go to downtown"), + (Building1PlayerFloorToBuilding1Basement1, "go to basement"), + ], + ); + } +} + +/// Shows hint for bed or for meditating when player is in the zone to actually +/// interact with those objects. +fn toggle_zone_hints( + mut events: EventReader, + + mut sleeping: Query< + &mut Visibility, + (With, Without), + >, + mut meditating: Query< + &mut Visibility, + (With, Without), + >, +) { + use ZoneTileKind::{Bed, Meditation}; + + for event in events.read().filter(|event| event.is_player()) { + match event { + ActorMovementEvent::ZoneEntered { zone, .. } => match *zone { + TileKind::Zone(Meditation) => { + *meditating.single_mut() = Visibility::Visible; + } + TileKind::Zone(Bed) => { + *sleeping.single_mut() = Visibility::Visible; + } + _ => {} + }, + ActorMovementEvent::ZoneLeft { zone, .. } => match *zone { + TileKind::Zone(Meditation) => { + *meditating.single_mut() = Visibility::Hidden; + } + TileKind::Zone(Bed) => { + *sleeping.single_mut() = Visibility::Hidden; + } + _ => {} + }, + } + } +} + +fn sleep(mut cmd: Commands, player: Query>) { + let Some(player) = player.get_single_or_none() else { + return; + }; + + vec![ + CutsceneStep::TakeAwayPlayerControl(player), + CutsceneStep::ChangeGlobalState { + to: THIS_SCENE.leaving(), + with: GlobalGameStateTransition::Sleeping, + }, + CutsceneStep::StartLoadingScreen { + settings: Some(LoadingScreenSettings { + atlas: Some( + common_loading_screen::LoadingScreenAtlas::WinnieInBathroom, + ), + stare_at_loading_screen_for_at_least: Some( + WINNIE_IN_BATHROOM_TRANSITION_FOR_AT_LEAST, + ), + ..default() + }), + }, + ] + .spawn(&mut cmd); +} diff --git a/scenes/building1_player_floor/src/layout/watch_entry_to_hallway.rs b/scenes/top_down/src/building1_player_floor/watch_entry_to_hallway.rs similarity index 100% rename from scenes/building1_player_floor/src/layout/watch_entry_to_hallway.rs rename to scenes/top_down/src/building1_player_floor/watch_entry_to_hallway.rs diff --git a/scenes/clinic/src/layout.rs b/scenes/top_down/src/clinic.rs similarity index 89% rename from scenes/clinic/src/layout.rs rename to scenes/top_down/src/clinic.rs index e5657db4..31185459 100644 --- a/scenes/clinic/src/layout.rs +++ b/scenes/top_down/src/clinic.rs @@ -5,9 +5,7 @@ use main_game_lib::{ hud::notification::NotificationFifo, player_stats::PlayerStats, top_down::{ - actor::{self, movement_event_emitted}, - environmental_objects::{self, door::DoorBuilder}, - scene_configs::ZoneTileKind, + environmental_objects::door::DoorBuilder, scene_configs::ZoneTileKind, }, }; use rscn::{NodeName, TscnSpawner, TscnTree, TscnTreeHandle}; @@ -19,10 +17,28 @@ use top_down::{ use crate::prelude::*; +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Clinic; + +#[derive(TypePath, Default, Debug)] +struct Clinic; + +impl main_game_lib::rscn::TscnInBevy for Clinic { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString)] +enum ClinicAction { + ExitScene, +} + pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -40,22 +56,10 @@ impl bevy::app::Plugin for Plugin { exit.run_if(on_event::()) .run_if(in_scene_running_state(THIS_SCENE)) .run_if(not(in_cutscene())), - ) - .add_systems( - Update, - environmental_objects::door::toggle - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(movement_event_emitted()) - .after(actor::emit_movement_events), ); } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; - struct Spawner<'a> { player_entity: Entity, player_builder: &'a mut CharacterBundleBuilder, diff --git a/scenes/clinic_ward/src/layout.rs b/scenes/top_down/src/clinic_ward.rs similarity index 90% rename from scenes/clinic_ward/src/layout.rs rename to scenes/top_down/src/clinic_ward.rs index 9e541f97..67ea3179 100644 --- a/scenes/clinic_ward/src/layout.rs +++ b/scenes/top_down/src/clinic_ward.rs @@ -13,10 +13,28 @@ use top_down::{ use crate::prelude::*; +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::ClinicWard; + +#[derive(TypePath, Default, Debug)] +struct ClinicWard; + +impl main_game_lib::rscn::TscnInBevy for ClinicWard { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] +enum ClinicWardAction { + ExitScene, +} + pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -38,11 +56,6 @@ impl bevy::app::Plugin for Plugin { } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; - struct Spawner<'a> { player_entity: Entity, player_builder: &'a mut CharacterBundleBuilder, diff --git a/scenes/compound/src/layout.rs b/scenes/top_down/src/compound.rs similarity index 92% rename from scenes/compound/src/layout.rs rename to scenes/top_down/src/compound.rs index 3de03855..f6a5d8fc 100644 --- a/scenes/compound/src/layout.rs +++ b/scenes/top_down/src/compound.rs @@ -17,10 +17,29 @@ use top_down::{ use crate::prelude::*; +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Compound; + +#[derive(TypePath, Default, Debug)] +struct Compound; + +impl main_game_lib::rscn::TscnInBevy for Compound { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] +enum CompoundAction { + GoToDowntown, + EnterTower, +} + pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -47,11 +66,6 @@ impl bevy::app::Plugin for Plugin { } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; - struct Spawner<'a> { player_entity: Entity, player_builder: &'a mut CharacterBundleBuilder, @@ -64,6 +78,7 @@ struct Spawner<'a> { } /// The names are stored in the scene file. +#[allow(clippy::too_many_arguments)] fn spawn( mut cmd: Commands, asset_server: Res, diff --git a/scenes/compound_tower/src/layout.rs b/scenes/top_down/src/compound_tower.rs similarity index 90% rename from scenes/compound_tower/src/layout.rs rename to scenes/top_down/src/compound_tower.rs index 61db993c..bf7e7f6a 100644 --- a/scenes/compound_tower/src/layout.rs +++ b/scenes/top_down/src/compound_tower.rs @@ -13,10 +13,28 @@ use top_down::{ use crate::prelude::*; +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::CompoundTower; + +#[derive(TypePath, Default, Debug)] +struct CompoundTower; + +impl main_game_lib::rscn::TscnInBevy for CompoundTower { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] +enum CompoundTowerAction { + ExitScene, +} + pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -38,11 +56,6 @@ impl bevy::app::Plugin for Plugin { } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; - struct Spawner<'a> { player_entity: Entity, player_builder: &'a mut CharacterBundleBuilder, diff --git a/scenes/downtown/src/layout.rs b/scenes/top_down/src/downtown.rs similarity index 95% rename from scenes/downtown/src/layout.rs rename to scenes/top_down/src/downtown.rs index 7d5238b7..6a10cdfd 100644 --- a/scenes/downtown/src/layout.rs +++ b/scenes/top_down/src/downtown.rs @@ -28,10 +28,35 @@ use top_down::{ use crate::prelude::*; +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Downtown; + +#[derive(TypePath, Default)] +struct Downtown; + +impl main_game_lib::rscn::TscnInBevy for Downtown { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString, Eq, PartialEq)] +enum DowntownAction { + EnterBuilding1, + EnterTwinpeaksApartment, + EnterSewers, + EnterMall, + EnterCompound, + EnterClinic, + EnterClinicWard, + EnterPlantShop, +} + pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -72,11 +97,6 @@ impl bevy::app::Plugin for Plugin { } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; - struct Spawner<'a> { asset_server: &'a AssetServer, atlases: &'a mut Assets, @@ -96,6 +116,7 @@ struct Spawner<'a> { /// The names are stored in the scene file. /// See Godot scene file for details. +#[allow(clippy::too_many_arguments)] fn spawn( mut cmd: Commands, asset_server: Res, diff --git a/scenes/top_down/src/layout.rs b/scenes/top_down/src/layout.rs new file mode 100644 index 00000000..e836dc3d --- /dev/null +++ b/scenes/top_down/src/layout.rs @@ -0,0 +1,6 @@ +use crate::prelude::*; + +/// Assigned to the root of the scene. +/// We then recursively despawn it on scene leave. +#[derive(Component)] +pub(crate) struct LayoutEntity; diff --git a/scenes/top_down/src/lib.rs b/scenes/top_down/src/lib.rs new file mode 100644 index 00000000..187eca5a --- /dev/null +++ b/scenes/top_down/src/lib.rs @@ -0,0 +1,228 @@ +#![doc = include_str!("../README.md")] +#![allow(clippy::assertions_on_constants)] +#![allow(clippy::type_complexity)] +#![feature(trivial_bounds)] +#![feature(let_chains)] + +mod building1_basement1; +mod building1_basement2; +mod building1_player_floor; +mod clinic; +mod clinic_ward; +mod compound; +mod compound_tower; +mod downtown; +mod layout; +mod mall; +mod plant_shop; +mod prelude; +mod sewers; +mod twinpeaks_apartment; + +use common_loading_screen::LoadingScreenState; +use prelude::*; + +use crate::layout::LayoutEntity; + +pub fn add(app: &mut App) { + info!("Adding top down scenes to app"); + + debug!("Adding plugins"); + + app.add_plugins(( + building1_basement1::Plugin, + building1_basement2::Plugin, + building1_player_floor::Plugin, + clinic_ward::Plugin, + clinic::Plugin, + compound_tower::Plugin, + compound::Plugin, + downtown::Plugin, + mall::Plugin, + plant_shop::Plugin, + sewers::Plugin, + twinpeaks_apartment::Plugin, + )); + + debug!("Adding game loop"); + + // when everything is loaded, finish the loading process by transitioning + // to the next loading state + app.add_systems( + Last, + finish_when_everything_loaded + .run_if(in_top_down_loading_state()) + .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(in_top_down_loading_state()), + ); + + app.add_systems( + Update, + common_loading_screen::finish + .run_if(in_top_down_running_state()) + .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), + ); + + app.add_systems( + Update, + // 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(in_top_down_leaving_state()), + ); +} + +fn finish_when_everything_loaded( + mut next_loading_state: ResMut>, + map: Option>, +) { + if map.is_none() { + return; + } + + debug!("All assets loaded"); + + next_loading_state.set(common_loading_screen::finish_state()); +} + +fn enter_the_scene( + mut next_state: ResMut>, + scene: Res>, +) { + info!("Entering {}", **scene); + next_state.set(scene.running()); +} + +fn exit( + transition: Res, + mut next_state: ResMut>, + mut controls: ResMut>, + scene: Res>, +) { + info!("Leaving {}", **scene); + + // be a good guy and don't invade other game loops with "Enter" + controls.consume(&GlobalAction::Interact); + + use GlobalGameStateTransition::*; + match *transition { + Building1Basement1ToPlayerFloor => { + next_state.set(WhichTopDownScene::Building1PlayerFloor.loading()); + } + Building1Basement1ToDowntown => { + next_state.set(WhichTopDownScene::Downtown.loading()); + } + Building1Basement1ToBasement2 => { + next_state.set(WhichTopDownScene::Building1Basement2.loading()); + } + + Building1Basement2ToBasement1 => { + next_state.set(WhichTopDownScene::Building1Basement1.loading()); + } + + Building1PlayerFloorToBuilding1Basement1 => { + next_state.set(WhichTopDownScene::Building1Basement1.loading()); + } + Building1PlayerFloorToMeditation => { + next_state.set(GlobalGameState::LoadingMeditation); + } + Building1PlayerFloorToDowntown => { + next_state.set(WhichTopDownScene::Downtown.loading()); + } + Sleeping => { + next_state.set(WhichTopDownScene::Building1PlayerFloor.loading()); + } + + ClinicToDowntown => { + next_state.set(WhichTopDownScene::Downtown.loading()); + } + + ClinicWardToDowntown => { + next_state.set(WhichTopDownScene::Downtown.loading()); + } + + CompoundToDowntown => { + next_state.set(WhichTopDownScene::Downtown.loading()); + } + CompoundToTower => { + next_state.set(WhichTopDownScene::CompoundTower.loading()); + } + + SewersToDowntown => { + next_state.set(WhichTopDownScene::Downtown.loading()); + } + + PlantShopToDowntown => { + next_state.set(WhichTopDownScene::Downtown.loading()); + } + + TwinpeaksApartmentToDowntown => { + next_state.set(WhichTopDownScene::Downtown.loading()); + } + + TowerToCompound => { + next_state.set(WhichTopDownScene::Compound.loading()); + } + + MallToDowntown => { + next_state.set(WhichTopDownScene::Downtown.loading()); + } + + DowntownToBuilding1PlayerFloor => { + next_state.set(WhichTopDownScene::Building1PlayerFloor.loading()); + } + DowntownToMall => { + next_state.set(WhichTopDownScene::Mall.loading()); + } + DowntownToCompound => { + next_state.set(WhichTopDownScene::Compound.loading()); + } + DowntownToClinic => { + next_state.set(WhichTopDownScene::Clinic.loading()); + } + DowntownToClinicWard => { + next_state.set(WhichTopDownScene::ClinicWard.loading()); + } + DowntownToPlantShop => { + next_state.set(WhichTopDownScene::PlantShop.loading()); + } + DowntownToSewers => { + next_state.set(WhichTopDownScene::Sewers.loading()); + } + DowntownToTwinpeaksApartment => { + next_state.set(WhichTopDownScene::TwinpeaksApartment.loading()); + } + + _ => { + unreachable!("Invalid {} transition {transition:?}", **scene); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_has_valid_tscn_scenes() { + for entry in std::fs::read_dir("../../main_game/assets/scenes") + .expect("Cannot find scene assets") + { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_file() { + let path = path.to_str().unwrap(); + if path.ends_with(".tscn") { + let tscn = std::fs::read_to_string(path).unwrap(); + println!("Parsing {path:?}"); + rscn::parse(&tscn, &default()); + } + } + } + } +} diff --git a/scenes/mall/src/layout.rs b/scenes/top_down/src/mall.rs similarity index 93% rename from scenes/mall/src/layout.rs rename to scenes/top_down/src/mall.rs index 7dabf819..fea67038 100644 --- a/scenes/mall/src/layout.rs +++ b/scenes/top_down/src/mall.rs @@ -21,10 +21,29 @@ use top_down::{ use crate::prelude::*; +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Mall; + +#[derive(TypePath, Default, Debug)] +struct Mall; + +impl main_game_lib::rscn::TscnInBevy for Mall { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString)] +enum MallAction { + ExitScene, + StartGingerCatDialog, +} + pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -47,11 +66,6 @@ impl bevy::app::Plugin for Plugin { } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; - struct Spawner<'a> { white_cat_entity: Entity, white_cat_patrol_points: &'a mut Vec, diff --git a/scenes/plant_shop/src/layout.rs b/scenes/top_down/src/plant_shop.rs similarity index 92% rename from scenes/plant_shop/src/layout.rs rename to scenes/top_down/src/plant_shop.rs index 55a30ecb..4ed39b15 100644 --- a/scenes/plant_shop/src/layout.rs +++ b/scenes/top_down/src/plant_shop.rs @@ -13,10 +13,28 @@ use top_down::{ use crate::prelude::*; +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::PlantShop; + +#[derive(TypePath, Default, Debug)] +struct PlantShop; + +impl main_game_lib::rscn::TscnInBevy for PlantShop { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString, PartialEq, Eq)] +enum PlantShopAction { + ExitScene, +} + pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -38,11 +56,6 @@ impl bevy::app::Plugin for Plugin { } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; - struct Spawner<'a> { player_entity: Entity, player_builder: &'a mut CharacterBundleBuilder, diff --git a/scenes/top_down/src/prelude.rs b/scenes/top_down/src/prelude.rs new file mode 100644 index 00000000..8de0a68d --- /dev/null +++ b/scenes/top_down/src/prelude.rs @@ -0,0 +1,23 @@ +pub(crate) use bevy::render::view::RenderLayers; +pub(crate) use bevy_grid_squared::sq; +pub(crate) use common_loading_screen::LoadingScreenSettings; +pub(crate) use common_visuals::camera::{render_layer, MainCamera}; +pub(crate) use main_game_lib::{ + common_ext::QueryExt, + cutscene::{self, in_cutscene, IntoCutscene}, + dialog::DialogGraph, + prelude::*, + top_down::{ + actor::{self, movement_event_emitted, player::TakeAwayPlayerControl}, + scene_configs::ZoneTileKind, + TileKind, + }, +}; +pub(crate) use rscn::{NodeName, TscnSpawner, TscnTree, TscnTreeHandle}; +pub(crate) use top_down::{ + actor::{CharacterBundleBuilder, CharacterExt}, + inspect_and_interact::ZoneToInspectLabelEntity, + TileMap, +}; + +pub(crate) use crate::layout::LayoutEntity; diff --git a/scenes/sewers/src/layout.rs b/scenes/top_down/src/sewers.rs similarity index 92% rename from scenes/sewers/src/layout.rs rename to scenes/top_down/src/sewers.rs index ed13e0a5..39a4cb11 100644 --- a/scenes/sewers/src/layout.rs +++ b/scenes/top_down/src/sewers.rs @@ -13,10 +13,28 @@ use top_down::{ use crate::prelude::*; +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::Sewers; + +#[derive(TypePath, Default, Debug)] +pub struct Sewers; + +impl main_game_lib::rscn::TscnInBevy for Sewers { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString)] +pub enum SewersAction { + ExitScene, +} + pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -38,11 +56,6 @@ impl bevy::app::Plugin for Plugin { } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; - struct Spawner<'a> { cooper_entity: Entity, cooper_builder: &'a mut CharacterBundleBuilder, diff --git a/scenes/twinpeaks_apartment/src/layout.rs b/scenes/top_down/src/twinpeaks_apartment.rs similarity index 92% rename from scenes/twinpeaks_apartment/src/layout.rs rename to scenes/top_down/src/twinpeaks_apartment.rs index 4b2cb06f..e3b863ad 100644 --- a/scenes/twinpeaks_apartment/src/layout.rs +++ b/scenes/top_down/src/twinpeaks_apartment.rs @@ -13,10 +13,28 @@ use top_down::{ use crate::prelude::*; +const THIS_SCENE: WhichTopDownScene = WhichTopDownScene::TwinpeaksApartment; + +#[derive(TypePath, Default, Debug)] +struct TwinpeaksApartment; + +impl main_game_lib::rscn::TscnInBevy for TwinpeaksApartment { + fn tscn_asset_path() -> String { + format!("scenes/{}.tscn", THIS_SCENE.snake_case()) + } +} + +#[derive(Event, Reflect, Clone, strum::EnumString)] +enum TwinpeaksApartmentAction { + ExitScene, +} + pub(crate) struct Plugin; impl bevy::app::Plugin for Plugin { fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( OnEnter(THIS_SCENE.loading()), rscn::start_loading_tscn::, @@ -40,11 +58,6 @@ impl bevy::app::Plugin for Plugin { } } -/// Assigned to the root of the scene. -/// We then recursively despawn it on scene leave. -#[derive(Component)] -pub(crate) struct LayoutEntity; - struct Spawner<'a> { player_entity: Entity, player_builder: &'a mut CharacterBundleBuilder, diff --git a/scenes/twinpeaks_apartment/Cargo.toml b/scenes/twinpeaks_apartment/Cargo.toml deleted file mode 100644 index 5021f0ea..00000000 --- a/scenes/twinpeaks_apartment/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "scene_twinpeaks_apartment" -version.workspace = true -edition.workspace = true - - -[features] -devtools = [ - "main_game_lib/devtools", - "common_story/devtools", - "common_visuals/devtools", -] - - -[dependencies] -bevy_grid_squared.workspace = true -bevy_pixel_camera.workspace = true -bevy.workspace = true -common_action.workspace = true -common_assets.workspace = true -common_loading_screen.workspace = true -common_store.workspace = true -common_story.workspace = true -common_visuals.workspace = true -itertools.workspace = true -lazy_static.workspace = true -main_game_lib.workspace = true -rand.workspace = true -serde.workspace = true -smallvec.workspace = true -strum.workspace = true diff --git a/scenes/twinpeaks_apartment/README.md b/scenes/twinpeaks_apartment/README.md deleted file mode 100644 index 020579a4..00000000 --- a/scenes/twinpeaks_apartment/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Indoors surrealistic apartment scene. - -![Graph of zones](docs/tile-graph.svg) diff --git a/scenes/twinpeaks_apartment/src/lib.rs b/scenes/twinpeaks_apartment/src/lib.rs deleted file mode 100644 index 37b487ab..00000000 --- a/scenes/twinpeaks_apartment/src/lib.rs +++ /dev/null @@ -1,129 +0,0 @@ -#![doc = include_str!("../README.md")] -#![allow(clippy::assertions_on_constants)] -#![allow(clippy::type_complexity)] -#![feature(trivial_bounds)] -#![feature(let_chains)] - -mod layout; -mod prelude; - -use common_loading_screen::LoadingScreenState; -use prelude::*; - -use crate::layout::LayoutEntity; - -/// Important scene struct. -/// We use it as identifiable generic in common logic. -#[derive(TypePath, Default, Debug)] -pub struct TwinpeaksApartment; - -impl TopDownScene for TwinpeaksApartment {} - -impl main_game_lib::rscn::TscnInBevy for TwinpeaksApartment { - fn tscn_asset_path() -> String { - format!("scenes/{}.tscn", THIS_SCENE.snake_case()) - } -} - -#[derive(Event, Reflect, Clone, strum::EnumString)] -pub enum TwinpeaksApartmentAction { - ExitScene, -} - -pub fn add(app: &mut App) { - info!("Adding {TwinpeaksApartment:?} to app"); - - app.add_event::(); - - debug!("Adding plugins"); - - app.add_plugins(layout::Plugin); - - debug!("Adding game loop"); - - // when everything is loaded, finish the loading process by transitioning - // to the next loading state - app.add_systems( - Last, - finish_when_everything_loaded - .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(in_scene_loading_state(THIS_SCENE)), - ); - - app.add_systems( - Update, - common_loading_screen::finish - .run_if(in_scene_running_state(THIS_SCENE)) - .run_if(in_state(LoadingScreenState::WaitForSignalToFinish)), - ); - - app.add_systems( - Update, - // 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(in_scene_leaving_state(THIS_SCENE)), - ); - - info!("Added {TwinpeaksApartment:?} to app"); -} - -fn finish_when_everything_loaded( - mut next_loading_state: ResMut>, - map: Option>, -) { - if map.is_none() { - return; - } - - debug!("All assets loaded"); - - next_loading_state.set(common_loading_screen::finish_state()); -} - -fn enter_the_scene(mut next_state: ResMut>) { - info!("Entering {TwinpeaksApartment:?}"); - next_state.set(THIS_SCENE.running()); -} - -fn exit( - transition: Res, - mut next_state: ResMut>, - mut controls: ResMut>, -) { - info!("Leaving {TwinpeaksApartment:?}"); - - // be a good guy and don't invade other game loops with "Enter" - controls.consume(&GlobalAction::Interact); - - use GlobalGameStateTransition::*; - match *transition { - TwinpeaksApartmentToDowntown => { - next_state.set(WhichTopDownScene::Downtown.loading()); - } - _ => { - unreachable!( - "Invalid {TwinpeaksApartment:?} transition {transition:?}" - ); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_has_valid_tscn_scene() { - const TSCN: &str = include_str!( - "../../../main_game/assets/scenes/twinpeaks_apartment.tscn" - ); - rscn::parse(TSCN, &default()); - } -} diff --git a/scenes/twinpeaks_apartment/src/prelude.rs b/scenes/twinpeaks_apartment/src/prelude.rs deleted file mode 100644 index 1ed325ec..00000000 --- a/scenes/twinpeaks_apartment/src/prelude.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub(crate) use main_game_lib::prelude::*; - -pub(crate) use crate::{TwinpeaksApartment, TwinpeaksApartmentAction}; - -pub(crate) const THIS_SCENE: WhichTopDownScene = - WhichTopDownScene::TwinpeaksApartment;