mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-05-23 23:31:25 +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::framework::error::{GameError::CommandLineError, GameResult};
|
||||||
use crate::npc::NPC;
|
use crate::npc::NPC;
|
||||||
use crate::scene::game_scene::GameScene;
|
use crate::scene::game_scene::GameScene;
|
||||||
|
use crate::scripting::tsc::text_script::{ScriptMode, TextScript, TextScriptEncoding};
|
||||||
use crate::shared_game_state::SharedGameState;
|
use crate::shared_game_state::SharedGameState;
|
||||||
use crate::weapon::WeaponType;
|
use crate::weapon::WeaponType;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone)]
|
||||||
pub enum CommandLineCommand {
|
pub enum CommandLineCommand {
|
||||||
AddItem(u16),
|
AddItem(u16),
|
||||||
RemoveItem(u16),
|
RemoveItem(u16),
|
||||||
|
@ -20,6 +21,7 @@ pub enum CommandLineCommand {
|
||||||
RemoveXP(u16),
|
RemoveXP(u16),
|
||||||
SetMaxHP(u16),
|
SetMaxHP(u16),
|
||||||
SpawnNPC(u16),
|
SpawnNPC(u16),
|
||||||
|
TSC(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandLineCommand {
|
impl CommandLineCommand {
|
||||||
|
@ -30,6 +32,10 @@ impl CommandLineCommand {
|
||||||
|
|
||||||
let command = components[0];
|
let command = components[0];
|
||||||
|
|
||||||
|
if command.starts_with("<") {
|
||||||
|
return Some(CommandLineCommand::TSC(components.join(" ").replace("\\n", "\n")));
|
||||||
|
}
|
||||||
|
|
||||||
match command.replacen("/", "", 1).as_str() {
|
match command.replacen("/", "", 1).as_str() {
|
||||||
"add_item" => {
|
"add_item" => {
|
||||||
if components.len() < 2 {
|
if components.len() < 2 {
|
||||||
|
@ -138,6 +144,14 @@ impl CommandLineCommand {
|
||||||
return Some(CommandLineCommand::SpawnNPC(npc_id.unwrap()));
|
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,
|
_ => return None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +159,7 @@ impl CommandLineCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(&mut self, game_scene: &mut GameScene, state: &mut SharedGameState) -> GameResult {
|
pub fn execute(&mut self, game_scene: &mut GameScene, state: &mut SharedGameState) -> GameResult {
|
||||||
match *self {
|
match self.clone() {
|
||||||
CommandLineCommand::AddItem(item_id) => {
|
CommandLineCommand::AddItem(item_id) => {
|
||||||
game_scene.inventory_player1.add_item(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);
|
npc.x = game_scene.player1.x + game_scene.player1.direction.vector_x() * (0x2000 * 3);
|
||||||
game_scene.npc_list.spawn(0x100, npc)?;
|
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(())
|
Ok(())
|
||||||
|
@ -233,6 +260,7 @@ impl CommandLineCommand {
|
||||||
CommandLineCommand::RemoveXP(xp_count) => format!("/remove_xp {}", xp_count),
|
CommandLineCommand::RemoveXP(xp_count) => format!("/remove_xp {}", xp_count),
|
||||||
CommandLineCommand::SetMaxHP(hp_count) => format!("/set_max_hp {}", hp_count),
|
CommandLineCommand::SetMaxHP(hp_count) => format!("/set_max_hp {}", hp_count),
|
||||||
CommandLineCommand::SpawnNPC(npc_id) => format!("/spawn_npc {}", npc_id),
|
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::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::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::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 {
|
match command {
|
||||||
Some(command) => {
|
Some(command) => {
|
||||||
self.command_history.push(command);
|
self.command_history.push(command.clone());
|
||||||
self.cursor = self.command_history.len() - 1;
|
self.cursor = self.command_history.len() - 1;
|
||||||
|
|
||||||
Some(command)
|
Some(command)
|
||||||
|
|
|
@ -1806,7 +1806,7 @@ impl Scene for GameScene {
|
||||||
self.map_system.tick(state, ctx, &self.stage, [&self.player1, &self.player2])?;
|
self.map_system.tick(state, ctx, &self.stage, [&self.player1, &self.player2])?;
|
||||||
|
|
||||||
match state.textscript_vm.mode {
|
match state.textscript_vm.mode {
|
||||||
ScriptMode::Map => {
|
ScriptMode::Map | ScriptMode::Debug => {
|
||||||
TextScriptVM::run(state, self, ctx)?;
|
TextScriptVM::run(state, self, ctx)?;
|
||||||
|
|
||||||
match state.textscript_vm.state {
|
match state.textscript_vm.state {
|
||||||
|
@ -1991,7 +1991,7 @@ impl Scene for GameScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
match state.textscript_vm.mode {
|
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_player1.draw(state, ctx, &self.frame)?;
|
||||||
self.hud_player2.draw(state, ctx, &self.frame)?;
|
self.hud_player2.draw(state, ctx, &self.frame)?;
|
||||||
self.boss_life_bar.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.map_system.draw(state, ctx, &self.stage, [&self.player1, &self.player2])?;
|
||||||
self.fade.draw(state, ctx, &self.frame)?;
|
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)?;
|
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
|
&& state.textscript_vm.state != TextScriptExecutionState::MapSystem
|
||||||
&& self.map_name_counter > 0
|
&& self.map_name_counter > 0
|
||||||
{
|
{
|
||||||
|
|
|
@ -68,6 +68,7 @@ pub enum ScriptMode {
|
||||||
Map,
|
Map,
|
||||||
Inventory,
|
Inventory,
|
||||||
StageSelect,
|
StageSelect,
|
||||||
|
Debug,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Not for ConfirmSelection {
|
impl Not for ConfirmSelection {
|
||||||
|
@ -145,12 +146,20 @@ pub struct Scripts {
|
||||||
pub inventory_script: TextScript,
|
pub inventory_script: TextScript,
|
||||||
/// StageSelect.tsc - used by teleport target selector
|
/// StageSelect.tsc - used by teleport target selector
|
||||||
pub stage_select_script: TextScript,
|
pub stage_select_script: TextScript,
|
||||||
|
/// Debug TSC sink - used by the debug command line
|
||||||
|
pub debug_script: TextScript,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scripts {
|
impl Scripts {
|
||||||
pub fn find_script(&self, mode: ScriptMode, event_num: u16) -> Option<&Vec<u8>> {
|
pub fn find_script(&self, mode: ScriptMode, event_num: u16) -> Option<&Vec<u8>> {
|
||||||
match mode {
|
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) {
|
if let Some(tsc) = self.scene_script.event_map.get(&event_num) {
|
||||||
return Some(tsc);
|
return Some(tsc);
|
||||||
} else if let Some(tsc) = self.global_script.event_map.get(&event_num) {
|
} else if let Some(tsc) = self.global_script.event_map.get(&event_num) {
|
||||||
|
@ -181,6 +190,7 @@ impl TextScriptVM {
|
||||||
scene_script: TextScript::new(),
|
scene_script: TextScript::new(),
|
||||||
inventory_script: TextScript::new(),
|
inventory_script: TextScript::new(),
|
||||||
stage_select_script: TextScript::new(),
|
stage_select_script: TextScript::new(),
|
||||||
|
debug_script: TextScript::new(),
|
||||||
})),
|
})),
|
||||||
state: TextScriptExecutionState::Ended,
|
state: TextScriptExecutionState::Ended,
|
||||||
stack: Vec::with_capacity(6),
|
stack: Vec::with_capacity(6),
|
||||||
|
@ -236,6 +246,11 @@ impl TextScriptVM {
|
||||||
scripts.stage_select_script = script;
|
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>>) {
|
pub fn set_substitution_rect_map(&mut self, rect_map: HashMap<char, Rect<u16>>) {
|
||||||
self.substitution_rect_map = rect_map;
|
self.substitution_rect_map = rect_map;
|
||||||
}
|
}
|
||||||
|
@ -670,6 +685,10 @@ impl TextScriptVM {
|
||||||
state.textscript_vm.flags.set_background_visible(false);
|
state.textscript_vm.flags.set_background_visible(false);
|
||||||
state.textscript_vm.stack.clear();
|
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.player1.cond.set_interacted(false);
|
||||||
game_scene.player2.cond.set_interacted(false);
|
game_scene.player2.cond.set_interacted(false);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue