mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-11-26 14:17:08 +00:00
Improve TextScript VM to make it execute ingame-conversations
This commit is contained in:
parent
677f928467
commit
8f908b306d
|
|
@ -88,12 +88,18 @@ impl Clone for WorldConsts {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TextScriptConsts {
|
pub struct TextScriptConsts {
|
||||||
pub encoding: TextScriptEncoding,
|
pub encoding: TextScriptEncoding,
|
||||||
|
pub textbox_rect_top: Rect<usize>,
|
||||||
|
pub textbox_rect_middle: Rect<usize>,
|
||||||
|
pub textbox_rect_bottom: Rect<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for TextScriptConsts {
|
impl Clone for TextScriptConsts {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
encoding: self.encoding,
|
encoding: self.encoding,
|
||||||
|
textbox_rect_top: self.textbox_rect_top,
|
||||||
|
textbox_rect_middle: self.textbox_rect_middle,
|
||||||
|
textbox_rect_bottom: self.textbox_rect_bottom,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -364,7 +370,10 @@ impl EngineConstants {
|
||||||
},
|
},
|
||||||
textscript: TextScriptConsts {
|
textscript: TextScriptConsts {
|
||||||
encoding: TextScriptEncoding::UTF8,
|
encoding: TextScriptEncoding::UTF8,
|
||||||
}
|
textbox_rect_top: Rect { left: 0, top: 0, right: 244, bottom: 8 },
|
||||||
|
textbox_rect_middle: Rect { left: 0, top: 8, right: 244, bottom: 16 },
|
||||||
|
textbox_rect_bottom: Rect { left: 0, top: 16, right: 244, bottom: 24 },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ impl LiveDebugger {
|
||||||
.size([300.0, 100.0], Condition::Appearing)
|
.size([300.0, 100.0], Condition::Appearing)
|
||||||
.build(ui, || {
|
.build(ui, || {
|
||||||
ui.push_item_width(-1.0);
|
ui.push_item_width(-1.0);
|
||||||
ui.text(self.error.as_ref().unwrap());
|
ui.text_wrapped(self.error.as_ref().unwrap());
|
||||||
|
|
||||||
if ui.button(im_str!("OK"), [0.0, 0.0]) {
|
if ui.button(im_str!("OK"), [0.0, 0.0]) {
|
||||||
self.error = None;
|
self.error = None;
|
||||||
|
|
@ -135,25 +135,29 @@ impl LiveDebugger {
|
||||||
Window::new(im_str!("Events"))
|
Window::new(im_str!("Events"))
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.position([80.0, 80.0], Condition::FirstUseEver)
|
.position([80.0, 80.0], Condition::FirstUseEver)
|
||||||
.size([250.0, 300.0], Condition::FirstUseEver)
|
.size([280.0, 300.0], Condition::FirstUseEver)
|
||||||
.build(ui, || {
|
.build(ui, || {
|
||||||
if self.events.is_empty() {
|
if self.events.is_empty() {
|
||||||
self.event_ids.clear();
|
self.event_ids.clear();
|
||||||
|
|
||||||
let vm = &state.textscript_vm;
|
let vm = &state.textscript_vm;
|
||||||
for event in vm.global_script.get_event_ids() {
|
for event in vm.scripts.global_script.get_event_ids() {
|
||||||
self.events.push(ImString::new(format!("Global: #{:04}", event)));
|
self.events.push(ImString::new(format!("Global: #{:04}", event)));
|
||||||
self.event_ids.push(event);
|
self.event_ids.push(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
for event in vm.scene_script.get_event_ids() {
|
for event in vm.scripts.scene_script.get_event_ids() {
|
||||||
self.events.push(ImString::new(format!("Scene: #{:04}", event)));
|
self.events.push(ImString::new(format!("Scene: #{:04}", event)));
|
||||||
self.event_ids.push(event);
|
self.event_ids.push(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let events: Vec<&ImStr> = self.events.iter().map(|e| e.as_ref()).collect();
|
let events: Vec<&ImStr> = self.events.iter().map(|e| e.as_ref()).collect();
|
||||||
|
|
||||||
ui.text(format!("Execution state: {:?}", state.textscript_vm.state));
|
ui.text_wrapped(&ImString::new(format!("Execution state: {:?}", state.textscript_vm.state)));
|
||||||
|
let line1: String = state.textscript_vm.line_1.iter().collect();
|
||||||
|
let line2: String = state.textscript_vm.line_2.iter().collect();
|
||||||
|
ui.text_wrapped(&ImString::new(&line1));
|
||||||
|
ui.text_wrapped(&ImString::new(&line2));
|
||||||
|
|
||||||
ui.push_item_width(-1.0);
|
ui.push_item_width(-1.0);
|
||||||
ui.list_box(im_str!(""), &mut self.selected_event, &events, 10);
|
ui.list_box(im_str!(""), &mut self.selected_event, &events, 10);
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ bitfield! {
|
||||||
}
|
}
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
pub struct ControlFlags(u32);
|
pub struct ControlFlags(u16);
|
||||||
impl Debug;
|
impl Debug;
|
||||||
pub flag_x01, set_flag_x01: 0;
|
pub flag_x01, set_flag_x01: 0;
|
||||||
pub control_enabled, set_control_enabled: 1;
|
pub control_enabled, set_control_enabled: 1;
|
||||||
|
|
|
||||||
|
|
@ -87,12 +87,12 @@ pub struct Player {
|
||||||
pub unit: u8,
|
pub unit: u8,
|
||||||
pub question: bool,
|
pub question: bool,
|
||||||
pub booster_fuel: usize,
|
pub booster_fuel: usize,
|
||||||
|
pub up: bool,
|
||||||
|
pub down: bool,
|
||||||
|
pub shock_counter: u8,
|
||||||
index_x: isize,
|
index_x: isize,
|
||||||
index_y: isize,
|
index_y: isize,
|
||||||
sprash: bool,
|
sprash: bool,
|
||||||
up: bool,
|
|
||||||
down: bool,
|
|
||||||
shock_counter: u8,
|
|
||||||
booster_switch: u8,
|
booster_switch: u8,
|
||||||
star: u8,
|
star: u8,
|
||||||
bubble: u8,
|
bubble: u8,
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,13 @@ 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::nalgebra::clamp;
|
use crate::ggez::nalgebra::clamp;
|
||||||
use crate::live_debugger::LiveDebugger;
|
|
||||||
use crate::player::Player;
|
use crate::player::Player;
|
||||||
use crate::scene::Scene;
|
use crate::scene::Scene;
|
||||||
use crate::SharedGameState;
|
use crate::SharedGameState;
|
||||||
use crate::stage::{BackgroundType, Stage};
|
use crate::stage::{BackgroundType, Stage};
|
||||||
use crate::str;
|
use crate::str;
|
||||||
use crate::ui::{UI, Components};
|
|
||||||
use crate::text_script::{TextScript, TextScriptVM};
|
use crate::text_script::{TextScript, TextScriptVM};
|
||||||
|
use crate::ui::Components;
|
||||||
|
|
||||||
pub struct GameScene {
|
pub struct GameScene {
|
||||||
pub tick: usize,
|
pub tick: usize,
|
||||||
|
|
@ -22,6 +21,7 @@ pub struct GameScene {
|
||||||
pub stage_id: usize,
|
pub stage_id: usize,
|
||||||
tex_background_name: String,
|
tex_background_name: String,
|
||||||
tex_caret_name: String,
|
tex_caret_name: String,
|
||||||
|
tex_face_name: String,
|
||||||
tex_hud_name: String,
|
tex_hud_name: String,
|
||||||
tex_npcsym_name: String,
|
tex_npcsym_name: String,
|
||||||
tex_tileset_name: String,
|
tex_tileset_name: String,
|
||||||
|
|
@ -51,6 +51,7 @@ impl GameScene {
|
||||||
|
|
||||||
let tex_background_name = stage.data.background.filename();
|
let tex_background_name = stage.data.background.filename();
|
||||||
let tex_caret_name = str!("Caret");
|
let tex_caret_name = str!("Caret");
|
||||||
|
let tex_face_name = str!("Face");
|
||||||
let tex_hud_name = str!("TextBox");
|
let tex_hud_name = str!("TextBox");
|
||||||
let tex_npcsym_name = str!("Npc/NpcSym");
|
let tex_npcsym_name = str!("Npc/NpcSym");
|
||||||
let tex_tileset_name = ["Stage/", &stage.data.tileset.filename()].join("");
|
let tex_tileset_name = ["Stage/", &stage.data.tileset.filename()].join("");
|
||||||
|
|
@ -67,6 +68,7 @@ impl GameScene {
|
||||||
stage_id: id,
|
stage_id: id,
|
||||||
tex_background_name,
|
tex_background_name,
|
||||||
tex_caret_name,
|
tex_caret_name,
|
||||||
|
tex_face_name,
|
||||||
tex_hud_name,
|
tex_hud_name,
|
||||||
tex_npcsym_name,
|
tex_npcsym_name,
|
||||||
tex_tileset_name,
|
tex_tileset_name,
|
||||||
|
|
@ -208,6 +210,37 @@ impl GameScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_black_bars(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
fn draw_black_bars(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_text_boxes(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
|
if !state.textscript_vm.flags.render() { return Ok(()); }
|
||||||
|
|
||||||
|
let top_pos = if state.textscript_vm.flags.position_top() { 32.0 } else { state.canvas_size.1 as f32 - 64.0 };
|
||||||
|
let left_pos = (state.canvas_size.0 / 2.0 - 122.0).floor();
|
||||||
|
|
||||||
|
if state.textscript_vm.flags.background_visible() {
|
||||||
|
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_hud_name)?;
|
||||||
|
|
||||||
|
batch.add_rect(left_pos, top_pos, &state.constants.textscript.textbox_rect_top);
|
||||||
|
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.draw(ctx)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.textscript_vm.face != 0 {
|
||||||
|
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_face_name)?;
|
||||||
|
batch.add_rect(left_pos + 14.0, top_pos + 8.0, &Rect::<usize>::new_size(
|
||||||
|
(state.textscript_vm.face as usize % 6) * 48,
|
||||||
|
(state.textscript_vm.face as usize / 6) * 48,
|
||||||
|
48, 48,
|
||||||
|
));
|
||||||
|
|
||||||
|
batch.draw(ctx)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -320,7 +353,7 @@ impl Scene for GameScene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextScriptVM::run(state, self);
|
TextScriptVM::run(state, self)?;
|
||||||
self.tick = self.tick.wrapping_add(1);
|
self.tick = self.tick.wrapping_add(1);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -337,6 +370,8 @@ impl Scene for GameScene {
|
||||||
self.draw_hud(state, ctx)?;
|
self.draw_hud(state, ctx)?;
|
||||||
self.draw_number(state.canvas_size.0 - 8.0, 8.0, timer::fps(ctx) as usize, Alignment::Right, state, ctx)?;
|
self.draw_number(state.canvas_size.0 - 8.0, 8.0, timer::fps(ctx) as usize, Alignment::Right, state, ctx)?;
|
||||||
|
|
||||||
|
self.draw_text_boxes(state, ctx)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use num_derive::FromPrimitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
|
|
||||||
use crate::{SharedGameState, str};
|
use crate::{SharedGameState, str};
|
||||||
use crate::common::CursorIterator;
|
use crate::bitfield;
|
||||||
use crate::ggez::GameError::ParseError;
|
use crate::ggez::GameError::ParseError;
|
||||||
use crate::ggez::GameResult;
|
use crate::ggez::GameResult;
|
||||||
use crate::scene::game_scene::GameScene;
|
use crate::scene::game_scene::GameScene;
|
||||||
|
|
@ -161,29 +161,47 @@ pub enum OpCode {
|
||||||
// ---- Custom opcodes, for use by modders ----
|
// ---- Custom opcodes, for use by modders ----
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, EnumIter, PartialEq, Eq, Hash, Copy, Clone)]
|
bitfield! {
|
||||||
|
pub struct TextScriptFlags(u16);
|
||||||
|
impl Debug;
|
||||||
|
pub render, set_render: 0;
|
||||||
|
pub background_visible, set_background_visible: 1;
|
||||||
|
pub flag_x10, set_flag_x10: 4;
|
||||||
|
pub position_top, set_position_top: 5;
|
||||||
|
pub flag_x40, set_flag_x40: 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[repr(u8)]
|
||||||
pub enum TextScriptEncoding {
|
pub enum TextScriptEncoding {
|
||||||
UTF8,
|
UTF8 = 0,
|
||||||
ShiftJIS,
|
ShiftJIS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum TextScriptLine {
|
||||||
|
Line1 = 0,
|
||||||
|
Line2,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
pub enum TextScriptExecutionState {
|
pub enum TextScriptExecutionState {
|
||||||
Ended,
|
Ended,
|
||||||
Running(u16, u32),
|
Running(u16, u32),
|
||||||
Msg(u16, u32, u32),
|
Msg(u16, u32, u32, u8),
|
||||||
WaitTicks(u16, u32, u32),
|
WaitTicks(u16, u32, u32),
|
||||||
WaitInput(u16, u32),
|
WaitInput(u16, u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextScriptVM {
|
pub struct TextScriptVM {
|
||||||
pub global_script: TextScript,
|
pub scripts: TextScriptVMScripts,
|
||||||
pub scene_script: TextScript,
|
|
||||||
pub state: TextScriptExecutionState,
|
pub state: TextScriptExecutionState,
|
||||||
msg_timer: u8,
|
pub flags: TextScriptFlags,
|
||||||
face: u16,
|
pub face: u16,
|
||||||
line_1: Vec<char>,
|
pub current_line: TextScriptLine,
|
||||||
line_2: Vec<char>,
|
pub line_1: Vec<char>,
|
||||||
|
pub line_2: Vec<char>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TextScriptVM {
|
impl Default for TextScriptVM {
|
||||||
|
|
@ -192,6 +210,23 @@ impl Default for TextScriptVM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TextScriptVMScripts {
|
||||||
|
pub global_script: TextScript,
|
||||||
|
pub scene_script: TextScript,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextScriptVMScripts {
|
||||||
|
pub fn find_script(&self, event_num: u16) -> Option<&Vec<u8>> {
|
||||||
|
if let Some(tsc) = self.scene_script.event_map.get(&event_num) {
|
||||||
|
return Some(tsc);
|
||||||
|
} else if let Some(tsc) = self.global_script.event_map.get(&event_num) {
|
||||||
|
return Some(tsc);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn read_cur_varint(cursor: &mut Cursor<&Vec<u8>>) -> GameResult<i32> {
|
fn read_cur_varint(cursor: &mut Cursor<&Vec<u8>>) -> GameResult<i32> {
|
||||||
let mut result = 0u32;
|
let mut result = 0u32;
|
||||||
|
|
||||||
|
|
@ -209,9 +244,9 @@ fn read_cur_varint(cursor: &mut Cursor<&Vec<u8>>) -> GameResult<i32> {
|
||||||
|
|
||||||
/// Decodes UTF-8 character in a less strict way.
|
/// Decodes UTF-8 character in a less strict way.
|
||||||
/// http://simonsapin.github.io/wtf-8/#decoding-wtf-8
|
/// http://simonsapin.github.io/wtf-8/#decoding-wtf-8
|
||||||
fn read_cur_wtf8(cursor: &mut Cursor<&Vec<u8>>, max_bytes: usize) -> (u8, char) {
|
fn read_cur_wtf8(cursor: &mut Cursor<&Vec<u8>>, max_bytes: u32) -> (u32, char) {
|
||||||
let mut result = 0u32;
|
let mut result = 0u32;
|
||||||
let mut consumed = 0u8;
|
let mut consumed = 0u32;
|
||||||
|
|
||||||
if max_bytes == 0 {
|
if max_bytes == 0 {
|
||||||
return (0, '\u{fffd}');
|
return (0, '\u{fffd}');
|
||||||
|
|
@ -256,39 +291,38 @@ fn read_cur_wtf8(cursor: &mut Cursor<&Vec<u8>>, max_bytes: usize) -> (u8, char)
|
||||||
impl TextScriptVM {
|
impl TextScriptVM {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
global_script: TextScript::new(),
|
scripts: TextScriptVMScripts {
|
||||||
scene_script: TextScript::new(),
|
global_script: TextScript::new(),
|
||||||
|
scene_script: TextScript::new(),
|
||||||
|
},
|
||||||
state: TextScriptExecutionState::Ended,
|
state: TextScriptExecutionState::Ended,
|
||||||
msg_timer: 0,
|
flags: TextScriptFlags(0),
|
||||||
face: 0,
|
face: 0,
|
||||||
|
current_line: TextScriptLine::Line1,
|
||||||
line_1: Vec::with_capacity(24),
|
line_1: Vec::with_capacity(24),
|
||||||
line_2: Vec::with_capacity(24),
|
line_2: Vec::with_capacity(24),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_global_script(&mut self, script: TextScript) {
|
pub fn set_global_script(&mut self, script: TextScript) {
|
||||||
self.global_script = script;
|
self.scripts.global_script = script;
|
||||||
self.reset();
|
self.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_scene_script(&mut self, script: TextScript) {
|
pub fn set_scene_script(&mut self, script: TextScript) {
|
||||||
self.scene_script = script;
|
self.scripts.scene_script = script;
|
||||||
self.reset();
|
self.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_script(&self, event_num: u16) -> Option<&Vec<u8>> {
|
|
||||||
if let Some(tsc) = self.scene_script.event_map.get(&event_num) {
|
|
||||||
return Some(tsc);
|
|
||||||
} else if let Some(tsc) = self.global_script.event_map.get(&event_num) {
|
|
||||||
return Some(tsc);
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.state = TextScriptExecutionState::Ended;
|
self.state = TextScriptExecutionState::Ended;
|
||||||
|
self.clear_text_box();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_text_box(&mut self) {
|
||||||
|
self.flags.0 = 0;
|
||||||
self.face = 0;
|
self.face = 0;
|
||||||
|
self.current_line = TextScriptLine::Line1;
|
||||||
self.line_1.clear();
|
self.line_1.clear();
|
||||||
self.line_2.clear();
|
self.line_2.clear();
|
||||||
}
|
}
|
||||||
|
|
@ -303,14 +337,52 @@ impl TextScriptVM {
|
||||||
loop {
|
loop {
|
||||||
match state.textscript_vm.state {
|
match state.textscript_vm.state {
|
||||||
TextScriptExecutionState::Ended => {
|
TextScriptExecutionState::Ended => {
|
||||||
|
state.control_flags.set_flag_x04(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TextScriptExecutionState::Running(event, ip) => {
|
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)?;
|
||||||
println!("new vm state: {:?}", state.textscript_vm.state);
|
|
||||||
|
if state.textscript_vm.state == TextScriptExecutionState::Ended {
|
||||||
|
state.textscript_vm.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TextScriptExecutionState::Msg(event, ip, remaining) => {
|
TextScriptExecutionState::Msg(event, ip, remaining, timer) => {
|
||||||
if let Some(bytecode) = state.textscript_vm.find_script(event) {} else {
|
if timer > 0 {
|
||||||
|
state.textscript_vm.state = TextScriptExecutionState::Msg(event, ip, remaining, timer - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (consumed, chr) = read_cur_wtf8(&mut cursor, remaining);
|
||||||
|
println!("char: {} {} {}", chr, remaining, consumed);
|
||||||
|
|
||||||
|
match chr {
|
||||||
|
'\n' => {
|
||||||
|
state.textscript_vm.line_1.clear();
|
||||||
|
state.textscript_vm.line_2.append(&mut state.textscript_vm.line_1);
|
||||||
|
}
|
||||||
|
'\r' => {}
|
||||||
|
_ if state.textscript_vm.current_line == TextScriptLine::Line1 => {
|
||||||
|
state.textscript_vm.line_1.push(chr);
|
||||||
|
}
|
||||||
|
_ if state.textscript_vm.current_line == TextScriptLine::Line2 => {
|
||||||
|
state.textscript_vm.line_2.push(chr);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remaining - consumed) > 0 {
|
||||||
|
let ticks = if state.key_state.jump() || state.key_state.fire() { 1 } else { 4 };
|
||||||
|
state.textscript_vm.state = TextScriptExecutionState::Msg(event, ip + consumed, remaining - consumed, ticks);
|
||||||
|
} else {
|
||||||
|
state.textscript_vm.state = TextScriptExecutionState::Running(event, ip + consumed);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
state.textscript_vm.reset();
|
state.textscript_vm.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -337,28 +409,61 @@ impl TextScriptVM {
|
||||||
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) -> 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.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)?);
|
||||||
|
|
||||||
if let Some(op) = op_maybe {
|
if let Some(op) = op_maybe {
|
||||||
|
println!("opcode: {:?}", op);
|
||||||
match op {
|
match op {
|
||||||
OpCode::_NOP => {
|
OpCode::_NOP => {
|
||||||
println!("opcode: {:?}", op);
|
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
OpCode::_UNI => {}
|
OpCode::_UNI => {}
|
||||||
OpCode::_STR => {
|
OpCode::_STR => {
|
||||||
// simply skip the text if we aren't in message mode.
|
|
||||||
let len = read_cur_varint(&mut cursor)? as u32;
|
let len = read_cur_varint(&mut cursor)? as u32;
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32 + len);
|
if state.textscript_vm.flags.render() {
|
||||||
|
exec_state = TextScriptExecutionState::Msg(event, cursor.position() as u32, len, 4);
|
||||||
|
} else {
|
||||||
|
// simply skip the text if we aren't in message mode.
|
||||||
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32 + len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
OpCode::_END | OpCode::END => {
|
OpCode::_END | OpCode::END => {
|
||||||
|
state.control_flags.set_flag_x01(true);
|
||||||
|
state.control_flags.set_control_enabled(true);
|
||||||
|
|
||||||
exec_state = TextScriptExecutionState::Ended;
|
exec_state = TextScriptExecutionState::Ended;
|
||||||
}
|
}
|
||||||
|
OpCode::PRI => {
|
||||||
|
state.control_flags.set_flag_x01(false);
|
||||||
|
state.control_flags.set_control_enabled(false);
|
||||||
|
|
||||||
|
game_scene.player.shock_counter = 0;
|
||||||
|
|
||||||
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
|
}
|
||||||
|
OpCode::KEY => {
|
||||||
|
state.control_flags.set_flag_x01(true);
|
||||||
|
state.control_flags.set_control_enabled(false);
|
||||||
|
|
||||||
|
game_scene.player.up = false;
|
||||||
|
game_scene.player.down = false;
|
||||||
|
game_scene.player.shock_counter = 0;
|
||||||
|
|
||||||
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
|
}
|
||||||
|
OpCode::FRE => {
|
||||||
|
state.control_flags.set_flag_x01(true);
|
||||||
|
state.control_flags.set_control_enabled(true);
|
||||||
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
|
}
|
||||||
|
OpCode::WAI => {
|
||||||
|
let ticks = read_cur_varint(&mut cursor)? as u32;
|
||||||
|
exec_state = TextScriptExecutionState::WaitTicks(event, cursor.position() as u32, ticks);
|
||||||
|
}
|
||||||
OpCode::NOD => {
|
OpCode::NOD => {
|
||||||
exec_state = TextScriptExecutionState::WaitInput(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::WaitInput(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
|
|
@ -372,6 +477,8 @@ impl TextScriptVM {
|
||||||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||||
if let Some(true) = state.game_flags.get(flag_num) {
|
if let Some(true) = state.game_flags.get(flag_num) {
|
||||||
exec_state = TextScriptExecutionState::Running(event_num, 0);
|
exec_state = TextScriptExecutionState::Running(event_num, 0);
|
||||||
|
} else {
|
||||||
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OpCode::EVE => {
|
OpCode::EVE => {
|
||||||
|
|
@ -380,6 +487,7 @@ impl TextScriptVM {
|
||||||
}
|
}
|
||||||
OpCode::MM0 => {
|
OpCode::MM0 => {
|
||||||
game_scene.player.vel_x = 0;
|
game_scene.player.vel_x = 0;
|
||||||
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
OpCode::CMP => {
|
OpCode::CMP => {
|
||||||
let pos_x = read_cur_varint(&mut cursor)? as usize;
|
let pos_x = read_cur_varint(&mut cursor)? as usize;
|
||||||
|
|
@ -397,23 +505,41 @@ impl TextScriptVM {
|
||||||
game_scene.player.max_life += life;
|
game_scene.player.max_life += life;
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
|
OpCode::FAC => {
|
||||||
|
let face = read_cur_varint(&mut cursor)? as u16;
|
||||||
|
state.textscript_vm.face = face;
|
||||||
|
|
||||||
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
|
}
|
||||||
|
OpCode::MSG => {
|
||||||
|
state.textscript_vm.face = 0;
|
||||||
|
state.textscript_vm.current_line = TextScriptLine::Line1;
|
||||||
|
state.textscript_vm.line_1.clear();
|
||||||
|
state.textscript_vm.line_2.clear();
|
||||||
|
state.textscript_vm.flags.set_render(true);
|
||||||
|
state.textscript_vm.flags.set_background_visible(true);
|
||||||
|
state.textscript_vm.flags.set_flag_x10(state.textscript_vm.flags.flag_x40());
|
||||||
|
state.textscript_vm.flags.set_position_top(false);
|
||||||
|
|
||||||
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
|
}
|
||||||
|
|
||||||
// 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::CLR | OpCode::CPS |
|
||||||
OpCode::CRE | OpCode::CSS | OpCode::ESC | OpCode::FLA | OpCode::FMU |
|
OpCode::CRE | OpCode::CSS | OpCode::ESC | OpCode::FLA | OpCode::FMU |
|
||||||
OpCode::FRE | OpCode::HMC | OpCode::INI | OpCode::KEY | OpCode::LDP | OpCode::MLP |
|
OpCode::HMC | OpCode::INI | OpCode::LDP | OpCode::MLP |
|
||||||
OpCode::MNA | OpCode::MS2 | OpCode::MS3 | OpCode::MSG |
|
OpCode::MNA | OpCode::MS2 | OpCode::MS3 |
|
||||||
OpCode::PRI | OpCode::RMU | OpCode::SAT | OpCode::SLP | OpCode::SMC | OpCode::SPS |
|
OpCode::RMU | OpCode::SAT | OpCode::SLP | OpCode::SMC | OpCode::SPS |
|
||||||
OpCode::STC | OpCode::SVP | OpCode::TUR | OpCode::WAS | OpCode::ZAM => {
|
OpCode::STC | OpCode::SVP | OpCode::TUR | OpCode::WAS | OpCode::ZAM => {
|
||||||
println!("unimplemented opcode: {:?}", op);
|
println!("unimplemented opcode: {:?}", op);
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
// 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::WAI | OpCode::FAC |
|
OpCode::MYB | OpCode::MYD | OpCode::FAI | OpCode::FAO | OpCode::FAC |
|
||||||
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::MLp |
|
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 |
|
||||||
OpCode::XX1 | OpCode::SIL | OpCode::LIp | OpCode::SOU | OpCode::CMU |
|
OpCode::XX1 | OpCode::SIL | OpCode::LIp | OpCode::SOU | OpCode::CMU |
|
||||||
OpCode::SSS | OpCode::ACH => {
|
OpCode::SSS | OpCode::ACH => {
|
||||||
|
|
@ -447,6 +573,8 @@ impl TextScriptVM {
|
||||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
exec_state = TextScriptExecutionState::Ended;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Ok(TextScriptExecutionState::Ended);
|
return Ok(TextScriptExecutionState::Ended);
|
||||||
|
|
@ -531,7 +659,7 @@ impl TextScript {
|
||||||
println!("{:x?}", &bytecode);
|
println!("{:x?}", &bytecode);
|
||||||
event_map.insert(event_num, bytecode);
|
event_map.insert(event_num, bytecode);
|
||||||
}
|
}
|
||||||
b'\r' | b'\n' => {
|
b'\r' | b'\n' | b' ' => {
|
||||||
iter.next();
|
iter.next();
|
||||||
}
|
}
|
||||||
n => {
|
n => {
|
||||||
|
|
|
||||||
|
|
@ -159,4 +159,9 @@ impl TextureSet {
|
||||||
|
|
||||||
Ok(self.tex_map.get_mut(name).unwrap())
|
Ok(self.tex_map.get_mut(name).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn draw_text(&mut self, ctx: &mut Context, text: &str) -> GameResult {
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue