1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-11-26 06:08:16 +00:00

tsc: stage switching

This commit is contained in:
Alula 2020-08-28 00:29:10 +02:00
parent 1d8c8fe9d0
commit af9b69c303
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
5 changed files with 81 additions and 23 deletions

View file

@ -1,4 +1,5 @@
use num_traits::clamp; use num_traits::clamp;
use std::clone::Clone;
use crate::bitfield; use crate::bitfield;
use crate::caret::CaretType; use crate::caret::CaretType;
@ -10,6 +11,7 @@ use crate::SharedGameState;
use crate::str; use crate::str;
bitfield! { bitfield! {
#[derive(Clone)]
pub struct Flags(u32); pub struct Flags(u32);
impl Debug; impl Debug;
@ -39,6 +41,7 @@ bitfield! {
} }
bitfield! { bitfield! {
#[derive(Clone)]
pub struct Equip(u16); pub struct Equip(u16);
impl Debug; impl Debug;
@ -54,8 +57,8 @@ bitfield! {
// 7 bits wasted, thx pixel // 7 bits wasted, thx pixel
} }
bitfield! { bitfield! {
#[derive(Clone)]
pub struct Cond(u16); pub struct Cond(u16);
impl Debug; impl Debug;
@ -69,6 +72,7 @@ bitfield! {
pub visible, set_visible: 7; pub visible, set_visible: 7;
} }
#[derive(Clone)]
pub struct Player { pub struct Player {
pub x: isize, pub x: isize,
pub y: isize, pub y: isize,

View file

@ -4,6 +4,7 @@ use crate::common::Rect;
use crate::entity::GameEntity; use crate::entity::GameEntity;
use crate::frame::Frame; use crate::frame::Frame;
use crate::ggez::{Context, GameResult, timer}; use crate::ggez::{Context, GameResult, timer};
use crate::ggez::graphics::{Drawable, DrawParam, Text, TextFragment};
use crate::ggez::nalgebra::clamp; use crate::ggez::nalgebra::clamp;
use crate::player::Player; use crate::player::Player;
use crate::scene::Scene; use crate::scene::Scene;
@ -226,7 +227,7 @@ impl GameScene {
for i in 1..7 { 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 + 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)?; batch.draw(ctx)?;
} }
@ -242,6 +243,23 @@ impl GameScene {
batch.draw(ctx)?; 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(()) Ok(())
} }
@ -314,10 +332,9 @@ impl Scene for GameScene {
fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
state.textscript_vm.set_scene_script(self.stage.text_script.clone()); state.textscript_vm.set_scene_script(self.stage.text_script.clone());
self.stage.text_script = TextScript::new(); self.stage.text_script = TextScript::new();
state.textscript_vm.suspend = false;
//self.player.x = 700 * 0x200; //self.player.equip.set_booster_2_0(true);
//self.player.y = 1000 * 0x200;
self.player.equip.set_booster_2_0(true);
state.control_flags.set_flag_x01(true); state.control_flags.set_flag_x01(true);
state.control_flags.set_control_enabled(true); state.control_flags.set_control_enabled(true);
Ok(()) 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); self.tick = self.tick.wrapping_add(1);
Ok(()) Ok(())
} }

View file

@ -3,7 +3,7 @@ use crate::scene::game_scene::GameScene;
use crate::scene::Scene; use crate::scene::Scene;
use crate::SharedGameState; use crate::SharedGameState;
use crate::stage::StageData; use crate::stage::StageData;
use crate::text_script::TextScript; use crate::text_script::{TextScript, TextScriptExecutionState};
pub struct LoadingScene { pub struct LoadingScene {
tick: usize, tick: usize,
@ -25,7 +25,12 @@ impl Scene for LoadingScene {
state.stages = stages; state.stages = stages;
let script = TextScript::load_from(filesystem::open(ctx, [&state.base_path, "/Head.tsc"].join(""))?)?; let script = TextScript::load_from(filesystem::open(ctx, [&state.base_path, "/Head.tsc"].join(""))?)?;
state.textscript_vm.set_global_script(script); 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; self.tick += 1;

View file

@ -378,8 +378,8 @@ pub struct Stage {
impl Stage { impl Stage {
pub fn load(ctx: &mut Context, root: &str, data: &StageData) -> GameResult<Self> { pub fn load(ctx: &mut Context, root: &str, data: &StageData) -> GameResult<Self> {
let map_file = filesystem::open(ctx, [root, "Stage/", &data.map, ".pxm"].join(""))?; 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 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 map = Map::load_from(map_file, attrib_file)?;
let text_script = TextScript::load_from(tsc_file)?; let text_script = TextScript::load_from(tsc_file)?;

View file

@ -1,8 +1,8 @@
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::io; 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::iter::Peekable;
use std::str::FromStr; use std::str::FromStr;
@ -13,8 +13,8 @@ use num_traits::FromPrimitive;
use crate::{SharedGameState, str}; use crate::{SharedGameState, str};
use crate::bitfield; use crate::bitfield;
use crate::ggez::{Context, GameResult};
use crate::ggez::GameError::ParseError; use crate::ggez::GameError::ParseError;
use crate::ggez::GameResult;
use crate::scene::game_scene::GameScene; use crate::scene::game_scene::GameScene;
/// Engine's text script VM operation codes. /// Engine's text script VM operation codes.
@ -198,6 +198,7 @@ pub struct TextScriptVM {
pub scripts: TextScriptVMScripts, pub scripts: TextScriptVMScripts,
pub state: TextScriptExecutionState, pub state: TextScriptExecutionState,
pub flags: TextScriptFlags, pub flags: TextScriptFlags,
pub suspend: bool,
pub face: u16, pub face: u16,
pub current_line: TextScriptLine, pub current_line: TextScriptLine,
pub line_1: Vec<char>, pub line_1: Vec<char>,
@ -296,6 +297,7 @@ impl TextScriptVM {
scene_script: TextScript::new(), scene_script: TextScript::new(),
}, },
state: TextScriptExecutionState::Ended, state: TextScriptExecutionState::Ended,
suspend: true,
flags: TextScriptFlags(0), flags: TextScriptFlags(0),
face: 0, face: 0,
current_line: TextScriptLine::Line1, current_line: TextScriptLine::Line1,
@ -306,12 +308,12 @@ impl TextScriptVM {
pub fn set_global_script(&mut self, script: TextScript) { pub fn set_global_script(&mut self, script: TextScript) {
self.scripts.global_script = script; self.scripts.global_script = script;
self.reset(); if !self.suspend { self.reset(); }
} }
pub fn set_scene_script(&mut self, script: TextScript) { pub fn set_scene_script(&mut self, script: TextScript) {
self.scripts.scene_script = script; self.scripts.scene_script = script;
self.reset(); if !self.suspend { self.reset(); }
} }
pub fn reset(&mut self) { pub fn reset(&mut self) {
@ -333,8 +335,10 @@ impl TextScriptVM {
log::info!("Started script: #{:04}", event_num); 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 { loop {
if state.textscript_vm.suspend { break; }
match state.textscript_vm.state { match state.textscript_vm.state {
TextScriptExecutionState::Ended => { TextScriptExecutionState::Ended => {
state.control_flags.set_flag_x04(false); state.control_flags.set_flag_x04(false);
@ -342,7 +346,7 @@ impl TextScriptVM {
} }
TextScriptExecutionState::Running(event, ip) => { TextScriptExecutionState::Running(event, ip) => {
state.control_flags.set_flag_x04(true); 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 { if state.textscript_vm.state == TextScriptExecutionState::Ended {
state.textscript_vm.reset(); state.textscript_vm.reset();
@ -362,9 +366,12 @@ impl TextScriptVM {
println!("char: {} {} {}", chr, remaining, consumed); println!("char: {} {} {}", chr, remaining, consumed);
match chr { match chr {
'\n' if state.textscript_vm.current_line == TextScriptLine::Line1 => {
state.textscript_vm.current_line = TextScriptLine::Line2;
}
'\n' => { '\n' => {
state.textscript_vm.line_1.clear(); 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' => {} '\r' => {}
_ if state.textscript_vm.current_line == TextScriptLine::Line1 => { _ if state.textscript_vm.current_line == TextScriptLine::Line1 => {
@ -406,14 +413,15 @@ impl TextScriptVM {
Ok(()) Ok(())
} }
pub fn execute(event: u16, ip: u32, state: &mut SharedGameState, game_scene: &mut GameScene) -> GameResult<TextScriptExecutionState> { pub fn execute(event: u16, ip: u32, state: &mut SharedGameState, game_scene: &mut GameScene, ctx: &mut Context) -> GameResult<TextScriptExecutionState> {
let mut exec_state = state.textscript_vm.state; let mut exec_state = state.textscript_vm.state;
if let Some(bytecode) = state.textscript_vm.scripts.find_script(event) { if let Some(bytecode) = state.textscript_vm.scripts.find_script(event) {
let mut cursor = Cursor::new(bytecode); let mut cursor = Cursor::new(bytecode);
cursor.seek(SeekFrom::Start(ip as u64))?; cursor.seek(SeekFrom::Start(ip as u64))?;
let op_maybe: Option<OpCode> = FromPrimitive::from_i32(read_cur_varint(&mut cursor)?); let op_maybe: Option<OpCode> = FromPrimitive::from_i32(read_cur_varint(&mut cursor)
.unwrap_or_else(|_| OpCode::END as i32));
if let Some(op) = op_maybe { if let Some(op) = op_maybe {
println!("opcode: {:?}", op); println!("opcode: {:?}", op);
@ -511,6 +519,13 @@ impl TextScriptVM {
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); 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 => { OpCode::MSG => {
state.textscript_vm.face = 0; state.textscript_vm.face = 0;
state.textscript_vm.current_line = TextScriptLine::Line1; state.textscript_vm.current_line = TextScriptLine::Line1;
@ -523,10 +538,27 @@ impl TextScriptVM {
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32); 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 // unimplemented opcodes
// Zero operands // 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::CRE | OpCode::CSS | OpCode::ESC | OpCode::FLA | OpCode::FMU |
OpCode::HMC | OpCode::INI | OpCode::LDP | OpCode::MLP | OpCode::HMC | OpCode::INI | OpCode::LDP | OpCode::MLP |
OpCode::MNA | OpCode::MS2 | OpCode::MS3 | OpCode::MNA | OpCode::MS2 | OpCode::MS3 |
@ -537,7 +569,7 @@ impl TextScriptVM {
} }
// One operand codes // One operand codes
OpCode::BOA | OpCode::BSL | OpCode::FOB | OpCode::FOM | OpCode::QUA | OpCode::UNI | 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::GIT | OpCode::NUM | OpCode::DNA | OpCode::DNP |
OpCode::MPp | OpCode::SKm | OpCode::SKp | OpCode::EQp | OpCode::EQm | OpCode::MPp | OpCode::SKm | OpCode::SKp | OpCode::EQp | OpCode::EQm |
OpCode::ITp | OpCode::ITm | OpCode::AMm | OpCode::UNJ | OpCode::MPJ | OpCode::YNJ | 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); exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
} }
// Four operand codes // Four operand codes
OpCode::TRA | OpCode::MNP | OpCode::SNP => { OpCode::MNP | OpCode::SNP => {
let par_a = read_cur_varint(&mut cursor)?; let par_a = read_cur_varint(&mut cursor)?;
let par_b = read_cur_varint(&mut cursor)?; let par_b = read_cur_varint(&mut cursor)?;
let par_c = read_cur_varint(&mut cursor)?; let par_c = read_cur_varint(&mut cursor)?;