diff --git a/src/live_debugger.rs b/src/live_debugger.rs index 4257b03..78e0a85 100644 --- a/src/live_debugger.rs +++ b/src/live_debugger.rs @@ -44,6 +44,7 @@ impl LiveDebugger { } Window::new(im_str!("Debugger")) + .collapsed(true, Condition::FirstUseEver) .position([5.0, 5.0], Condition::FirstUseEver) .size([300.0, 120.0], Condition::FirstUseEver) .build(ui, || { diff --git a/src/main.rs b/src/main.rs index 1ab0328..90c0a8e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,14 +101,14 @@ impl Game { for _ in 0..self.loops { scene.tick(&mut self.state, ctx)?; - if self.state.speed_hack { + if self.state.settings.speed_hack { scene.tick(&mut self.state, ctx)?; } } } TimingMode::FrameSynchronized => { scene.tick(&mut self.state, ctx)?; - if self.state.speed_hack { + if self.state.settings.speed_hack { scene.tick(&mut self.state, ctx)?; } } @@ -151,8 +151,8 @@ impl Game { KeyCode::X => { state.key_state.set_fire(true) } KeyCode::A => { state.key_state.set_weapon_prev(true) } KeyCode::S => { state.key_state.set_weapon_next(true) } - KeyCode::F11 => { state.god_mode = !state.god_mode } - KeyCode::F12 => { state.set_speed_hack(!state.speed_hack) } + KeyCode::F11 => { state.settings.god_mode = !state.settings.god_mode } + KeyCode::F12 => { state.set_speed_hack(!state.settings.speed_hack) } _ => {} } } diff --git a/src/player.rs b/src/player.rs index 0a1845f..34da08e 100644 --- a/src/player.rs +++ b/src/player.rs @@ -537,7 +537,7 @@ impl Player { } pub fn damage(&mut self, hp: isize, state: &mut SharedGameState) { - if state.god_mode || self.shock_counter > 0 { + if state.settings.god_mode || self.shock_counter > 0 { return; } diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index e002e68..1afc3ea 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -557,26 +557,14 @@ impl GameScene { graphics::clear(ctx, Color::from_rgb(150, 150, 150)); { - if !self.player.cond.hidden() && self.inventory.get_current_weapon().is_some() { - let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "builtin/lightmap/direct")?; - - let direction = if self.player.up { - Direction::Up - } else if self.player.down { - Direction::Bottom - } else { - self.player.direction - }; - - self.draw_directional_light(((self.player.x - self.frame.x) / 0x200) as f32, - ((self.player.y - self.frame.y) / 0x200) as f32, - 3.0, direction, (255, 255, 255), batch); - - batch.draw_filtered(FilterMode::Linear, ctx)?; - } - let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "builtin/lightmap/spot")?; + if !self.player.cond.hidden() && self.inventory.get_current_weapon().is_some() { + self.draw_light(((self.player.x - self.frame.x) / 0x200) as f32, + ((self.player.y - self.frame.y) / 0x200) as f32, + 2.5, (255, 255, 255), batch); + } + for bullet in self.bullet_manager.bullets.iter() { self.draw_light(((bullet.x - self.frame.x) / 0x200) as f32, ((bullet.y - self.frame.y) / 0x200) as f32, @@ -588,17 +576,7 @@ impl GameScene { CaretType::ProjectileDissipation | CaretType::Shoot => { self.draw_light(((caret.x - self.frame.x) / 0x200) as f32, ((caret.y - self.frame.y) / 0x200) as f32, - 1.0, (200, 200, 200), batch); - } - CaretType::LevelUp if caret.direction == Direction::Left => { - self.draw_light(((caret.x - self.frame.x) / 0x200) as f32, - ((caret.y - self.frame.y) / 0x200) as f32, - 2.0, (0, 100, 160), batch); - } - CaretType::LevelUp if caret.direction == Direction::Right => { - self.draw_light(((caret.x - self.frame.x) / 0x200) as f32, - ((caret.y - self.frame.y) / 0x200) as f32, - 2.0, (255, 30, 30), batch); + 4.0, (200, 200, 200), batch); } _ => {} } @@ -1007,7 +985,7 @@ impl Scene for GameScene { fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { self.draw_background(state, ctx)?; self.draw_tiles(state, ctx, TileLayer::Background)?; - if state.enhanced_graphics { + if state.settings.enhanced_graphics { self.draw_light_map(state, ctx)?; } diff --git a/src/scene/loading_scene.rs b/src/scene/loading_scene.rs index e993877..1d0f579 100644 --- a/src/scene/loading_scene.rs +++ b/src/scene/loading_scene.rs @@ -31,6 +31,14 @@ impl Scene for LoadingScene { let head_script = TextScript::load_from(head_tsc, &state.constants)?; state.textscript_vm.set_global_script(head_script); + let arms_item_tsc = filesystem::open(ctx, [&state.base_path, "/ArmsItem.tsc"].join(""))?; + let arms_item_script = TextScript::load_from(arms_item_tsc, &state.constants)?; + state.textscript_vm.set_inventory_script(arms_item_script); + + let stage_select_tsc = filesystem::open(ctx, [&state.base_path, "/StageSelect.tsc"].join(""))?; + let stage_select_script = TextScript::load_from(stage_select_tsc, &state.constants)?; + state.textscript_vm.set_stage_select_script(stage_select_script); + state.next_scene = Some(Box::new(TitleScene::new())); } diff --git a/src/scene/title_scene.rs b/src/scene/title_scene.rs index 1b95540..4de603e 100644 --- a/src/scene/title_scene.rs +++ b/src/scene/title_scene.rs @@ -4,6 +4,7 @@ use crate::ggez::graphics::{Color, FilterMode}; use crate::menu::{Menu, MenuEntry, MenuSelectionResult}; use crate::scene::Scene; use crate::shared_game_state::{SharedGameState, TimingMode}; +use crate::texture_set::TextureSet; #[derive(PartialEq, Eq, Copy, Clone)] #[repr(u8)] @@ -93,8 +94,13 @@ impl Scene for TitleScene { self.option_menu.push_entry(MenuEntry::Toggle("50 FPS timing".to_string(), state.timing_mode == TimingMode::_50Hz)); self.option_menu.push_entry(MenuEntry::Toggle("Linear scaling".to_string(), ctx.filter_mode == FilterMode::Linear)); - self.option_menu.push_entry(MenuEntry::Toggle("Enhanced graphics".to_string(), state.enhanced_graphics)); - self.option_menu.push_entry(MenuEntry::Toggle("2x Speed hack".to_string(), state.speed_hack)); + self.option_menu.push_entry(MenuEntry::Toggle("Enhanced graphics".to_string(), state.settings.enhanced_graphics)); + if state.constants.is_cs_plus { + self.option_menu.push_entry(MenuEntry::Toggle("Original textures".to_string(), state.settings.original_textures)); + } else { + self.option_menu.push_entry(MenuEntry::Disabled("Original textures".to_string())); + } + self.option_menu.push_entry(MenuEntry::Toggle("2x Speed hack".to_string(), state.settings.speed_hack)); self.option_menu.push_entry(MenuEntry::Active("Join our Discord".to_string())); self.option_menu.push_entry(MenuEntry::Disabled(DISCORD_LINK.to_owned())); self.option_menu.push_entry(MenuEntry::Active("Back".to_string())); @@ -155,24 +161,38 @@ impl Scene for TitleScene { } MenuSelectionResult::Selected(2, toggle) => { if let MenuEntry::Toggle(_, value) = toggle { - state.enhanced_graphics = !state.enhanced_graphics; + state.settings.enhanced_graphics = !state.settings.enhanced_graphics; - *value = state.enhanced_graphics; + *value = state.settings.enhanced_graphics; } } MenuSelectionResult::Selected(3, toggle) => { if let MenuEntry::Toggle(_, value) = toggle { - state.set_speed_hack(!state.speed_hack); + state.settings.original_textures = !state.settings.original_textures; - *value = state.speed_hack; + let path = if state.settings.original_textures { + "/base/ogph/" + } else { + "/base/" + }; + state.texture_set = TextureSet::new(path); + + *value = state.settings.original_textures; } } - MenuSelectionResult::Selected(4, _) => { + MenuSelectionResult::Selected(4, toggle) => { + if let MenuEntry::Toggle(_, value) = toggle { + state.set_speed_hack(!state.settings.speed_hack); + + *value = state.settings.speed_hack; + } + } + MenuSelectionResult::Selected(5, _) => { if let Err(e) = webbrowser::open(DISCORD_LINK) { log::warn!("Error opening web browser: {}", e); } } - MenuSelectionResult::Selected(6, _) | MenuSelectionResult::Canceled => { + MenuSelectionResult::Selected(7, _) | MenuSelectionResult::Canceled => { self.current_menu = CurrentMenu::MainMenu; } _ => {} diff --git a/src/shared_game_state.rs b/src/shared_game_state.rs index e16471e..a29ad62 100644 --- a/src/shared_game_state.rs +++ b/src/shared_game_state.rs @@ -37,6 +37,13 @@ impl TimingMode { } } +pub struct Settings { + pub god_mode: bool, + pub speed_hack: bool, + pub original_textures: bool, + pub enhanced_graphics: bool, +} + pub struct SharedGameState { pub timing_mode: TimingMode, pub control_flags: ControlFlags, @@ -54,12 +61,10 @@ pub struct SharedGameState { pub npc_table: NPCTable, pub stages: Vec, pub sound_manager: SoundManager, + pub settings: Settings, pub constants: EngineConstants, pub new_npcs: Vec, pub scale: f32, - pub god_mode: bool, - pub speed_hack: bool, - pub enhanced_graphics: bool, pub lightmap_canvas: Canvas, pub canvas_size: (f32, f32), pub screen_size: (f32, f32), @@ -113,12 +118,15 @@ impl SharedGameState { npc_table: NPCTable::new(), stages: Vec::with_capacity(96), sound_manager: SoundManager::new(ctx)?, + settings: Settings { + god_mode: false, + speed_hack: false, + original_textures: false, + enhanced_graphics: true, + }, constants, new_npcs: Vec::with_capacity(8), scale, - god_mode: false, - speed_hack: false, - enhanced_graphics: true, lightmap_canvas: Canvas::with_window_size(ctx)?, screen_size, canvas_size, @@ -209,7 +217,7 @@ impl SharedGameState { } pub fn set_speed_hack(&mut self, toggle: bool) { - self.speed_hack = toggle; + self.settings.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); diff --git a/src/text_script.rs b/src/text_script.rs index 0c5a53c..8a3bbbf 100644 --- a/src/text_script.rs +++ b/src/text_script.rs @@ -279,6 +279,10 @@ pub enum OpCode { PSH, /// , pub flags: TextScriptFlags, + pub mode: ScriptMode, /// Toggle for non-strict TSC parsing because English versions of CS+ (both AG and Nicalis release) /// modified the events carelessly and since original Pixel's engine hasn't enforced constraints /// while parsing no one noticed them. @@ -365,12 +378,18 @@ impl Default for TextScriptVM { } } -pub struct TextScriptVMScripts { +pub struct Scripts { + /// Head.tsc - shared part of map scripts pub global_script: TextScript, + /// .tsc - map script pub scene_script: TextScript, + /// ArmsItem.tsc - used by inventory + pub inventory_script: TextScript, + /// StageSelect.tsc - used by teleport target selector + pub stage_select_script: TextScript, } -impl TextScriptVMScripts { +impl Scripts { pub fn find_script(&self, event_num: u16) -> Option<&Vec> { if let Some(tsc) = self.scene_script.event_map.get(&event_num) { return Some(tsc); @@ -400,9 +419,11 @@ fn read_cur_varint(cursor: &mut Cursor<&Vec>) -> GameResult { impl TextScriptVM { pub fn new() -> Self { Self { - scripts: TextScriptVMScripts { + scripts: Scripts { global_script: TextScript::new(), scene_script: TextScript::new(), + inventory_script: TextScript::new(), + stage_select_script: TextScript::new(), }, state: TextScriptExecutionState::Ended, stack: Vec::with_capacity(6), @@ -415,6 +436,7 @@ impl TextScriptVM { line_1: Vec::with_capacity(24), line_2: Vec::with_capacity(24), line_3: Vec::with_capacity(24), + mode: ScriptMode::Map, } } @@ -428,20 +450,12 @@ impl TextScriptVM { if !self.suspend { self.reset(); } } - pub fn append_global_script(&mut self, script: TextScript) { - for (key, val) in script.event_map { - self.scripts.global_script.event_map.insert(key, val); - } - - if !self.suspend { self.reset(); } + pub fn set_inventory_script(&mut self, script: TextScript) { + self.scripts.inventory_script = script; } - pub fn append_scene_script(&mut self, script: TextScript) { - for (key, val) in script.event_map { - self.scripts.scene_script.event_map.insert(key, val); - } - - if !self.suspend { self.reset(); } + pub fn set_stage_select_script(&mut self, script: TextScript) { + self.scripts.stage_select_script = script; } pub fn reset(&mut self) { @@ -459,6 +473,8 @@ impl TextScriptVM { self.line_3.clear(); } + pub fn set_mode(&mut self, mode: ScriptMode) {} + pub fn start_script(&mut self, event_num: u16) { self.reset(); self.state = TextScriptExecutionState::Running(event_num, 0); @@ -1232,9 +1248,9 @@ impl TextScriptVM { } // unimplemented opcodes // Zero operands - OpCode::CAT | OpCode::CIL | OpCode::CPS | + OpCode::CAT | OpCode::CIL | OpCode::CPS | OpCode::KE2 | OpCode::CRE | OpCode::CSS | OpCode::FLA | OpCode::MLP | - OpCode::SAT | OpCode::SLP | OpCode::SPS | + OpCode::SAT | OpCode::SLP | OpCode::SPS | OpCode::FR2 | OpCode::STC | OpCode::SVP | OpCode::TUR | OpCode::HM2 => { log::warn!("unimplemented opcode: {:?}", op); @@ -1513,7 +1529,7 @@ impl TextScript { OpCode::MM0 | OpCode::MNA | OpCode::MS2 | OpCode::MS3 | OpCode::MSG | OpCode::NOD | OpCode::PRI | OpCode::RMU | OpCode::SAT | OpCode::SLP | OpCode::SMC | OpCode::SPS | OpCode::STC | OpCode::SVP | OpCode::TUR | OpCode::WAS | OpCode::ZAM | OpCode::HM2 | - OpCode::POP => { + OpCode::POP | OpCode::KE2 | OpCode::FR2 => { TextScript::put_varint(instr as i32, out); } // One operand codes