diff --git a/src/player.rs b/src/player.rs index 323a1a8..9d626f4 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,4 +1,5 @@ use num_traits::clamp; +use std::clone::Clone; use crate::bitfield; use crate::caret::CaretType; @@ -10,6 +11,7 @@ use crate::SharedGameState; use crate::str; bitfield! { + #[derive(Clone)] pub struct Flags(u32); impl Debug; @@ -39,6 +41,7 @@ bitfield! { } bitfield! { + #[derive(Clone)] pub struct Equip(u16); impl Debug; @@ -54,8 +57,8 @@ bitfield! { // 7 bits wasted, thx pixel } - bitfield! { + #[derive(Clone)] pub struct Cond(u16); impl Debug; @@ -69,6 +72,7 @@ bitfield! { pub visible, set_visible: 7; } +#[derive(Clone)] pub struct Player { pub x: isize, pub y: isize, diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index b3d6c4d..dcf9989 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -4,6 +4,7 @@ use crate::common::Rect; use crate::entity::GameEntity; use crate::frame::Frame; use crate::ggez::{Context, GameResult, timer}; +use crate::ggez::graphics::{Drawable, DrawParam, Text, TextFragment}; use crate::ggez::nalgebra::clamp; use crate::player::Player; use crate::scene::Scene; @@ -226,7 +227,7 @@ impl GameScene { for i in 1..7 { batch.add_rect(left_pos, top_pos + i as f32 * 8.0, &state.constants.textscript.textbox_rect_middle); } - batch.add_rect(left_pos, top_pos + 64.0, &state.constants.textscript.textbox_rect_bottom); + batch.add_rect(left_pos, top_pos + 56.0, &state.constants.textscript.textbox_rect_bottom); batch.draw(ctx)?; } @@ -242,6 +243,23 @@ impl GameScene { batch.draw(ctx)?; } + let text_offset = if state.textscript_vm.face == 0 { 0.0 } else { 56.0 }; + + // todo: proper text rendering + if !state.textscript_vm.line_1.is_empty() { + let line1: String = state.textscript_vm.line_1.iter().collect(); + Text::new(TextFragment::from(line1.as_str())).draw(ctx, DrawParam::new() + .dest(nalgebra::Point2::new((left_pos + text_offset) * 2.0 + 32.0, top_pos * 2.0 + 32.0)) + .scale(nalgebra::Vector2::new(0.5, 0.5)))?; + } + + if !state.textscript_vm.line_2.is_empty() { + let line2: String = state.textscript_vm.line_2.iter().collect(); + Text::new(TextFragment::from(line2.as_str())).draw(ctx, DrawParam::new() + .dest(nalgebra::Point2::new((left_pos + text_offset) * 2.0 + 32.0, (top_pos + 24.0) * 2.0 + 32.0)) + .scale(nalgebra::Vector2::new(0.5, 0.5)))?; + } + Ok(()) } @@ -314,10 +332,9 @@ impl Scene for GameScene { fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { state.textscript_vm.set_scene_script(self.stage.text_script.clone()); self.stage.text_script = TextScript::new(); + state.textscript_vm.suspend = false; - //self.player.x = 700 * 0x200; - //self.player.y = 1000 * 0x200; - self.player.equip.set_booster_2_0(true); + //self.player.equip.set_booster_2_0(true); state.control_flags.set_flag_x01(true); state.control_flags.set_control_enabled(true); Ok(()) @@ -353,7 +370,7 @@ impl Scene for GameScene { } } - TextScriptVM::run(state, self)?; + TextScriptVM::run(state, self, ctx)?; self.tick = self.tick.wrapping_add(1); Ok(()) } diff --git a/src/scene/loading_scene.rs b/src/scene/loading_scene.rs index 5987690..dbc3ae4 100644 --- a/src/scene/loading_scene.rs +++ b/src/scene/loading_scene.rs @@ -3,7 +3,7 @@ use crate::scene::game_scene::GameScene; use crate::scene::Scene; use crate::SharedGameState; use crate::stage::StageData; -use crate::text_script::TextScript; +use crate::text_script::{TextScript, TextScriptExecutionState}; pub struct LoadingScene { tick: usize, @@ -25,7 +25,12 @@ impl Scene for LoadingScene { state.stages = stages; let script = TextScript::load_from(filesystem::open(ctx, [&state.base_path, "/Head.tsc"].join(""))?)?; state.textscript_vm.set_global_script(script); - state.next_scene = Some(Box::new(GameScene::new(state, ctx, 0)?)); + + let mut next_scene = GameScene::new(state, ctx, 13)?; + next_scene.player.x = 10 * 16 * 0x200; + next_scene.player.y = 8 * 16 * 0x200; + state.next_scene = Some(Box::new(next_scene)); + state.textscript_vm.state = TextScriptExecutionState::Running(200, 0); } self.tick += 1; diff --git a/src/stage.rs b/src/stage.rs index 2732ed9..fa81698 100644 --- a/src/stage.rs +++ b/src/stage.rs @@ -378,8 +378,8 @@ pub struct Stage { impl Stage { pub fn load(ctx: &mut Context, root: &str, data: &StageData) -> GameResult { let map_file = filesystem::open(ctx, [root, "Stage/", &data.map, ".pxm"].join(""))?; + let tsc_file = filesystem::open(ctx, [root, "Stage/", &data.map, ".tsc"].join(""))?; let attrib_file = filesystem::open(ctx, [root, "Stage/", &data.tileset.name, ".pxa"].join(""))?; - let tsc_file = filesystem::open(ctx, [root, "Stage/", &data.tileset.name, ".tsc"].join(""))?; let map = Map::load_from(map_file, attrib_file)?; let text_script = TextScript::load_from(tsc_file)?; diff --git a/src/text_script.rs b/src/text_script.rs index de8177c..153fee2 100644 --- a/src/text_script.rs +++ b/src/text_script.rs @@ -1,8 +1,8 @@ -use std::borrow::BorrowMut; -use std::cell::RefCell; use std::collections::HashMap; use std::io; -use std::io::{Cursor, Read, Seek, SeekFrom}; +use std::io::Cursor; +use std::io::Seek; +use std::io::SeekFrom; use std::iter::Peekable; use std::str::FromStr; @@ -13,8 +13,8 @@ use num_traits::FromPrimitive; use crate::{SharedGameState, str}; use crate::bitfield; +use crate::ggez::{Context, GameResult}; use crate::ggez::GameError::ParseError; -use crate::ggez::GameResult; use crate::scene::game_scene::GameScene; /// Engine's text script VM operation codes. @@ -198,6 +198,7 @@ pub struct TextScriptVM { pub scripts: TextScriptVMScripts, pub state: TextScriptExecutionState, pub flags: TextScriptFlags, + pub suspend: bool, pub face: u16, pub current_line: TextScriptLine, pub line_1: Vec, @@ -296,6 +297,7 @@ impl TextScriptVM { scene_script: TextScript::new(), }, state: TextScriptExecutionState::Ended, + suspend: true, flags: TextScriptFlags(0), face: 0, current_line: TextScriptLine::Line1, @@ -306,12 +308,12 @@ impl TextScriptVM { pub fn set_global_script(&mut self, script: TextScript) { self.scripts.global_script = script; - self.reset(); + if !self.suspend { self.reset(); } } pub fn set_scene_script(&mut self, script: TextScript) { self.scripts.scene_script = script; - self.reset(); + if !self.suspend { self.reset(); } } pub fn reset(&mut self) { @@ -333,8 +335,10 @@ impl TextScriptVM { log::info!("Started script: #{:04}", event_num); } - pub fn run(state: &mut SharedGameState, game_scene: &mut GameScene) -> GameResult { + pub fn run(state: &mut SharedGameState, game_scene: &mut GameScene, ctx: &mut Context) -> GameResult { loop { + if state.textscript_vm.suspend { break; } + match state.textscript_vm.state { TextScriptExecutionState::Ended => { state.control_flags.set_flag_x04(false); @@ -342,7 +346,7 @@ impl TextScriptVM { } TextScriptExecutionState::Running(event, ip) => { state.control_flags.set_flag_x04(true); - state.textscript_vm.state = TextScriptVM::execute(event, ip, state, game_scene)?; + state.textscript_vm.state = TextScriptVM::execute(event, ip, state, game_scene, ctx)?; if state.textscript_vm.state == TextScriptExecutionState::Ended { state.textscript_vm.reset(); @@ -362,9 +366,12 @@ impl TextScriptVM { println!("char: {} {} {}", chr, remaining, consumed); match chr { + '\n' if state.textscript_vm.current_line == TextScriptLine::Line1 => { + state.textscript_vm.current_line = TextScriptLine::Line2; + } '\n' => { state.textscript_vm.line_1.clear(); - state.textscript_vm.line_2.append(&mut state.textscript_vm.line_1); + state.textscript_vm.line_1.append(&mut state.textscript_vm.line_2); } '\r' => {} _ if state.textscript_vm.current_line == TextScriptLine::Line1 => { @@ -406,14 +413,15 @@ impl TextScriptVM { Ok(()) } - pub fn execute(event: u16, ip: u32, state: &mut SharedGameState, game_scene: &mut GameScene) -> GameResult { + pub fn execute(event: u16, ip: u32, state: &mut SharedGameState, game_scene: &mut GameScene, ctx: &mut Context) -> GameResult { let mut exec_state = state.textscript_vm.state; if let Some(bytecode) = state.textscript_vm.scripts.find_script(event) { let mut cursor = Cursor::new(bytecode); cursor.seek(SeekFrom::Start(ip as u64))?; - let op_maybe: Option = FromPrimitive::from_i32(read_cur_varint(&mut cursor)?); + let op_maybe: Option = FromPrimitive::from_i32(read_cur_varint(&mut cursor) + .unwrap_or_else(|_| OpCode::END as i32)); if let Some(op) = op_maybe { println!("opcode: {:?}", op); @@ -511,6 +519,13 @@ impl TextScriptVM { exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); } + OpCode::CLR => { + state.textscript_vm.current_line = TextScriptLine::Line1; + state.textscript_vm.line_1.clear(); + state.textscript_vm.line_2.clear(); + + exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); + } OpCode::MSG => { state.textscript_vm.face = 0; state.textscript_vm.current_line = TextScriptLine::Line1; @@ -523,10 +538,27 @@ impl TextScriptVM { exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); } + OpCode::TRA => { + let map_id = read_cur_varint(&mut cursor)? as usize; + let event_num = read_cur_varint(&mut cursor)? as u16; + let pos_x = read_cur_varint(&mut cursor)? as isize * 16 * 0x200; + let pos_y = read_cur_varint(&mut cursor)? as isize * 16 * 0x200; + let mut new_scene = GameScene::new(state, ctx, map_id)?; + new_scene.player = game_scene.player.clone(); + new_scene.player.vel_x = 0; + new_scene.player.vel_y = 0; + new_scene.player.x = pos_x; + new_scene.player.y = pos_y; + + state.textscript_vm.suspend = true; + + state.next_scene = Some(Box::new(new_scene)); + exec_state = TextScriptExecutionState::Running(event_num, 0); + } // unimplemented opcodes // Zero operands - OpCode::AEp | OpCode::CAT | OpCode::CIL | OpCode::CLO | OpCode::CLR | OpCode::CPS | + OpCode::AEp | OpCode::CAT | OpCode::CIL | OpCode::CLO | OpCode::CPS | OpCode::CRE | OpCode::CSS | OpCode::ESC | OpCode::FLA | OpCode::FMU | OpCode::HMC | OpCode::INI | OpCode::LDP | OpCode::MLP | OpCode::MNA | OpCode::MS2 | OpCode::MS3 | @@ -537,7 +569,7 @@ impl TextScriptVM { } // One operand codes OpCode::BOA | OpCode::BSL | OpCode::FOB | OpCode::FOM | OpCode::QUA | OpCode::UNI | - OpCode::MYB | OpCode::MYD | OpCode::FAI | OpCode::FAO | OpCode::FAC | + OpCode::MYB | OpCode::MYD | OpCode::FAI | OpCode::FAO | OpCode::GIT | OpCode::NUM | OpCode::DNA | OpCode::DNP | OpCode::MPp | OpCode::SKm | OpCode::SKp | OpCode::EQp | OpCode::EQm | OpCode::ITp | OpCode::ITm | OpCode::AMm | OpCode::UNJ | OpCode::MPJ | OpCode::YNJ | @@ -564,7 +596,7 @@ impl TextScriptVM { exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); } // Four operand codes - OpCode::TRA | OpCode::MNP | OpCode::SNP => { + OpCode::MNP | OpCode::SNP => { let par_a = read_cur_varint(&mut cursor)?; let par_b = read_cur_varint(&mut cursor)?; let par_c = read_cur_varint(&mut cursor)?;