run arbitrary TSC from debug command line

This commit is contained in:
Sallai József 2022-08-22 03:08:57 +03:00
parent a25dc297ef
commit 670e6891c1
3 changed files with 56 additions and 8 deletions

View File

@ -3,10 +3,11 @@ use num_traits::FromPrimitive;
use crate::framework::error::{GameError::CommandLineError, GameResult};
use crate::npc::NPC;
use crate::scene::game_scene::GameScene;
use crate::scripting::tsc::text_script::{ScriptMode, TextScript, TextScriptEncoding};
use crate::shared_game_state::SharedGameState;
use crate::weapon::WeaponType;
#[derive(Clone, Copy)]
#[derive(Clone)]
pub enum CommandLineCommand {
AddItem(u16),
RemoveItem(u16),
@ -20,6 +21,7 @@ pub enum CommandLineCommand {
RemoveXP(u16),
SetMaxHP(u16),
SpawnNPC(u16),
TSC(String),
}
impl CommandLineCommand {
@ -30,6 +32,10 @@ impl CommandLineCommand {
let command = components[0];
if command.starts_with("<") {
return Some(CommandLineCommand::TSC(components.join(" ").replace("\\n", "\n")));
}
match command.replacen("/", "", 1).as_str() {
"add_item" => {
if components.len() < 2 {
@ -138,6 +144,14 @@ impl CommandLineCommand {
return Some(CommandLineCommand::SpawnNPC(npc_id.unwrap()));
}
}
"tsc" => {
if components.len() < 2 {
return None;
}
let script = components[1..].join(" ").replace("\\n", "\n");
return Some(CommandLineCommand::TSC(script));
}
_ => return None,
}
@ -145,7 +159,7 @@ impl CommandLineCommand {
}
pub fn execute(&mut self, game_scene: &mut GameScene, state: &mut SharedGameState) -> GameResult {
match *self {
match self.clone() {
CommandLineCommand::AddItem(item_id) => {
game_scene.inventory_player1.add_item(item_id);
}
@ -213,6 +227,19 @@ impl CommandLineCommand {
npc.x = game_scene.player1.x + game_scene.player1.direction.vector_x() * (0x2000 * 3);
game_scene.npc_list.spawn(0x100, npc)?;
}
CommandLineCommand::TSC(script) => {
log::info!("Executing TSC script: {}", format!("#9999\n{}", script));
match TextScript::compile(format!("#9999\n{}", script).as_bytes(), true, TextScriptEncoding::UTF8) {
Ok(text_script) => {
state.textscript_vm.set_debug_script(text_script);
state.textscript_vm.set_mode(ScriptMode::Debug);
state.textscript_vm.start_script(9999);
}
Err(err) => {
return Err(CommandLineError(format!("Error compiling TSC: {}", err)));
}
};
}
}
Ok(())
@ -233,6 +260,7 @@ impl CommandLineCommand {
CommandLineCommand::RemoveXP(xp_count) => format!("/remove_xp {}", xp_count),
CommandLineCommand::SetMaxHP(hp_count) => format!("/set_max_hp {}", hp_count),
CommandLineCommand::SpawnNPC(npc_id) => format!("/spawn_npc {}", npc_id),
CommandLineCommand::TSC(script) => format!("/tsc {}", script.replace("\n", "\\n")),
}
}
@ -254,6 +282,7 @@ impl CommandLineCommand {
CommandLineCommand::RemoveXP(xp_count) => format!("Removed {} XP from current weapon.", xp_count),
CommandLineCommand::SetMaxHP(hp_count) => format!("Set max HP of player to {}.", hp_count),
CommandLineCommand::SpawnNPC(npc_id) => format!("Spawned NPC ID {} in front of player.", npc_id),
CommandLineCommand::TSC(_) => "Executed TSC script.".to_string(),
}
}
}
@ -283,7 +312,7 @@ impl CommandLineParser {
match command {
Some(command) => {
self.command_history.push(command);
self.command_history.push(command.clone());
self.cursor = self.command_history.len() - 1;
Some(command)

View File

@ -1806,7 +1806,7 @@ impl Scene for GameScene {
self.map_system.tick(state, ctx, &self.stage, [&self.player1, &self.player2])?;
match state.textscript_vm.mode {
ScriptMode::Map => {
ScriptMode::Map | ScriptMode::Debug => {
TextScriptVM::run(state, self, ctx)?;
match state.textscript_vm.state {
@ -1991,7 +1991,7 @@ impl Scene for GameScene {
}
match state.textscript_vm.mode {
ScriptMode::Map if state.control_flags.control_enabled() => {
ScriptMode::Map | ScriptMode::Debug if state.control_flags.control_enabled() => {
self.hud_player1.draw(state, ctx, &self.frame)?;
self.hud_player2.draw(state, ctx, &self.frame)?;
self.boss_life_bar.draw(state, ctx, &self.frame)?;
@ -2158,11 +2158,11 @@ impl Scene for GameScene {
self.map_system.draw(state, ctx, &self.stage, [&self.player1, &self.player2])?;
self.fade.draw(state, ctx, &self.frame)?;
if state.textscript_vm.mode == ScriptMode::Map {
if state.textscript_vm.mode == ScriptMode::Map || state.textscript_vm.mode == ScriptMode::Debug {
self.nikumaru.draw(state, ctx, &self.frame)?;
}
if state.textscript_vm.mode == ScriptMode::Map
if (state.textscript_vm.mode == ScriptMode::Map || state.textscript_vm.mode == ScriptMode::Debug)
&& state.textscript_vm.state != TextScriptExecutionState::MapSystem
&& self.map_name_counter > 0
{

View File

@ -68,6 +68,7 @@ pub enum ScriptMode {
Map,
Inventory,
StageSelect,
Debug,
}
impl Not for ConfirmSelection {
@ -145,12 +146,20 @@ pub struct Scripts {
pub inventory_script: TextScript,
/// StageSelect.tsc - used by teleport target selector
pub stage_select_script: TextScript,
/// Debug TSC sink - used by the debug command line
pub debug_script: TextScript,
}
impl Scripts {
pub fn find_script(&self, mode: ScriptMode, event_num: u16) -> Option<&Vec<u8>> {
match mode {
ScriptMode::Map => {
ScriptMode::Map | ScriptMode::Debug => {
if mode == ScriptMode::Debug {
if let Some(tsc) = self.debug_script.event_map.get(&event_num) {
return Some(tsc);
}
}
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) {
@ -181,6 +190,7 @@ impl TextScriptVM {
scene_script: TextScript::new(),
inventory_script: TextScript::new(),
stage_select_script: TextScript::new(),
debug_script: TextScript::new(),
})),
state: TextScriptExecutionState::Ended,
stack: Vec::with_capacity(6),
@ -236,6 +246,11 @@ impl TextScriptVM {
scripts.stage_select_script = script;
}
pub fn set_debug_script(&mut self, script: TextScript) {
let mut scripts = self.scripts.borrow_mut();
scripts.debug_script = script;
}
pub fn set_substitution_rect_map(&mut self, rect_map: HashMap<char, Rect<u16>>) {
self.substitution_rect_map = rect_map;
}
@ -670,6 +685,10 @@ impl TextScriptVM {
state.textscript_vm.flags.set_background_visible(false);
state.textscript_vm.stack.clear();
if state.textscript_vm.mode == ScriptMode::Debug {
state.textscript_vm.set_mode(ScriptMode::Map);
}
game_scene.player1.cond.set_interacted(false);
game_scene.player2.cond.set_interacted(false);