mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-05-22 14:51:05 +00:00
run arbitrary TSC from debug command line
This commit is contained in:
parent
a25dc297ef
commit
670e6891c1
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue