2022-03-23 22:09:32 +00:00
|
|
|
use imgui::{CollapsingHeader, Condition, ImStr, ImString, Slider, Window};
|
2020-11-24 23:08:27 +00:00
|
|
|
use itertools::Itertools;
|
|
|
|
|
2021-03-15 21:08:30 +00:00
|
|
|
use crate::framework::context::Context;
|
|
|
|
use crate::framework::error::GameResult;
|
2022-12-22 22:26:46 +00:00
|
|
|
use crate::game::scripting::tsc::text_script::TextScriptExecutionState;
|
2022-11-19 17:20:03 +00:00
|
|
|
use crate::game::shared_game_state::SharedGameState;
|
2020-08-19 13:11:34 +00:00
|
|
|
use crate::scene::game_scene::GameScene;
|
2020-08-19 11:21:40 +00:00
|
|
|
|
2022-08-21 22:10:33 +00:00
|
|
|
use self::command_line::CommandLineParser;
|
|
|
|
|
|
|
|
pub mod command_line;
|
|
|
|
|
2020-11-24 23:08:27 +00:00
|
|
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
|
|
|
#[repr(u8)]
|
|
|
|
pub enum ScriptType {
|
|
|
|
Scene,
|
|
|
|
Global,
|
|
|
|
Inventory,
|
|
|
|
StageSelect,
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:21:40 +00:00
|
|
|
pub struct LiveDebugger {
|
2020-08-20 18:31:47 +00:00
|
|
|
map_selector_visible: bool,
|
2020-08-27 02:43:21 +00:00
|
|
|
events_visible: bool,
|
2020-09-10 23:40:45 +00:00
|
|
|
flags_visible: bool,
|
2021-03-15 21:08:30 +00:00
|
|
|
npc_inspector_visible: bool,
|
2022-04-24 15:01:31 +00:00
|
|
|
hotkey_list_visible: bool,
|
2022-08-21 22:10:33 +00:00
|
|
|
command_line_parser: CommandLineParser,
|
2020-08-27 02:43:21 +00:00
|
|
|
last_stage_id: usize,
|
2020-08-19 13:11:34 +00:00
|
|
|
stages: Vec<ImString>,
|
2020-08-27 02:43:21 +00:00
|
|
|
selected_stage: i32,
|
|
|
|
events: Vec<ImString>,
|
2020-11-24 23:08:27 +00:00
|
|
|
event_ids: Vec<(ScriptType, u16)>,
|
2020-08-27 02:43:21 +00:00
|
|
|
selected_event: i32,
|
2020-11-24 23:08:27 +00:00
|
|
|
text_windows: Vec<(u32, ImString, ImString)>,
|
2020-08-19 13:11:34 +00:00
|
|
|
error: Option<ImString>,
|
2020-08-19 11:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl LiveDebugger {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
2020-08-20 18:31:47 +00:00
|
|
|
map_selector_visible: false,
|
2020-08-27 02:43:21 +00:00
|
|
|
events_visible: false,
|
2020-09-10 23:40:45 +00:00
|
|
|
flags_visible: false,
|
2021-03-15 21:08:30 +00:00
|
|
|
npc_inspector_visible: false,
|
2022-04-24 15:01:31 +00:00
|
|
|
hotkey_list_visible: false,
|
2022-08-21 22:10:33 +00:00
|
|
|
command_line_parser: CommandLineParser::new(),
|
2020-08-27 02:43:21 +00:00
|
|
|
last_stage_id: usize::MAX,
|
|
|
|
stages: Vec::new(),
|
|
|
|
selected_stage: -1,
|
|
|
|
events: Vec::new(),
|
|
|
|
event_ids: Vec::new(),
|
|
|
|
selected_event: -1,
|
2020-11-24 23:08:27 +00:00
|
|
|
text_windows: Vec::new(),
|
2020-08-19 13:11:34 +00:00
|
|
|
error: None,
|
2020-08-19 11:21:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
pub fn run_ingame(
|
|
|
|
&mut self,
|
|
|
|
game_scene: &mut GameScene,
|
|
|
|
state: &mut SharedGameState,
|
|
|
|
ctx: &mut Context,
|
|
|
|
ui: &mut imgui::Ui,
|
|
|
|
) -> GameResult {
|
2020-08-27 02:43:21 +00:00
|
|
|
if self.last_stage_id != game_scene.stage_id {
|
|
|
|
self.last_stage_id = game_scene.stage_id;
|
|
|
|
self.events.clear();
|
|
|
|
self.selected_event = -1;
|
|
|
|
}
|
|
|
|
|
2022-08-21 22:10:33 +00:00
|
|
|
if state.command_line {
|
|
|
|
let width = state.screen_size.0;
|
|
|
|
let height = 85.0;
|
|
|
|
let x = 0.0 as f32;
|
|
|
|
let y = state.screen_size.1 - height;
|
|
|
|
|
|
|
|
Window::new("Command Line")
|
|
|
|
.position([x, y], Condition::FirstUseEver)
|
|
|
|
.size([width, height], Condition::FirstUseEver)
|
|
|
|
.resizable(false)
|
|
|
|
.collapsible(false)
|
|
|
|
.movable(false)
|
|
|
|
.build(ui, || {
|
|
|
|
ui.text("Command:");
|
|
|
|
ui.same_line();
|
|
|
|
|
|
|
|
ui.input_text("", &mut self.command_line_parser.buffer).build();
|
|
|
|
|
|
|
|
if ui.is_item_active() {
|
|
|
|
state.control_flags.set_tick_world(false);
|
|
|
|
} else {
|
|
|
|
state.control_flags.set_tick_world(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
ui.same_line();
|
|
|
|
if ui.is_key_released(imgui::Key::Enter) || ui.button("Execute") {
|
|
|
|
log::info!("Executing command: {}", self.command_line_parser.buffer);
|
|
|
|
match self.command_line_parser.push(self.command_line_parser.buffer.clone()) {
|
|
|
|
Some(mut command) => match command.execute(game_scene, state) {
|
|
|
|
Ok(()) => {
|
|
|
|
self.command_line_parser.last_feedback = command.feedback_string();
|
|
|
|
self.command_line_parser.last_feedback_color = [0.0, 1.0, 0.0, 1.0];
|
|
|
|
state.sound_manager.play_sfx(5);
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
self.command_line_parser.last_feedback = e.to_string();
|
|
|
|
self.command_line_parser.last_feedback_color = [1.0, 0.0, 0.0, 1.0];
|
|
|
|
state.sound_manager.play_sfx(12);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
self.command_line_parser.last_feedback = "Invalid command".to_string();
|
|
|
|
self.command_line_parser.last_feedback_color = [1.0, 0.0, 0.0, 1.0];
|
|
|
|
state.sound_manager.play_sfx(12);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ui.text_colored(
|
|
|
|
self.command_line_parser.last_feedback_color,
|
|
|
|
self.command_line_parser.last_feedback.clone(),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-04-19 19:13:18 +00:00
|
|
|
if !state.debugger {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
Window::new("Debugger")
|
2020-11-24 23:08:27 +00:00
|
|
|
.resizable(false)
|
2021-02-10 11:53:49 +00:00
|
|
|
.collapsed(true, Condition::FirstUseEver)
|
2020-08-20 18:31:47 +00:00
|
|
|
.position([5.0, 5.0], Condition::FirstUseEver)
|
2022-08-21 22:10:33 +00:00
|
|
|
.size([400.0, 265.0], Condition::FirstUseEver)
|
2020-08-19 11:21:40 +00:00
|
|
|
.build(ui, || {
|
|
|
|
ui.text(format!(
|
2020-11-24 23:08:27 +00:00
|
|
|
"Player position: ({:.1},{:.1}), velocity: ({:.1},{:.1})",
|
2020-11-28 19:25:51 +00:00
|
|
|
game_scene.player1.x as f32 / 512.0,
|
|
|
|
game_scene.player1.y as f32 / 512.0,
|
|
|
|
game_scene.player1.vel_x as f32 / 512.0,
|
|
|
|
game_scene.player1.vel_y as f32 / 512.0,
|
2020-08-20 18:31:47 +00:00
|
|
|
));
|
|
|
|
|
2020-09-23 13:10:42 +00:00
|
|
|
ui.text(format!(
|
2021-06-27 01:06:56 +00:00
|
|
|
"frame: ({:.1},{:.1} -> {:.1},{:.1} / {})",
|
|
|
|
game_scene.frame.x as f32 / 512.0,
|
|
|
|
game_scene.frame.y as f32 / 512.0,
|
|
|
|
game_scene.frame.target_x as f32 / 512.0,
|
|
|
|
game_scene.frame.target_y as f32 / 512.0,
|
|
|
|
game_scene.frame.wait
|
2020-09-23 13:10:42 +00:00
|
|
|
));
|
|
|
|
|
2020-08-20 18:31:47 +00:00
|
|
|
ui.text(format!(
|
2021-06-27 01:06:56 +00:00
|
|
|
"NPC Count: {}/{}/{} Booster fuel: {}",
|
|
|
|
game_scene.npc_list.iter_alive().count(),
|
|
|
|
game_scene.npc_list.current_capacity(),
|
|
|
|
game_scene.npc_list.max_capacity(),
|
|
|
|
game_scene.player1.booster_fuel
|
2020-08-19 11:21:40 +00:00
|
|
|
));
|
2020-08-20 18:31:47 +00:00
|
|
|
|
2020-11-24 23:08:27 +00:00
|
|
|
ui.text(format!("Game speed ({:.1} TPS):", state.current_tps()));
|
|
|
|
let mut speed = state.settings.speed;
|
2021-12-02 08:21:06 +00:00
|
|
|
Slider::new("", 0.1, 3.0).build(ui, &mut speed);
|
|
|
|
ui.same_line();
|
|
|
|
if ui.button("Reset") {
|
2020-11-24 23:08:27 +00:00
|
|
|
speed = 1.0
|
|
|
|
}
|
|
|
|
|
2020-12-04 12:35:30 +00:00
|
|
|
#[allow(clippy::float_cmp)]
|
2020-11-24 23:08:27 +00:00
|
|
|
if state.settings.speed != speed {
|
|
|
|
state.set_speed(speed);
|
|
|
|
}
|
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
if ui.button("Maps") {
|
2020-09-10 13:24:04 +00:00
|
|
|
self.map_selector_visible = !self.map_selector_visible;
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
2020-08-23 02:16:31 +00:00
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.same_line();
|
|
|
|
if ui.button("TSC Scripts") {
|
2020-09-10 13:24:04 +00:00
|
|
|
self.events_visible = !self.events_visible;
|
2020-08-27 02:43:21 +00:00
|
|
|
}
|
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.same_line();
|
|
|
|
if ui.button("Flags") {
|
2020-09-10 23:40:45 +00:00
|
|
|
self.flags_visible = !self.flags_visible;
|
|
|
|
}
|
2020-12-04 17:37:47 +00:00
|
|
|
|
2021-10-15 14:36:05 +00:00
|
|
|
#[cfg(feature = "scripting-lua")]
|
2022-12-22 22:26:46 +00:00
|
|
|
{
|
|
|
|
ui.same_line();
|
|
|
|
if ui.button("Reload Lua Scripts") {
|
|
|
|
if let Err(err) = state.lua.reload_scripts(ctx) {
|
|
|
|
log::error!("Error reloading scripts: {:?}", err);
|
|
|
|
self.error = Some(ImString::new(err.to_string()));
|
2021-01-01 01:46:01 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-22 22:26:46 +00:00
|
|
|
}
|
2021-01-01 01:46:01 +00:00
|
|
|
|
2020-12-04 17:37:47 +00:00
|
|
|
if game_scene.player2.cond.alive() {
|
2021-12-02 08:21:06 +00:00
|
|
|
if ui.button("Drop Player 2") {
|
2020-12-04 17:37:47 +00:00
|
|
|
game_scene.drop_player2();
|
|
|
|
}
|
2021-12-02 08:21:06 +00:00
|
|
|
} else if ui.button("Add Player 2") {
|
2022-12-22 22:26:46 +00:00
|
|
|
game_scene.add_player2(state, ctx);
|
2020-12-04 17:37:47 +00:00
|
|
|
}
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.same_line();
|
2021-03-15 21:08:30 +00:00
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
if ui.button("NPC Inspector") {
|
2021-03-15 21:08:30 +00:00
|
|
|
self.npc_inspector_visible = !self.npc_inspector_visible;
|
|
|
|
}
|
2022-04-24 15:01:31 +00:00
|
|
|
ui.same_line();
|
|
|
|
|
|
|
|
if state.textscript_vm.state == TextScriptExecutionState::Ended {
|
|
|
|
if ui.button("Save") {
|
|
|
|
let _ = state.save_game(game_scene, ctx);
|
2022-08-21 19:06:06 +00:00
|
|
|
state.sound_manager.play_sfx(18);
|
2022-04-24 15:01:31 +00:00
|
|
|
}
|
2022-12-22 22:26:46 +00:00
|
|
|
} else if ui.button("Busy") {
|
|
|
|
}
|
2022-04-24 15:01:31 +00:00
|
|
|
|
|
|
|
ui.same_line();
|
|
|
|
if ui.button("Hotkey List") {
|
|
|
|
self.hotkey_list_visible = !self.hotkey_list_visible;
|
|
|
|
}
|
2022-08-21 19:06:06 +00:00
|
|
|
|
2022-08-21 22:10:33 +00:00
|
|
|
if ui.button("Command Line") {
|
|
|
|
state.command_line = !state.command_line;
|
|
|
|
}
|
|
|
|
|
2022-04-24 15:01:31 +00:00
|
|
|
ui.checkbox("noclip", &mut state.settings.noclip);
|
2022-08-21 19:06:06 +00:00
|
|
|
ui.same_line();
|
2022-08-16 11:47:11 +00:00
|
|
|
ui.checkbox("more rust", &mut state.more_rust);
|
2020-08-20 18:31:47 +00:00
|
|
|
});
|
2020-08-19 13:11:34 +00:00
|
|
|
|
2020-08-20 18:31:47 +00:00
|
|
|
if self.map_selector_visible {
|
2021-12-02 08:21:06 +00:00
|
|
|
Window::new("Map selector")
|
2020-08-20 18:31:47 +00:00
|
|
|
.resizable(false)
|
2020-11-24 23:08:27 +00:00
|
|
|
.position([80.0, 80.0], Condition::Appearing)
|
|
|
|
.size([240.0, 280.0], Condition::Appearing)
|
2020-08-20 18:31:47 +00:00
|
|
|
.build(ui, || {
|
|
|
|
if self.stages.is_empty() {
|
2022-01-17 22:29:30 +00:00
|
|
|
for s in &state.stages {
|
2020-08-20 18:31:47 +00:00
|
|
|
self.stages.push(ImString::new(s.name.to_owned()));
|
|
|
|
}
|
2020-08-19 13:11:34 +00:00
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
self.selected_stage =
|
|
|
|
match state.stages.iter().find_position(|s| s.name == game_scene.stage.data.name) {
|
|
|
|
Some((pos, _)) => pos as i32,
|
|
|
|
_ => -1,
|
|
|
|
};
|
2020-08-20 18:31:47 +00:00
|
|
|
}
|
|
|
|
let stages: Vec<&ImStr> = self.stages.iter().map(|e| e.as_ref()).collect();
|
2020-08-19 13:11:34 +00:00
|
|
|
|
2020-08-20 18:31:47 +00:00
|
|
|
ui.push_item_width(-1.0);
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.list_box("", &mut self.selected_stage, &stages, 10);
|
2020-08-19 13:11:34 +00:00
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
if ui.button("Load") {
|
2020-08-27 02:43:21 +00:00
|
|
|
match GameScene::new(state, ctx, self.selected_stage as usize) {
|
2020-08-20 18:31:47 +00:00
|
|
|
Ok(mut scene) => {
|
2021-06-27 01:06:56 +00:00
|
|
|
let tile_size = scene.stage.map.tile_size.as_int() * 0x200;
|
2020-11-28 19:25:51 +00:00
|
|
|
scene.inventory_player1 = game_scene.inventory_player1.clone();
|
2020-12-04 12:35:30 +00:00
|
|
|
scene.inventory_player2 = game_scene.inventory_player2.clone();
|
|
|
|
|
2020-11-28 19:25:51 +00:00
|
|
|
scene.player1 = game_scene.player1.clone();
|
2021-06-27 01:06:56 +00:00
|
|
|
scene.player1.x = scene.stage.map.width as i32 / 2 * tile_size;
|
|
|
|
scene.player1.y = scene.stage.map.height as i32 / 2 * tile_size;
|
2020-09-10 23:40:45 +00:00
|
|
|
|
2020-11-28 19:25:51 +00:00
|
|
|
if scene.player1.life == 0 {
|
|
|
|
scene.player1.life = scene.player1.max_life;
|
2020-09-10 23:40:45 +00:00
|
|
|
}
|
|
|
|
|
2020-12-04 12:35:30 +00:00
|
|
|
scene.player2 = game_scene.player2.clone();
|
2021-06-27 01:06:56 +00:00
|
|
|
scene.player2.x = scene.stage.map.width as i32 / 2 * tile_size;
|
|
|
|
scene.player2.y = scene.stage.map.height as i32 / 2 * tile_size;
|
2020-12-04 12:35:30 +00:00
|
|
|
|
|
|
|
if scene.player2.life == 0 {
|
|
|
|
scene.player2.life = scene.player1.max_life;
|
|
|
|
}
|
|
|
|
|
2021-01-01 01:46:01 +00:00
|
|
|
state.textscript_vm.suspend = true;
|
|
|
|
state.textscript_vm.state = TextScriptExecutionState::Running(94, 0);
|
2020-08-20 18:31:47 +00:00
|
|
|
state.next_scene = Some(Box::new(scene));
|
|
|
|
}
|
|
|
|
Err(e) => {
|
2020-08-26 01:07:04 +00:00
|
|
|
log::error!("Error loading map: {:?}", e);
|
2020-08-20 18:31:47 +00:00
|
|
|
self.error = Some(ImString::new(e.to_string()));
|
|
|
|
}
|
2020-08-19 13:11:34 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-20 18:31:47 +00:00
|
|
|
});
|
|
|
|
}
|
2020-08-19 11:21:40 +00:00
|
|
|
|
2020-08-27 02:43:21 +00:00
|
|
|
if self.events_visible {
|
2021-12-02 08:21:06 +00:00
|
|
|
Window::new("TSC Scripts")
|
2020-08-27 02:43:21 +00:00
|
|
|
.resizable(false)
|
2020-11-24 23:08:27 +00:00
|
|
|
.position([80.0, 80.0], Condition::Appearing)
|
2021-10-16 02:37:42 +00:00
|
|
|
.size([300.0, 320.0], Condition::Appearing)
|
2020-08-27 02:43:21 +00:00
|
|
|
.build(ui, || {
|
|
|
|
if self.events.is_empty() {
|
|
|
|
self.event_ids.clear();
|
|
|
|
|
2021-10-16 02:37:42 +00:00
|
|
|
let scripts = state.textscript_vm.scripts.borrow();
|
2020-11-24 23:08:27 +00:00
|
|
|
|
2021-10-16 02:37:42 +00:00
|
|
|
for event in scripts.scene_script.get_event_ids() {
|
2020-11-24 23:08:27 +00:00
|
|
|
self.events.push(ImString::new(format!("Scene: #{:04}", event)));
|
|
|
|
self.event_ids.push((ScriptType::Scene, event));
|
|
|
|
}
|
|
|
|
|
2021-10-16 02:37:42 +00:00
|
|
|
for event in scripts.global_script.get_event_ids() {
|
2020-08-27 02:43:21 +00:00
|
|
|
self.events.push(ImString::new(format!("Global: #{:04}", event)));
|
2020-11-24 23:08:27 +00:00
|
|
|
self.event_ids.push((ScriptType::Global, event));
|
2020-08-27 02:43:21 +00:00
|
|
|
}
|
|
|
|
|
2021-10-16 02:37:42 +00:00
|
|
|
for event in scripts.inventory_script.get_event_ids() {
|
2020-11-24 23:08:27 +00:00
|
|
|
self.events.push(ImString::new(format!("Inventory: #{:04}", event)));
|
|
|
|
self.event_ids.push((ScriptType::Inventory, event));
|
|
|
|
}
|
|
|
|
|
2021-10-16 02:37:42 +00:00
|
|
|
for event in scripts.stage_select_script.get_event_ids() {
|
2020-11-24 23:08:27 +00:00
|
|
|
self.events.push(ImString::new(format!("Stage Select: #{:04}", event)));
|
|
|
|
self.event_ids.push((ScriptType::StageSelect, event));
|
2020-08-27 02:43:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
let events: Vec<&ImStr> = self.events.iter().map(|e| e.as_ref()).collect();
|
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.text_wrapped(&ImString::new(format!(
|
|
|
|
"TextScript execution state: {:?}",
|
|
|
|
state.textscript_vm.state
|
|
|
|
)));
|
|
|
|
ui.text_wrapped(&ImString::new(format!(
|
|
|
|
"CreditScript execution state: {:?}",
|
|
|
|
state.creditscript_vm.state
|
|
|
|
)));
|
2020-08-27 02:43:21 +00:00
|
|
|
|
|
|
|
ui.push_item_width(-1.0);
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.list_box("", &mut self.selected_event, &events, 10);
|
2020-08-27 02:43:21 +00:00
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
if ui.button("Execute") {
|
2020-08-27 02:43:21 +00:00
|
|
|
assert_eq!(self.event_ids.len(), self.events.len());
|
|
|
|
|
2020-11-24 23:08:27 +00:00
|
|
|
if let Some((_, event_num)) = self.event_ids.get(self.selected_event as usize) {
|
2020-09-25 12:55:28 +00:00
|
|
|
state.control_flags.set_tick_world(true);
|
2020-09-21 23:53:46 +00:00
|
|
|
state.control_flags.set_interactions_disabled(true);
|
2020-11-24 23:08:27 +00:00
|
|
|
state.textscript_vm.start_script(*event_num);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.same_line();
|
|
|
|
if ui.button("Decompile") {
|
2020-11-24 23:08:27 +00:00
|
|
|
if let Some((stype, event_num)) = self.event_ids.get(self.selected_event as usize) {
|
|
|
|
let id = ((*stype as u32) << 16) | (*event_num as u32);
|
|
|
|
if !self.text_windows.iter().any(|(e, _, _)| *e == id) {
|
2021-10-16 02:37:42 +00:00
|
|
|
let scripts = state.textscript_vm.scripts.borrow();
|
2020-11-24 23:08:27 +00:00
|
|
|
let script = match stype {
|
2021-10-16 02:37:42 +00:00
|
|
|
ScriptType::Scene => &scripts.scene_script,
|
|
|
|
ScriptType::Global => &scripts.global_script,
|
|
|
|
ScriptType::Inventory => &scripts.inventory_script,
|
|
|
|
ScriptType::StageSelect => &scripts.stage_select_script,
|
2020-11-24 23:08:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
match script.decompile_event(*event_num) {
|
|
|
|
Ok(code) => {
|
|
|
|
self.text_windows.push((
|
|
|
|
id,
|
|
|
|
ImString::new(format!("Decompiled event: #{:04}", *event_num)),
|
2021-12-02 08:21:06 +00:00
|
|
|
ImString::new(code),
|
2020-11-24 23:08:27 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
Err(e) => {
|
2021-12-02 08:21:06 +00:00
|
|
|
self.error = Some(ImString::new(format!(
|
|
|
|
"Error decompiling TextScript #{:04}: {}",
|
|
|
|
*event_num, e
|
|
|
|
)));
|
2020-11-24 23:08:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-27 02:43:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-09-10 23:40:45 +00:00
|
|
|
if self.flags_visible {
|
2021-12-02 08:21:06 +00:00
|
|
|
Window::new("Flags")
|
2020-09-10 23:40:45 +00:00
|
|
|
.position([80.0, 80.0], Condition::FirstUseEver)
|
|
|
|
.size([280.0, 300.0], Condition::FirstUseEver)
|
|
|
|
.build(ui, || {
|
2022-01-17 22:29:30 +00:00
|
|
|
if CollapsingHeader::new("Control flags").default_open(false).build(ui) {
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.checkbox_flags("Tick world", &mut state.control_flags.0, 1);
|
|
|
|
ui.checkbox_flags("Control enabled", &mut state.control_flags.0, 2);
|
|
|
|
ui.checkbox_flags("Interactions disabled", &mut state.control_flags.0, 4);
|
|
|
|
ui.checkbox_flags("Credits running", &mut state.control_flags.0, 8);
|
2020-11-24 23:08:27 +00:00
|
|
|
ui.separator();
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.checkbox_flags("[Internal] Windy level", &mut state.control_flags.0, 15);
|
2020-11-24 23:08:27 +00:00
|
|
|
}
|
|
|
|
|
2022-01-17 22:29:30 +00:00
|
|
|
if CollapsingHeader::new("Player condition flags").default_open(false).build(ui) {
|
|
|
|
cond_flags(ui, &mut game_scene.player1.cond);
|
2020-11-24 23:08:27 +00:00
|
|
|
}
|
|
|
|
|
2022-01-17 22:29:30 +00:00
|
|
|
if CollapsingHeader::new("Player equipment").default_open(false).build(ui) {
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.checkbox_flags("Booster 0.8", &mut game_scene.player1.equip.0, 1);
|
|
|
|
ui.checkbox_flags("Map System", &mut game_scene.player1.equip.0, 2);
|
|
|
|
ui.checkbox_flags("Arms Barrier", &mut game_scene.player1.equip.0, 4);
|
|
|
|
ui.checkbox_flags("Turbocharge", &mut game_scene.player1.equip.0, 8);
|
|
|
|
ui.checkbox_flags("Air Tank", &mut game_scene.player1.equip.0, 16);
|
|
|
|
ui.checkbox_flags("Booster 2.0", &mut game_scene.player1.equip.0, 32);
|
|
|
|
ui.checkbox_flags("Mimiga Mask", &mut game_scene.player1.equip.0, 64);
|
|
|
|
ui.checkbox_flags("Whimsical Star", &mut game_scene.player1.equip.0, 128);
|
|
|
|
ui.checkbox_flags("Nikumaru Counter", &mut game_scene.player1.equip.0, 256);
|
2020-11-24 23:08:27 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-03-15 21:08:30 +00:00
|
|
|
if self.npc_inspector_visible {
|
2021-12-02 08:21:06 +00:00
|
|
|
Window::new("NPC Inspector")
|
2021-03-15 21:08:30 +00:00
|
|
|
.position([80.0, 80.0], Condition::FirstUseEver)
|
|
|
|
.size([280.0, 300.0], Condition::FirstUseEver)
|
|
|
|
.scrollable(true)
|
|
|
|
.always_vertical_scrollbar(true)
|
|
|
|
.build(ui, || {
|
|
|
|
for npc in game_scene.npc_list.iter_alive() {
|
2021-12-02 08:21:06 +00:00
|
|
|
if CollapsingHeader::new(&ImString::from(format!("id={} type={}", npc.id, npc.npc_type)))
|
|
|
|
.default_open(false)
|
2022-01-17 22:29:30 +00:00
|
|
|
.build(ui)
|
2021-12-02 08:21:06 +00:00
|
|
|
{
|
2021-03-15 21:08:30 +00:00
|
|
|
let mut position = [npc.x as f32 / 512.0, npc.y as f32 / 512.0];
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.input_float2("Position:", &mut position).build();
|
2021-03-15 21:08:30 +00:00
|
|
|
|
|
|
|
npc.x = (position[0] * 512.0) as i32;
|
|
|
|
npc.y = (position[1] * 512.0) as i32;
|
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
let content = &ImString::from(format!(
|
|
|
|
"\
|
2021-03-15 21:08:30 +00:00
|
|
|
Velocity: ({:.1},{:.1})\n\
|
|
|
|
Vel2/State2: ({:.1},{:.1} / {} {})\n\
|
|
|
|
Animation: frame={}, counter={}\n\
|
|
|
|
Action: num={}, counter={}, counter2={}\n\
|
|
|
|
Health: {}, Experience drop: {}\n\
|
|
|
|
Event ID: {}, Flag ID: {}\n\
|
|
|
|
Parent: {}, Shock: {}, Size: {}",
|
2021-12-02 08:21:06 +00:00
|
|
|
npc.vel_x as f32 / 512.0,
|
|
|
|
npc.vel_y as f32 / 512.0,
|
|
|
|
npc.vel_x2 as f32 / 512.0,
|
|
|
|
npc.vel_y2 as f32 / 512.0,
|
|
|
|
npc.vel_x2,
|
|
|
|
npc.vel_y2,
|
|
|
|
npc.anim_num,
|
|
|
|
npc.anim_counter,
|
|
|
|
npc.action_num,
|
|
|
|
npc.action_counter,
|
|
|
|
npc.action_counter2,
|
|
|
|
npc.life,
|
|
|
|
npc.exp,
|
|
|
|
npc.event_num,
|
|
|
|
npc.flag_num,
|
|
|
|
npc.parent_id,
|
|
|
|
npc.shock,
|
|
|
|
npc.size
|
2021-03-15 21:08:30 +00:00
|
|
|
));
|
|
|
|
ui.text_wrapped(content);
|
|
|
|
|
2022-01-17 22:29:30 +00:00
|
|
|
cond_flags(ui, &mut npc.cond);
|
2021-03-15 21:08:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-04-24 15:01:31 +00:00
|
|
|
if self.hotkey_list_visible {
|
|
|
|
Window::new("Hotkeys")
|
|
|
|
.position([400.0, 5.0], Condition::FirstUseEver)
|
2022-08-21 22:10:33 +00:00
|
|
|
.size([300.0, 300.0], Condition::FirstUseEver)
|
2022-04-24 15:01:31 +00:00
|
|
|
.resizable(false)
|
|
|
|
.build(ui, || {
|
|
|
|
let key = vec![
|
|
|
|
"ESC + F2 > Quick Reset",
|
|
|
|
"F3 > Godmode",
|
|
|
|
"F4 > Infinite Booster Fuel",
|
|
|
|
"F5 > Toggle Subpixel Scrolling",
|
|
|
|
"F6 > Toggle Motion Interpolation",
|
|
|
|
"F7 > Reset TPS",
|
|
|
|
"F8 > Decrease TPS",
|
|
|
|
"F9 > Increase TPS",
|
|
|
|
"F10 > Debug Overlay",
|
|
|
|
"F11 > Toggle FPS Counter",
|
|
|
|
"F12 > Toggle Debugger",
|
2022-08-21 22:10:33 +00:00
|
|
|
"` > Toggle Command Line",
|
2022-07-09 13:49:56 +00:00
|
|
|
"Ctrl + F3 > Reload Sound Manager",
|
2022-08-21 19:06:06 +00:00
|
|
|
"Ctrl + S > Quick Save",
|
2022-04-24 15:01:31 +00:00
|
|
|
];
|
|
|
|
for hotkeys in key.iter() {
|
|
|
|
match hotkeys {
|
|
|
|
_ => "",
|
|
|
|
};
|
|
|
|
ui.bullet();
|
|
|
|
ui.same_line();
|
|
|
|
ui.text(format!("{}", hotkeys));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2022-08-21 22:10:33 +00:00
|
|
|
|
2020-11-24 23:08:27 +00:00
|
|
|
let mut remove = -1;
|
|
|
|
for (idx, (_, title, contents)) in self.text_windows.iter().enumerate() {
|
|
|
|
let mut opened = true;
|
|
|
|
|
|
|
|
Window::new(title)
|
|
|
|
.position([100.0, 100.0], Condition::FirstUseEver)
|
|
|
|
.size([400.0, 300.0], Condition::FirstUseEver)
|
|
|
|
.opened(&mut opened)
|
|
|
|
.build(ui, || {
|
|
|
|
ui.text_wrapped(contents);
|
|
|
|
});
|
|
|
|
|
|
|
|
if !opened {
|
|
|
|
remove = idx as i32;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if remove >= 0 {
|
|
|
|
self.text_windows.remove(remove as usize);
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.error.is_some() {
|
2021-12-02 08:21:06 +00:00
|
|
|
Window::new("Error!")
|
2020-11-24 23:08:27 +00:00
|
|
|
.resizable(false)
|
|
|
|
.collapsible(false)
|
2021-12-02 08:21:06 +00:00
|
|
|
.position(
|
|
|
|
[((state.screen_size.0 - 300.0) / 2.0).floor(), ((state.screen_size.1 - 100.0) / 2.0).floor()],
|
|
|
|
Condition::Appearing,
|
|
|
|
)
|
2020-11-24 23:08:27 +00:00
|
|
|
.size([300.0, 100.0], Condition::Appearing)
|
|
|
|
.build(ui, || {
|
|
|
|
ui.push_item_width(-1.0);
|
|
|
|
ui.text_wrapped(self.error.as_ref().unwrap());
|
|
|
|
|
2021-12-02 08:21:06 +00:00
|
|
|
if ui.button("OK") {
|
2020-11-24 23:08:27 +00:00
|
|
|
self.error = None;
|
2020-09-10 23:40:45 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:21:40 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2020-11-24 23:08:27 +00:00
|
|
|
|
|
|
|
fn cond_flags(ui: &imgui::Ui, cond: &mut crate::common::Condition) {
|
2021-12-02 08:21:06 +00:00
|
|
|
ui.checkbox_flags("Interacted", &mut cond.0, 1);
|
|
|
|
ui.checkbox_flags("Hidden", &mut cond.0, 2);
|
|
|
|
ui.checkbox_flags("Fallen", &mut cond.0, 4);
|
|
|
|
ui.checkbox_flags("Built-in NPC destroy handler", &mut cond.0, 8);
|
|
|
|
ui.checkbox_flags("Damage first boss NPC", &mut cond.0, 16);
|
|
|
|
ui.checkbox_flags("Increased acceleration", &mut cond.0, 32);
|
|
|
|
ui.checkbox_flags("Unknown (0x40)", &mut cond.0, 64);
|
|
|
|
ui.checkbox_flags("Alive", &mut cond.0, 128);
|
2020-11-24 23:08:27 +00:00
|
|
|
}
|