From 087218b4fd0b43a346c3b9530ea0ef8d4ee7755a Mon Sep 17 00:00:00 2001 From: Alula Date: Sun, 20 Sep 2020 17:27:31 +0200 Subject: [PATCH] resizable window and some reorganization --- src/bullet.rs | 2 +- src/entity.rs | 2 +- src/frame.rs | 2 +- src/ggez/graphics/mod.rs | 2 +- src/inventory.rs | 2 +- src/live_debugger.rs | 2 +- src/main.rs | 149 +++++----------------------------- src/menu.rs | 2 +- src/npc/characters.rs | 2 +- src/npc/egg_corridor.rs | 2 +- src/npc/first_cave.rs | 2 +- src/npc/mimiga_village.rs | 2 +- src/npc/misc.rs | 2 +- src/npc/misery.rs | 2 +- src/npc/mod.rs | 3 +- src/npc/pickups.rs | 2 +- src/npc/toroko.rs | 2 +- src/physics.rs | 2 +- src/player.rs | 2 +- src/player_hit.rs | 2 +- src/scene/game_scene.rs | 8 +- src/scene/loading_scene.rs | 2 +- src/scene/mod.rs | 2 +- src/scene/title_scene.rs | 15 ++-- src/shared_game_state.rs | 161 +++++++++++++++++++++++++++++++++++++ src/sound/mod.rs | 2 +- src/sound/pixtone.rs | 13 +-- src/text_script.rs | 15 +++- src/ui.rs | 10 ++- src/weapon.rs | 2 +- 30 files changed, 247 insertions(+), 171 deletions(-) create mode 100644 src/shared_game_state.rs diff --git a/src/bullet.rs b/src/bullet.rs index ec67008..fa9e8a7 100644 --- a/src/bullet.rs +++ b/src/bullet.rs @@ -5,7 +5,7 @@ use crate::common::{Condition, Direction, Flag, Rect}; use crate::engine_constants::{BulletData, EngineConstants}; use crate::npc::NPCMap; use crate::physics::{OFF_X, OFF_Y, PhysicalEntity}; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; use crate::stage::Stage; pub struct BulletManager { diff --git a/src/entity.rs b/src/entity.rs index 79e28c9..d81bd97 100644 --- a/src/entity.rs +++ b/src/entity.rs @@ -1,7 +1,7 @@ use crate::ggez::{Context, GameResult}; use crate::frame::Frame; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; pub trait GameEntity { fn tick(&mut self, state: &mut SharedGameState, custom: C) -> GameResult; diff --git a/src/frame.rs b/src/frame.rs index 3669dfb..8e6218f 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -1,5 +1,5 @@ use crate::player::Player; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; use crate::stage::Stage; pub struct Frame { diff --git a/src/ggez/graphics/mod.rs b/src/ggez/graphics/mod.rs index 267eb98..db7403a 100644 --- a/src/ggez/graphics/mod.rs +++ b/src/ggez/graphics/mod.rs @@ -876,7 +876,7 @@ pub fn set_window_title(context: &Context, title: &str) { /// Ideally you should not need to use this because ggez /// would provide all the functions you need without having /// to dip into Glutin itself. But life isn't always ideal. -pub fn window(context: &Context) -> &glutin::Window { +pub fn window(context: &Context) -> &glutin::WindowedContext { let gfx = &context.gfx_context; &gfx.window } diff --git a/src/inventory.rs b/src/inventory.rs index 5e0b52e..0cab938 100644 --- a/src/inventory.rs +++ b/src/inventory.rs @@ -1,5 +1,5 @@ use crate::engine_constants::EngineConstants; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; use crate::weapon::{Weapon, WeaponLevel, WeaponType}; #[derive(Clone, Copy)] diff --git a/src/live_debugger.rs b/src/live_debugger.rs index 6906c0e..70cf8c2 100644 --- a/src/live_debugger.rs +++ b/src/live_debugger.rs @@ -3,7 +3,7 @@ use itertools::Itertools; use crate::ggez::{Context, GameResult}; use crate::scene::game_scene::GameScene; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; pub struct LiveDebugger { map_selector_visible: bool, diff --git a/src/main.rs b/src/main.rs index 0411c3d..64c23a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,19 +14,13 @@ extern crate strum_macros; use std::{env, mem}; use std::path; -use std::time::Instant; -use bitvec::vec::BitVec; use log::*; use pretty_env_logger::env_logger::Env; use winit::{ElementState, Event, KeyboardInput, WindowEvent}; -use crate::bmfont_renderer::BMFontRenderer; use crate::builtin_fs::BuiltinFS; -use crate::caret::{Caret, CaretType}; -use crate::common::{ControlFlags, Direction, FadeState, KeyState}; -use crate::engine_constants::EngineConstants; -use crate::ggez::{Context, ContextBuilder, event, filesystem, GameResult}; +use crate::ggez::{Context, ContextBuilder, filesystem, GameResult}; use crate::ggez::conf::{WindowMode, WindowSetup}; use crate::ggez::event::{KeyCode, KeyMods}; use crate::ggez::graphics; @@ -34,14 +28,9 @@ use crate::ggez::graphics::DrawParam; use crate::ggez::input::keyboard; use crate::ggez::mint::ColumnMatrix4; use crate::ggez::nalgebra::Vector2; -use crate::npc::{NPCTable, NPC}; -use crate::rng::RNG; use crate::scene::loading_scene::LoadingScene; use crate::scene::Scene; -use crate::sound::SoundManager; -use crate::stage::StageData; -use crate::text_script::TextScriptVM; -use crate::texture_set::TextureSet; +use crate::shared_game_state::SharedGameState; use crate::ui::UI; mod bmfont; @@ -66,6 +55,7 @@ mod player; mod player_hit; mod rng; mod scene; +mod shared_game_state; mod stage; mod sound; mod text_script; @@ -77,127 +67,16 @@ struct Game { scene: Option>, state: SharedGameState, ui: UI, - scaled_matrix: ColumnMatrix4, def_matrix: ColumnMatrix4, } -pub struct SharedGameState { - pub control_flags: ControlFlags, - pub game_flags: BitVec, - pub fade_state: FadeState, - pub game_rng: RNG, - pub effect_rng: RNG, - pub quake_counter: u16, - pub carets: Vec, - pub key_state: KeyState, - pub key_trigger: KeyState, - pub font: BMFontRenderer, - pub texture_set: TextureSet, - pub base_path: String, - pub npc_table: NPCTable, - pub stages: Vec, - pub sound_manager: SoundManager, - pub constants: EngineConstants, - pub new_npcs: Vec, - pub scale: f32, - pub god_mode: bool, - pub speed_hack: bool, - pub canvas_size: (f32, f32), - pub screen_size: (f32, f32), - pub next_scene: Option>, - pub textscript_vm: TextScriptVM, - key_old: u16, -} - -impl SharedGameState { - pub fn update_key_trigger(&mut self) { - let mut trigger = self.key_state.0 ^ self.key_old; - trigger &= self.key_state.0; - self.key_old = self.key_state.0; - self.key_trigger = KeyState(trigger); - } - - pub fn tick_carets(&mut self) { - for caret in self.carets.iter_mut() { - caret.tick(&self.effect_rng, &self.constants); - } - - self.carets.retain(|c| !c.is_dead()); - } - - pub fn create_caret(&mut self, x: isize, y: isize, ctype: CaretType, direct: Direction) { - self.carets.push(Caret::new(x, y, ctype, direct, &self.constants)); - } - - pub fn set_speed_hack(&mut self, toggle: bool) { - self.speed_hack = toggle; - - if let Err(err) = self.sound_manager.set_speed(if toggle { 2.0 } else { 1.0 }) { - log::error!("Error while sending a message to sound manager: {}", err); - } - } -} - impl Game { fn new(ctx: &mut Context) -> GameResult { - let scale = 2.0; - let screen_size = graphics::drawable_size(ctx); - let canvas_size = (screen_size.0 / scale, screen_size.1 / scale); - let mut constants = EngineConstants::defaults(); - let mut base_path = "/"; - - if filesystem::exists(ctx, "/base/Nicalis.bmp") { - info!("Cave Story+ (PC) data files detected."); - constants.apply_csplus_patches(); - base_path = "/base/"; - } else if filesystem::exists(ctx, "/base/lighting.tbl") { - info!("Cave Story+ (Switch) data files detected."); - constants.apply_csplus_patches(); - constants.apply_csplus_nx_patches(); - base_path = "/base/"; - } else if filesystem::exists(ctx, "/mrmap.bin") { - info!("CSE2E data files detected."); - } else if filesystem::exists(ctx, "/stage.dat") { - info!("NXEngine-evo data files detected."); - } - let font = BMFontRenderer::load(base_path, &constants.font_path, ctx)?; - //.or_else(|| Some(BMFontRenderer::load("/", "builtin/builtin_font.fnt", ctx)?)) - //.ok_or_else(|| ResourceLoadError(str!("Cannot load game font.")))?; - let s = Game { scene: None, - scaled_matrix: DrawParam::new() - .scale(Vector2::new(scale, scale)) - .to_matrix(), ui: UI::new(ctx)?, def_matrix: DrawParam::new().to_matrix(), - state: SharedGameState { - control_flags: ControlFlags(0), - game_flags: bitvec::bitvec![0; 8000], - fade_state: FadeState::Hidden, - game_rng: RNG::new(0), - effect_rng: RNG::new(Instant::now().elapsed().as_nanos() as i32), - quake_counter: 0, - carets: Vec::with_capacity(32), - key_state: KeyState(0), - key_trigger: KeyState(0), - font, - texture_set: TextureSet::new(base_path), - base_path: str!(base_path), - npc_table: NPCTable::new(), - stages: Vec::with_capacity(96), - sound_manager: SoundManager::new(ctx)?, - constants, - new_npcs: Vec::with_capacity(8), - scale, - god_mode: false, - speed_hack: false, - screen_size, - canvas_size, - next_scene: None, - textscript_vm: TextScriptVM::new(), - key_old: 0, - }, + state: SharedGameState::new(ctx)?, }; Ok(s) @@ -215,7 +94,9 @@ impl Game { fn draw(&mut self, ctx: &mut Context) -> GameResult { graphics::clear(ctx, [0.0, 0.0, 0.0, 1.0].into()); - graphics::set_transform(ctx, self.scaled_matrix); + graphics::set_transform(ctx, DrawParam::new() + .scale(Vector2::new(self.state.scale, self.state.scale)) + .to_matrix()); graphics::apply_transformations(ctx)?; if let Some(scene) = self.scene.as_mut() { @@ -284,7 +165,10 @@ pub fn main() -> GameResult { let cb = ContextBuilder::new("doukutsu-rs") .window_setup(WindowSetup::default().title("Cave Story (doukutsu-rs)")) - .window_mode(WindowMode::default().dimensions(854.0, 480.0)) + .window_mode(WindowMode::default() + .resizable(true) + .min_dimensions(320.0, 240.0) + .dimensions(854.0, 480.0)) .add_resource_path(resource_dir); let (ctx, event_loop) = &mut cb.build()?; @@ -301,7 +185,11 @@ pub fn main() -> GameResult { if let Event::WindowEvent { event, .. } = event { match event { - WindowEvent::CloseRequested => event::quit(ctx), + WindowEvent::CloseRequested => { game.state.shutdown(); } + WindowEvent::Resized(_) => { + game.state.handle_resize(ctx).unwrap(); + gfx_window_glutin::update_views(graphics::window(ctx), &mut game.ui.main_color, &mut game.ui.main_depth); + } WindowEvent::KeyboardInput { input: KeyboardInput { @@ -330,6 +218,11 @@ pub fn main() -> GameResult { game.update(ctx)?; game.draw(ctx)?; + if game.state.shutdown { + log::info!("Shutting down..."); + break; + } + if game.state.next_scene.is_some() { mem::swap(&mut game.scene, &mut game.state.next_scene); game.state.next_scene = None; diff --git a/src/menu.rs b/src/menu.rs index e7e43f0..43b49d4 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -1,6 +1,6 @@ use crate::common::Rect; use crate::ggez::{Context, GameResult}; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; pub enum MenuEntry { Active(String), diff --git a/src/npc/characters.rs b/src/npc/characters.rs index 02a350a..27b5a05 100644 --- a/src/npc/characters.rs +++ b/src/npc/characters.rs @@ -4,7 +4,7 @@ use crate::common::Direction; use crate::ggez::GameResult; use crate::npc::NPC; use crate::player::Player; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; impl NPC { pub(crate) fn tick_n052_sitting_blue_robot(&mut self, state: &mut SharedGameState) -> GameResult { diff --git a/src/npc/egg_corridor.rs b/src/npc/egg_corridor.rs index faa9104..7dc2e63 100644 --- a/src/npc/egg_corridor.rs +++ b/src/npc/egg_corridor.rs @@ -4,7 +4,7 @@ use crate::common::Direction; use crate::ggez::GameResult; use crate::npc::NPC; use crate::player::Player; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; impl NPC { pub(crate) fn tick_n002_behemoth(&mut self, state: &mut SharedGameState) -> GameResult { diff --git a/src/npc/first_cave.rs b/src/npc/first_cave.rs index fda50f6..fbac048 100644 --- a/src/npc/first_cave.rs +++ b/src/npc/first_cave.rs @@ -2,7 +2,7 @@ use crate::common::Direction; use crate::ggez::GameResult; use crate::npc::NPC; use crate::player::Player; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; use nalgebra::clamp; impl NPC { diff --git a/src/npc/mimiga_village.rs b/src/npc/mimiga_village.rs index 2ff8a08..dad34e1 100644 --- a/src/npc/mimiga_village.rs +++ b/src/npc/mimiga_village.rs @@ -4,7 +4,7 @@ use crate::common::Direction; use crate::ggez::GameResult; use crate::npc::NPC; use crate::player::Player; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; impl NPC { pub(crate) fn tick_n071_chinfish(&mut self, state: &mut SharedGameState) -> GameResult { diff --git a/src/npc/misc.rs b/src/npc/misc.rs index 1a5497a..83bc47c 100644 --- a/src/npc/misc.rs +++ b/src/npc/misc.rs @@ -3,7 +3,7 @@ use crate::common::Direction; use crate::ggez::GameResult; use crate::npc::{NPC, NPCMap}; use crate::player::Player; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; impl NPC { pub(crate) fn tick_n000_null(&mut self) -> GameResult { diff --git a/src/npc/misery.rs b/src/npc/misery.rs index d547d25..789aa35 100644 --- a/src/npc/misery.rs +++ b/src/npc/misery.rs @@ -7,7 +7,7 @@ use num_traits::real::Real; use crate::common::Direction; use crate::ggez::GameResult; use crate::npc::{NPC, NPCMap, NPCTable}; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; impl NPC { pub(crate) fn tick_n066_misery_bubble(&mut self, state: &mut SharedGameState, map: &HashMap>) -> GameResult { diff --git a/src/npc/mod.rs b/src/npc/mod.rs index f927f6d..f886e67 100644 --- a/src/npc/mod.rs +++ b/src/npc/mod.rs @@ -7,7 +7,7 @@ use bitvec::vec::BitVec; use byteorder::{LE, ReadBytesExt}; use itertools::Itertools; -use crate::{bitfield, SharedGameState}; +use crate::bitfield; use crate::caret::CaretType; use crate::common::{Condition, Rect}; use crate::common::Direction; @@ -19,6 +19,7 @@ use crate::map::NPCData; use crate::physics::PhysicalEntity; use crate::player::Player; use crate::str; +use crate::shared_game_state::SharedGameState; pub mod characters; pub mod egg_corridor; diff --git a/src/npc/pickups.rs b/src/npc/pickups.rs index 1fcff32..1fb183c 100644 --- a/src/npc/pickups.rs +++ b/src/npc/pickups.rs @@ -3,7 +3,7 @@ use nalgebra::clamp; use crate::common::Direction; use crate::ggez::GameResult; use crate::npc::NPC; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; impl NPC { pub(crate) fn tick_n001_experience(&mut self, state: &mut SharedGameState) -> GameResult { diff --git a/src/npc/toroko.rs b/src/npc/toroko.rs index b1ba481..3f253b8 100644 --- a/src/npc/toroko.rs +++ b/src/npc/toroko.rs @@ -4,7 +4,7 @@ use crate::common::Direction; use crate::ggez::GameResult; use crate::npc::NPC; use crate::player::Player; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; impl NPC { pub(crate) fn tick_n060_toroko(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult { diff --git a/src/physics.rs b/src/physics.rs index 37f0431..de5d455 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -2,7 +2,7 @@ use num_traits::clamp; use crate::caret::CaretType; use crate::common::{Condition, Direction, Flag, Rect}; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; use crate::stage::Stage; pub const OFF_X: [isize; 9] = [0, 1, 0, 1, 2, 2, 2, 0, 1]; diff --git a/src/player.rs b/src/player.rs index 81e17e5..d979e9c 100644 --- a/src/player.rs +++ b/src/player.rs @@ -10,7 +10,7 @@ use crate::entity::GameEntity; use crate::frame::Frame; use crate::ggez::{Context, GameResult}; use crate::inventory::Inventory; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive)] #[repr(u8)] diff --git a/src/player_hit.rs b/src/player_hit.rs index bef3c1c..9de0b84 100644 --- a/src/player_hit.rs +++ b/src/player_hit.rs @@ -6,7 +6,7 @@ use crate::inventory::{AddExperienceResult, Inventory}; use crate::npc::{NPC, NPCMap}; use crate::physics::PhysicalEntity; use crate::player::Player; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; impl PhysicalEntity for Player { #[inline(always)] diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index f4cff61..2ea1935 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -13,7 +13,7 @@ use crate::npc::NPCMap; use crate::physics::PhysicalEntity; use crate::player::Player; use crate::scene::Scene; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; use crate::stage::{BackgroundType, Stage}; use crate::text_script::{ConfirmSelection, TextScriptExecutionState, TextScriptVM}; use crate::ui::Components; @@ -692,9 +692,9 @@ impl Scene for GameScene { self.player.target_y = self.player.y; self.frame.immediate_update(state, &self.player, &self.stage); - self.inventory.add_weapon(WeaponType::PolarStar, 0); - self.inventory.add_xp(120, state); - self.player.equip.set_booster_2_0(true); + // self.inventory.add_weapon(WeaponType::PolarStar, 0); + // self.inventory.add_xp(120, state); + // self.player.equip.set_booster_2_0(true); Ok(()) } diff --git a/src/scene/loading_scene.rs b/src/scene/loading_scene.rs index e7ff411..2a11b54 100644 --- a/src/scene/loading_scene.rs +++ b/src/scene/loading_scene.rs @@ -2,7 +2,7 @@ use crate::ggez::{Context, filesystem, GameResult}; use crate::npc::NPCTable; use crate::scene::Scene; use crate::scene::title_scene::TitleScene; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; use crate::stage::StageData; use crate::text_script::TextScript; diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 7d27703..7c31016 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -1,6 +1,6 @@ use crate::ggez::{Context, GameResult}; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; use crate::ui::Components; pub mod game_scene; diff --git a/src/scene/title_scene.rs b/src/scene/title_scene.rs index 1e4ea8d..1f27992 100644 --- a/src/scene/title_scene.rs +++ b/src/scene/title_scene.rs @@ -1,9 +1,9 @@ use crate::common::{FadeState, Rect}; use crate::ggez::{Context, GameResult}; -use crate::menu::{Menu, MenuSelectionResult, MenuEntry}; +use crate::menu::{Menu, MenuEntry, MenuSelectionResult}; use crate::scene::game_scene::GameScene; use crate::scene::Scene; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; use crate::text_script::TextScriptExecutionState; pub struct TitleScene { @@ -19,7 +19,9 @@ impl TitleScene { } } - fn start_game(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + fn new_game(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + state.reset(); + let mut next_scene = GameScene::new(state, ctx, 13)?; next_scene.player.x = 10 * 16 * 0x200; next_scene.player.y = 8 * 16 * 0x200; @@ -94,10 +96,13 @@ impl Scene for TitleScene { match self.title_menu.tick(state) { MenuSelectionResult::Selected(0, _) => { - self.start_game(state, ctx); + self.new_game(state, ctx)?; } MenuSelectionResult::Selected(1, _) => { - self.start_game(state, ctx); + self.new_game(state, ctx)?; + } + MenuSelectionResult::Selected(4, _) => { + state.shutdown(); } _ => {} } diff --git a/src/shared_game_state.rs b/src/shared_game_state.rs new file mode 100644 index 0000000..4f68895 --- /dev/null +++ b/src/shared_game_state.rs @@ -0,0 +1,161 @@ +use std::ops::Div; +use std::time::Instant; + +use bitvec::vec::BitVec; + +use crate::bmfont_renderer::BMFontRenderer; +use crate::caret::{Caret, CaretType}; +use crate::common::{ControlFlags, Direction, FadeState, KeyState}; +use crate::engine_constants::EngineConstants; +use crate::ggez::{Context, filesystem, GameResult, graphics}; +use crate::npc::{NPC, NPCTable}; +use crate::rng::RNG; +use crate::scene::Scene; +use crate::sound::SoundManager; +use crate::stage::StageData; +use crate::str; +use crate::text_script::TextScriptVM; +use crate::texture_set::TextureSet; + +pub struct SharedGameState { + pub control_flags: ControlFlags, + pub game_flags: BitVec, + pub fade_state: FadeState, + pub game_rng: RNG, + pub effect_rng: RNG, + pub quake_counter: u16, + pub carets: Vec, + pub key_state: KeyState, + pub key_trigger: KeyState, + pub font: BMFontRenderer, + pub texture_set: TextureSet, + pub base_path: String, + pub npc_table: NPCTable, + pub stages: Vec, + pub sound_manager: SoundManager, + pub constants: EngineConstants, + pub new_npcs: Vec, + pub scale: f32, + pub god_mode: bool, + pub speed_hack: bool, + pub canvas_size: (f32, f32), + pub screen_size: (f32, f32), + pub next_scene: Option>, + pub textscript_vm: TextScriptVM, + pub shutdown: bool, + key_old: u16, +} + +impl SharedGameState { + pub fn new(ctx: &mut Context) -> GameResult { + let screen_size = graphics::drawable_size(ctx); + let scale = screen_size.1.div(240.0).floor().max(1.0); + let canvas_size = (screen_size.0 / scale, screen_size.1 / scale); + + let mut constants = EngineConstants::defaults(); + let mut base_path = "/"; + + if filesystem::exists(ctx, "/base/Nicalis.bmp") { + info!("Cave Story+ (PC) data files detected."); + constants.apply_csplus_patches(); + base_path = "/base/"; + } else if filesystem::exists(ctx, "/base/lighting.tbl") { + info!("Cave Story+ (Switch) data files detected."); + constants.apply_csplus_patches(); + constants.apply_csplus_nx_patches(); + base_path = "/base/"; + } else if filesystem::exists(ctx, "/mrmap.bin") { + info!("CSE2E data files detected."); + } else if filesystem::exists(ctx, "/stage.dat") { + info!("NXEngine-evo data files detected."); + } + + let font = BMFontRenderer::load(base_path, &constants.font_path, ctx) + .or_else(|_| BMFontRenderer::load("/", "builtin/builtin_font.fnt", ctx))?; + + Ok(SharedGameState { + control_flags: ControlFlags(0), + game_flags: bitvec::bitvec![0; 8000], + fade_state: FadeState::Hidden, + game_rng: RNG::new(0), + effect_rng: RNG::new(Instant::now().elapsed().as_nanos() as i32), + quake_counter: 0, + carets: Vec::with_capacity(32), + key_state: KeyState(0), + key_trigger: KeyState(0), + font, + texture_set: TextureSet::new(base_path), + base_path: str!(base_path), + npc_table: NPCTable::new(), + stages: Vec::with_capacity(96), + sound_manager: SoundManager::new(ctx)?, + constants, + new_npcs: Vec::with_capacity(8), + scale, + god_mode: false, + speed_hack: false, + screen_size, + canvas_size, + next_scene: None, + textscript_vm: TextScriptVM::new(), + key_old: 0, + shutdown: false, + }) + } + + pub fn reset(&mut self) { + self.control_flags.0 = 0; + self.game_flags = bitvec::bitvec![0; 8000]; + self.fade_state = FadeState::Hidden; + self.game_rng = RNG::new(0); + self.quake_counter = 0; + self.carets.clear(); + self.key_state.0 = 0; + self.key_trigger.0 = 0; + self.key_old = 0; + self.new_npcs.clear(); + self.textscript_vm.reset(); + self.textscript_vm.suspend = true; + } + + pub fn handle_resize(&mut self, ctx: &mut Context) -> GameResult { + self.screen_size = graphics::drawable_size(ctx); + self.scale = self.screen_size.1.div(240.0).floor().max(1.0); + self.canvas_size = (self.screen_size.0 / self.scale, self.screen_size.1 / self.scale); + + graphics::set_screen_coordinates(ctx, graphics::Rect::new(0.0, 0.0, self.screen_size.0, self.screen_size.1))?; + + Ok(()) + } + + pub fn update_key_trigger(&mut self) { + let mut trigger = self.key_state.0 ^ self.key_old; + trigger &= self.key_state.0; + self.key_old = self.key_state.0; + self.key_trigger = KeyState(trigger); + } + + pub fn tick_carets(&mut self) { + for caret in self.carets.iter_mut() { + caret.tick(&self.effect_rng, &self.constants); + } + + self.carets.retain(|c| !c.is_dead()); + } + + pub fn create_caret(&mut self, x: isize, y: isize, ctype: CaretType, direct: Direction) { + self.carets.push(Caret::new(x, y, ctype, direct, &self.constants)); + } + + pub fn set_speed_hack(&mut self, toggle: bool) { + self.speed_hack = toggle; + + if let Err(err) = self.sound_manager.set_speed(if toggle { 2.0 } else { 1.0 }) { + log::error!("Error while sending a message to sound manager: {}", err); + } + } + + pub fn shutdown(&mut self) { + self.shutdown = true; + } +} diff --git a/src/sound/mod.rs b/src/sound/mod.rs index 86b666b..2148adb 100644 --- a/src/sound/mod.rs +++ b/src/sound/mod.rs @@ -289,6 +289,6 @@ fn run(rx: Receiver, bank: SoundBank, stream.play()?; loop { - std::thread::sleep(Duration::from_millis(4)); + std::thread::sleep(Duration::from_millis(1)); } } diff --git a/src/sound/pixtone.rs b/src/sound/pixtone.rs index 4243361..e479502 100644 --- a/src/sound/pixtone.rs +++ b/src/sound/pixtone.rs @@ -175,7 +175,7 @@ impl PixToneParameters { return Vec::new(); } - let mut samples = vec![0i16; length + 100]; + let mut samples = vec![0i16; length]; for channel in self.channels.iter() { if !channel.enabled { continue; } @@ -277,12 +277,13 @@ impl PixTonePlayback { break; } else { let pos = state.1 as usize; - let s1 = (sample[pos] as f32) / 32768.0; - let s2 = (sample[clamp(pos + 1, 0, sample.len() - 1)] as f32) / 32768.0; - let s3 = (sample[clamp(pos + 2, 0, sample.len() - 1)] as f32) / 32768.0; - let s4 = (sample[pos.saturating_sub(1)] as f32) / 32768.0; + //let s1 = (sample[pos] as f32) / 32768.0; + //let s2 = (sample[clamp(pos + 1, 0, sample.len() - 1)] as f32) / 32768.0; + //let s3 = (sample[clamp(pos + 2, 0, sample.len() - 1)] as f32) / 32768.0; + //let s4 = (sample[pos.saturating_sub(1)] as f32) / 32768.0; - let s = cubic_interp(s1, s2, s4, s3, state.1.fract()) * 32768.0; + //let s = cubic_interp(s1, s2, s4, s3, state.1.fract()) * 32768.0; + let s = sample[pos] as f32; let sam = (*result ^ 0x8000) as i16; *result = sam.saturating_add(s as i16) as u16 ^ 0x8000; diff --git a/src/text_script.rs b/src/text_script.rs index 8371fcb..b7eea90 100644 --- a/src/text_script.rs +++ b/src/text_script.rs @@ -12,7 +12,7 @@ use itertools::Itertools; use num_derive::FromPrimitive; use num_traits::{clamp, FromPrimitive}; -use crate::{SharedGameState, str}; +use crate::str; use crate::bitfield; use crate::common::{Direction, FadeDirection, FadeState}; use crate::encoding::{read_cur_shift_jis, read_cur_wtf8}; @@ -21,6 +21,8 @@ use crate::ggez::{Context, GameResult}; use crate::ggez::GameError::ParseError; use crate::player::ControlMode; use crate::scene::game_scene::GameScene; +use crate::scene::title_scene::TitleScene; +use crate::shared_game_state::SharedGameState; use crate::weapon::WeaponType; /// Engine's text script VM operation codes. @@ -427,11 +429,13 @@ impl TextScriptVM { } if state.key_trigger.left() || state.key_trigger.right() { + state.sound_manager.play_sfx(1); state.textscript_vm.state = TextScriptExecutionState::WaitConfirmation(event, ip, no_event, 0, !selection); break; } if state.key_trigger.jump() { + state.sound_manager.play_sfx(18); match selection { ConfirmSelection::Yes => { state.textscript_vm.state = TextScriptExecutionState::Running(event, ip); @@ -705,6 +709,8 @@ impl TextScriptVM { OpCode::YNJ => { let event_no = read_cur_varint(&mut cursor)? as u16; + state.sound_manager.play_sfx(5); + exec_state = TextScriptExecutionState::WaitConfirmation(event, cursor.position() as u32, event_no, 16, ConfirmSelection::Yes); } OpCode::GIT => { @@ -1032,10 +1038,15 @@ impl TextScriptVM { exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); } + OpCode::ESC => { + state.next_scene = Some(Box::new(TitleScene::new())); + + exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); + } // unimplemented opcodes // Zero operands OpCode::CAT | OpCode::CIL | OpCode::CPS | - OpCode::CRE | OpCode::CSS | OpCode::ESC | OpCode::FLA | + OpCode::CRE | OpCode::CSS | OpCode::FLA | OpCode::INI | OpCode::LDP | OpCode::MLP | OpCode::SAT | OpCode::SLP | OpCode::SPS | OpCode::STC | OpCode::SVP | OpCode::TUR => { diff --git a/src/ui.rs b/src/ui.rs index 804f4a1..d465cdb 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -3,7 +3,9 @@ use std::time::Instant; use imgui::{FontConfig, FontSource}; use imgui::sys::*; use imgui_gfx_renderer::{Renderer, Shaders}; +use imgui_gfx_renderer::gfx::format::DepthStencil; use imgui_gfx_renderer::gfx::format::Rgba8; +use imgui_gfx_renderer::gfx::handle::DepthStencilView; use imgui_gfx_renderer::gfx::handle::RenderTargetView; use imgui_gfx_renderer::gfx::memory::Typed; use imgui_winit_support::{HiDpiMode, WinitPlatform}; @@ -12,7 +14,7 @@ use crate::ggez::{Context, GameResult, graphics}; use crate::ggez::GameError::RenderError; use crate::live_debugger::LiveDebugger; use crate::scene::Scene; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; mod types { pub type Device = gfx_device_gl::Device; @@ -25,7 +27,8 @@ pub struct UI { pub platform: WinitPlatform, pub renderer: Renderer, pub components: Components, - main_color: RenderTargetView, + pub main_color: RenderTargetView, + pub main_depth: DepthStencilView, last_frame: Instant, } @@ -121,7 +124,7 @@ impl UI { let mut platform = WinitPlatform::init(&mut imgui); platform.attach_window(imgui.io_mut(), graphics::window(ctx), HiDpiMode::Rounded); - let (factory, dev, _, _, color) = graphics::gfx_objects(ctx); + let (factory, dev, _, depth, color) = graphics::gfx_objects(ctx); let shaders = { let version = dev.get_info().shading_language; if version.is_embedded { @@ -153,6 +156,7 @@ impl UI { live_debugger: LiveDebugger::new(), }, main_color: RenderTargetView::new(color), + main_depth: DepthStencilView::new(depth), last_frame: Instant::now(), }) } diff --git a/src/weapon.rs b/src/weapon.rs index fd6fe16..afa34bf 100644 --- a/src/weapon.rs +++ b/src/weapon.rs @@ -4,7 +4,7 @@ use crate::bullet::BulletManager; use crate::caret::CaretType; use crate::common::Direction; use crate::player::Player; -use crate::SharedGameState; +use crate::shared_game_state::SharedGameState; #[derive(PartialEq, Eq, Copy, Clone, FromPrimitive)] #[repr(u8)]