From 6a84c732b1f21c0c1333389d2dd17232f9d02c33 Mon Sep 17 00:00:00 2001 From: Alula Date: Sun, 23 Aug 2020 04:17:45 +0200 Subject: [PATCH] initial textscript things --- Cargo.toml | 3 +- src/stage.rs | 6 ++ src/text_script.rs | 150 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 155 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fa927ad..744b99e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ maplit = "1.0.2" mint = "0.5" nalgebra = {version = "0.18", features = ["mint"] } num-traits = "0.2.12" +owning_ref = "0.4.1" paste = "1.0.0" pretty_env_logger = "0.4.0" serde = "1" @@ -41,5 +42,5 @@ smart-default = "0.5" strum = "0.18.0" strum_macros = "0.18.0" toml = "0.5" -owning_ref = "0.4.1" +varint = "0.9.0" winit = { version = "0.19.3" } diff --git a/src/stage.rs b/src/stage.rs index 45e9203..2732ed9 100644 --- a/src/stage.rs +++ b/src/stage.rs @@ -8,6 +8,7 @@ use log::info; use crate::ggez::{Context, filesystem, GameResult}; use crate::ggez::GameError::ResourceLoadError; use crate::map::Map; +use crate::text_script::TextScript; #[derive(Debug, PartialEq, Eq, Hash)] pub struct NpcType { @@ -371,17 +372,22 @@ impl StageData { pub struct Stage { pub map: Map, pub data: StageData, + pub text_script: TextScript, } 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 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)?; let stage = Self { map, data: data.clone(), + text_script, }; Ok(stage) diff --git a/src/text_script.rs b/src/text_script.rs index f276224..360e93f 100644 --- a/src/text_script.rs +++ b/src/text_script.rs @@ -1,11 +1,155 @@ -use crate::ggez::{Context, GameResult}; +use std::io; -struct TextScript { +use crate::ggez::GameResult; +/// Engine's internal text script VM operation codes. +/// Based on https://www.cavestory.org/guides/basicmodding/guide/tscnotes.htm and game reverse engineering. +pub enum OpCode { + // ---- Internal opcodes (used by bytecode, no TSC representation) + /// internal: no operation + NOP, + + // ---- Official opcodes ---- + /// GameResult { + /// Loads, decrypts and compiles a text script from specified stream. + pub fn load_from(mut data: R) -> GameResult { + let mut buf = Vec::new(); + data.read_to_end(&mut buf)?; + + let half = buf.len() / 2; + let key = if let Some(0) = buf.get(half) { + 0xf9 + } else { + (-(*buf.get(half).unwrap() as isize)) as u8 + }; + + for (idx, byte) in buf.iter_mut().enumerate() { + if idx == half { + continue; + } + + *byte = byte.wrapping_add(key); + } + + TextScript::compile(&buf) + } + + /// Compiles a decrypted text script data into internal bytecode. + pub fn compile(data: &[u8]) -> GameResult { + println!("data: {}", String::from_utf8(data.to_vec())?); + let tsc = TextScript {}; Ok(tsc) }