mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2025-01-19 17:00:15 +00:00
Fix issue with not being able to reopen menu after fighter reset/reentry into training
This commit is contained in:
parent
17f2b05940
commit
88abeadfdd
2 changed files with 620 additions and 613 deletions
|
@ -1,464 +1,465 @@
|
||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
use crate::events::{Event, EVENT_QUEUE};
|
use crate::events::{Event, EVENT_QUEUE};
|
||||||
use crate::training::frame_counter;
|
use crate::training::frame_counter;
|
||||||
|
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use ramhorns::Template;
|
use ramhorns::Template;
|
||||||
use skyline::info::get_program_id;
|
use skyline::info::get_program_id;
|
||||||
use skyline::nn::hid::NpadGcState;
|
use skyline::nn::hid::NpadGcState;
|
||||||
use skyline::nn::web::WebSessionBootMode;
|
use skyline::nn::web::WebSessionBootMode;
|
||||||
use skyline_web::{Background, WebSession, Webpage};
|
use skyline_web::{Background, WebSession, Webpage};
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use training_mod_consts::{MenuJsonStruct, TrainingModpackMenu};
|
use training_mod_consts::{MenuJsonStruct, TrainingModpackMenu};
|
||||||
use training_mod_tui::Color;
|
use training_mod_tui::Color;
|
||||||
|
|
||||||
static mut FRAME_COUNTER_INDEX: usize = 0;
|
static mut FRAME_COUNTER_INDEX: usize = 0;
|
||||||
pub static mut QUICK_MENU_FRAME_COUNTER_INDEX: usize = 0;
|
pub static mut QUICK_MENU_FRAME_COUNTER_INDEX: usize = 0;
|
||||||
const MENU_LOCKOUT_FRAMES: u32 = 15;
|
const MENU_LOCKOUT_FRAMES: u32 = 15;
|
||||||
pub static mut QUICK_MENU_ACTIVE: bool = false;
|
pub static mut QUICK_MENU_ACTIVE: bool = false;
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
unsafe {
|
unsafe {
|
||||||
FRAME_COUNTER_INDEX = frame_counter::register_counter();
|
FRAME_COUNTER_INDEX = frame_counter::register_counter();
|
||||||
QUICK_MENU_FRAME_COUNTER_INDEX = frame_counter::register_counter();
|
QUICK_MENU_FRAME_COUNTER_INDEX = frame_counter::register_counter();
|
||||||
write_menu();
|
write_menu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn menu_condition(module_accessor: &mut smash::app::BattleObjectModuleAccessor) -> bool {
|
pub unsafe fn menu_condition(module_accessor: &mut smash::app::BattleObjectModuleAccessor) -> bool {
|
||||||
// also ensure quick menu is reset
|
// also ensure quick menu is reset
|
||||||
if frame_counter::get_frame_count(QUICK_MENU_FRAME_COUNTER_INDEX) > 60 {
|
if frame_counter::get_frame_count(QUICK_MENU_FRAME_COUNTER_INDEX) > 60 {
|
||||||
frame_counter::full_reset(QUICK_MENU_FRAME_COUNTER_INDEX);
|
frame_counter::full_reset(QUICK_MENU_FRAME_COUNTER_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only check for button combination if the counter is 0 (not locked out)
|
// Only check for button combination if the counter is 0 (not locked out)
|
||||||
match frame_counter::get_frame_count(FRAME_COUNTER_INDEX) {
|
match frame_counter::get_frame_count(FRAME_COUNTER_INDEX) {
|
||||||
0 => {
|
0 => {
|
||||||
ControlModule::check_button_on(module_accessor, *CONTROL_PAD_BUTTON_SPECIAL)
|
ControlModule::check_button_on(module_accessor, *CONTROL_PAD_BUTTON_SPECIAL)
|
||||||
&& ControlModule::check_button_on_trriger(
|
&& ControlModule::check_button_on_trriger(
|
||||||
module_accessor,
|
module_accessor,
|
||||||
*CONTROL_PAD_BUTTON_APPEAL_HI,
|
*CONTROL_PAD_BUTTON_APPEAL_HI,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
1..MENU_LOCKOUT_FRAMES => false,
|
1..MENU_LOCKOUT_FRAMES => false,
|
||||||
_ => {
|
_ => {
|
||||||
// Waited longer than the lockout time, reset the counter so the menu can be opened again
|
// Waited longer than the lockout time, reset the counter so the menu can be opened again
|
||||||
frame_counter::full_reset(FRAME_COUNTER_INDEX);
|
frame_counter::full_reset(FRAME_COUNTER_INDEX);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn write_menu() {
|
pub unsafe fn write_menu() {
|
||||||
let tpl = Template::new(include_str!("../templates/menu.html")).unwrap();
|
let tpl = Template::new(include_str!("../templates/menu.html")).unwrap();
|
||||||
|
|
||||||
let overall_menu = get_menu();
|
let overall_menu = get_menu();
|
||||||
|
|
||||||
let data = tpl.render(&overall_menu);
|
let data = tpl.render(&overall_menu);
|
||||||
|
|
||||||
// Now that we have the html, write it to file
|
// Now that we have the html, write it to file
|
||||||
// From skyline-web
|
// From skyline-web
|
||||||
let program_id = get_program_id();
|
let program_id = get_program_id();
|
||||||
let htdocs_dir = "training_modpack";
|
let htdocs_dir = "training_modpack";
|
||||||
let menu_html_path = Path::new("sd:/atmosphere/contents")
|
let menu_html_path = Path::new("sd:/atmosphere/contents")
|
||||||
.join(&format!("{:016X}", program_id))
|
.join(&format!("{:016X}", program_id))
|
||||||
.join(&format!("manual_html/html-document/{}.htdocs/", htdocs_dir))
|
.join(&format!("manual_html/html-document/{}.htdocs/", htdocs_dir))
|
||||||
.join("training_menu.html");
|
.join("training_menu.html");
|
||||||
|
|
||||||
let write_resp = fs::write(menu_html_path, data);
|
let write_resp = fs::write(menu_html_path, data);
|
||||||
if write_resp.is_err() {
|
if write_resp.is_err() {
|
||||||
println!("Error!: {}", write_resp.err().unwrap());
|
println!("Error!: {}", write_resp.err().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MENU_CONF_PATH: &str = "sd:/TrainingModpack/training_modpack_menu.conf";
|
const MENU_CONF_PATH: &str = "sd:/TrainingModpack/training_modpack_menu.conf";
|
||||||
|
|
||||||
pub unsafe fn set_menu_from_json(message: &str) {
|
pub unsafe fn set_menu_from_json(message: &str) {
|
||||||
if MENU.quick_menu == OnOff::Off {
|
if MENU.quick_menu == OnOff::Off {
|
||||||
if is_emulator() {
|
if is_emulator() {
|
||||||
skyline::error::show_error(
|
skyline::error::show_error(
|
||||||
0x69,
|
0x69,
|
||||||
"Cannot use web menu on emulator.\n\0",
|
"Cannot use web menu on emulator.\n\0",
|
||||||
"Only the quick menu is runnable via emulator currently.\n\0",
|
"Only the quick menu is runnable via emulator currently.\n\0",
|
||||||
);
|
);
|
||||||
MENU.quick_menu = OnOff::On;
|
MENU.quick_menu = OnOff::On;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Ok(message_json) = serde_json::from_str::<MenuJsonStruct>(message) {
|
if let Ok(message_json) = serde_json::from_str::<MenuJsonStruct>(message) {
|
||||||
// Includes both MENU and DEFAULTS_MENU
|
// Includes both MENU and DEFAULTS_MENU
|
||||||
// From Web Applet
|
// From Web Applet
|
||||||
MENU = message_json.menu;
|
MENU = message_json.menu;
|
||||||
DEFAULTS_MENU = message_json.defaults_menu;
|
DEFAULTS_MENU = message_json.defaults_menu;
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
MENU_CONF_PATH,
|
MENU_CONF_PATH,
|
||||||
serde_json::to_string_pretty(&message_json).unwrap(),
|
serde_json::to_string_pretty(&message_json).unwrap(),
|
||||||
)
|
)
|
||||||
.expect("Failed to write menu conf file");
|
.expect("Failed to write menu conf file");
|
||||||
} else if let Ok(message_json) = serde_json::from_str::<TrainingModpackMenu>(message) {
|
} else if let Ok(message_json) = serde_json::from_str::<TrainingModpackMenu>(message) {
|
||||||
// Only includes MENU
|
// Only includes MENU
|
||||||
// From TUI
|
// From TUI
|
||||||
MENU = message_json;
|
MENU = message_json;
|
||||||
|
|
||||||
let conf = MenuJsonStruct {
|
let conf = MenuJsonStruct {
|
||||||
menu: MENU,
|
menu: MENU,
|
||||||
defaults_menu: DEFAULTS_MENU,
|
defaults_menu: DEFAULTS_MENU,
|
||||||
};
|
};
|
||||||
std::fs::write(MENU_CONF_PATH, serde_json::to_string_pretty(&conf).unwrap())
|
std::fs::write(MENU_CONF_PATH, serde_json::to_string_pretty(&conf).unwrap())
|
||||||
.expect("Failed to write menu conf file");
|
.expect("Failed to write menu conf file");
|
||||||
} else {
|
} else {
|
||||||
skyline::error::show_error(
|
skyline::error::show_error(
|
||||||
0x70,
|
0x70,
|
||||||
"Could not parse the menu response!\nPlease send a screenshot of the details page to the developers.\n\0",
|
"Could not parse the menu response!\nPlease send a screenshot of the details page to the developers.\n\0",
|
||||||
message
|
message
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
EVENT_QUEUE.push(Event::menu_open(message.to_string()));
|
EVENT_QUEUE.push(Event::menu_open(message.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_menu() {
|
pub fn spawn_menu() {
|
||||||
unsafe {
|
unsafe {
|
||||||
frame_counter::reset_frame_count(FRAME_COUNTER_INDEX);
|
frame_counter::reset_frame_count(FRAME_COUNTER_INDEX);
|
||||||
frame_counter::start_counting(FRAME_COUNTER_INDEX);
|
frame_counter::start_counting(FRAME_COUNTER_INDEX);
|
||||||
frame_counter::reset_frame_count(QUICK_MENU_FRAME_COUNTER_INDEX);
|
frame_counter::reset_frame_count(QUICK_MENU_FRAME_COUNTER_INDEX);
|
||||||
frame_counter::start_counting(QUICK_MENU_FRAME_COUNTER_INDEX);
|
frame_counter::start_counting(QUICK_MENU_FRAME_COUNTER_INDEX);
|
||||||
|
|
||||||
if MENU.quick_menu == OnOff::Off {
|
if MENU.quick_menu == OnOff::Off {
|
||||||
WEB_MENU_ACTIVE = true;
|
WEB_MENU_ACTIVE = true;
|
||||||
} else {
|
} else {
|
||||||
QUICK_MENU_ACTIVE = true;
|
QUICK_MENU_ACTIVE = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ButtonPresses {
|
pub struct ButtonPresses {
|
||||||
pub a: ButtonPress,
|
pub a: ButtonPress,
|
||||||
pub b: ButtonPress,
|
pub b: ButtonPress,
|
||||||
pub zr: ButtonPress,
|
pub zr: ButtonPress,
|
||||||
pub zl: ButtonPress,
|
pub zl: ButtonPress,
|
||||||
pub left: ButtonPress,
|
pub left: ButtonPress,
|
||||||
pub right: ButtonPress,
|
pub right: ButtonPress,
|
||||||
pub up: ButtonPress,
|
pub up: ButtonPress,
|
||||||
pub down: ButtonPress,
|
pub down: ButtonPress,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ButtonPress {
|
pub struct ButtonPress {
|
||||||
pub prev_frame_is_pressed: bool,
|
pub prev_frame_is_pressed: bool,
|
||||||
pub is_pressed: bool,
|
pub is_pressed: bool,
|
||||||
pub lockout_frames: usize,
|
pub lockout_frames: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ButtonPress {
|
impl ButtonPress {
|
||||||
pub fn default() -> ButtonPress {
|
pub fn default() -> ButtonPress {
|
||||||
ButtonPress {
|
ButtonPress {
|
||||||
prev_frame_is_pressed: false,
|
prev_frame_is_pressed: false,
|
||||||
is_pressed: false,
|
is_pressed: false,
|
||||||
lockout_frames: 0,
|
lockout_frames: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_press(&mut self) -> bool {
|
pub fn read_press(&mut self) -> bool {
|
||||||
let is_pressed = self.is_pressed;
|
let is_pressed = self.is_pressed;
|
||||||
if self.is_pressed {
|
if self.is_pressed {
|
||||||
self.is_pressed = false;
|
self.is_pressed = false;
|
||||||
if self.lockout_frames == 0 {
|
if self.lockout_frames == 0 {
|
||||||
self.prev_frame_is_pressed = true;
|
self.prev_frame_is_pressed = true;
|
||||||
self.lockout_frames = 10;
|
self.lockout_frames = 10;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.lockout_frames > 0 {
|
if self.lockout_frames > 0 {
|
||||||
self.lockout_frames -= 1;
|
self.lockout_frames -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.prev_frame_is_pressed = is_pressed;
|
self.prev_frame_is_pressed = is_pressed;
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static mut BUTTON_PRESSES: ButtonPresses = ButtonPresses {
|
pub static mut BUTTON_PRESSES: ButtonPresses = ButtonPresses {
|
||||||
a: ButtonPress {
|
a: ButtonPress {
|
||||||
prev_frame_is_pressed: false,
|
prev_frame_is_pressed: false,
|
||||||
is_pressed: false,
|
is_pressed: false,
|
||||||
lockout_frames: 0,
|
lockout_frames: 0,
|
||||||
},
|
},
|
||||||
b: ButtonPress {
|
b: ButtonPress {
|
||||||
prev_frame_is_pressed: false,
|
prev_frame_is_pressed: false,
|
||||||
is_pressed: false,
|
is_pressed: false,
|
||||||
lockout_frames: 0,
|
lockout_frames: 0,
|
||||||
},
|
},
|
||||||
zr: ButtonPress {
|
zr: ButtonPress {
|
||||||
prev_frame_is_pressed: false,
|
prev_frame_is_pressed: false,
|
||||||
is_pressed: false,
|
is_pressed: false,
|
||||||
lockout_frames: 0,
|
lockout_frames: 0,
|
||||||
},
|
},
|
||||||
zl: ButtonPress {
|
zl: ButtonPress {
|
||||||
prev_frame_is_pressed: false,
|
prev_frame_is_pressed: false,
|
||||||
is_pressed: false,
|
is_pressed: false,
|
||||||
lockout_frames: 0,
|
lockout_frames: 0,
|
||||||
},
|
},
|
||||||
left: ButtonPress {
|
left: ButtonPress {
|
||||||
prev_frame_is_pressed: false,
|
prev_frame_is_pressed: false,
|
||||||
is_pressed: false,
|
is_pressed: false,
|
||||||
lockout_frames: 0,
|
lockout_frames: 0,
|
||||||
},
|
},
|
||||||
right: ButtonPress {
|
right: ButtonPress {
|
||||||
prev_frame_is_pressed: false,
|
prev_frame_is_pressed: false,
|
||||||
is_pressed: false,
|
is_pressed: false,
|
||||||
lockout_frames: 0,
|
lockout_frames: 0,
|
||||||
},
|
},
|
||||||
up: ButtonPress {
|
up: ButtonPress {
|
||||||
prev_frame_is_pressed: false,
|
prev_frame_is_pressed: false,
|
||||||
is_pressed: false,
|
is_pressed: false,
|
||||||
lockout_frames: 0,
|
lockout_frames: 0,
|
||||||
},
|
},
|
||||||
down: ButtonPress {
|
down: ButtonPress {
|
||||||
prev_frame_is_pressed: false,
|
prev_frame_is_pressed: false,
|
||||||
is_pressed: false,
|
is_pressed: false,
|
||||||
lockout_frames: 0,
|
lockout_frames: 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn handle_get_npad_state(state: *mut NpadGcState, _controller_id: *const u32) {
|
pub fn handle_get_npad_state(state: *mut NpadGcState, _controller_id: *const u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if menu::QUICK_MENU_ACTIVE {
|
if menu::QUICK_MENU_ACTIVE {
|
||||||
// TODO: This should make more sense, look into.
|
// TODO: This should make more sense, look into.
|
||||||
// BUTTON_PRESSES.a.is_pressed = (*state).Buttons & (1 << 0) > 0;
|
// BUTTON_PRESSES.a.is_pressed = (*state).Buttons & (1 << 0) > 0;
|
||||||
// BUTTON_PRESSES.b.is_pressed = (*state).Buttons & (1 << 1) > 0;
|
// BUTTON_PRESSES.b.is_pressed = (*state).Buttons & (1 << 1) > 0;
|
||||||
// BUTTON_PRESSES.zl.is_pressed = (*state).Buttons & (1 << 8) > 0;
|
// BUTTON_PRESSES.zl.is_pressed = (*state).Buttons & (1 << 8) > 0;
|
||||||
// BUTTON_PRESSES.zr.is_pressed = (*state).Buttons & (1 << 9) > 0;
|
// BUTTON_PRESSES.zr.is_pressed = (*state).Buttons & (1 << 9) > 0;
|
||||||
// BUTTON_PRESSES.left.is_pressed = (*state).Buttons & ((1 << 12) | (1 << 16)) > 0;
|
// BUTTON_PRESSES.left.is_pressed = (*state).Buttons & ((1 << 12) | (1 << 16)) > 0;
|
||||||
// BUTTON_PRESSES.right.is_pressed = (*state).Buttons & ((1 << 14) | (1 << 18)) > 0;
|
// BUTTON_PRESSES.right.is_pressed = (*state).Buttons & ((1 << 14) | (1 << 18)) > 0;
|
||||||
// BUTTON_PRESSES.down.is_pressed = (*state).Buttons & ((1 << 15) | (1 << 19)) > 0;
|
// BUTTON_PRESSES.down.is_pressed = (*state).Buttons & ((1 << 15) | (1 << 19)) > 0;
|
||||||
// BUTTON_PRESSES.up.is_pressed = (*state).Buttons & ((1 << 13) | (1 << 17)) > 0;
|
// BUTTON_PRESSES.up.is_pressed = (*state).Buttons & ((1 << 13) | (1 << 17)) > 0;
|
||||||
|
|
||||||
if frame_counter::get_frame_count(FRAME_COUNTER_INDEX) != 0 {
|
if frame_counter::get_frame_count(FRAME_COUNTER_INDEX) != 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*state).Buttons & (1 << 0) > 0 {
|
if (*state).Buttons & (1 << 0) > 0 {
|
||||||
BUTTON_PRESSES.a.is_pressed = true;
|
BUTTON_PRESSES.a.is_pressed = true;
|
||||||
}
|
}
|
||||||
if (*state).Buttons & (1 << 1) > 0 {
|
if (*state).Buttons & (1 << 1) > 0 {
|
||||||
BUTTON_PRESSES.b.is_pressed = true;
|
BUTTON_PRESSES.b.is_pressed = true;
|
||||||
}
|
}
|
||||||
if (*state).Buttons & (1 << 8) > 0 {
|
if (*state).Buttons & (1 << 8) > 0 {
|
||||||
BUTTON_PRESSES.zl.is_pressed = true;
|
BUTTON_PRESSES.zl.is_pressed = true;
|
||||||
}
|
}
|
||||||
if (*state).Buttons & (1 << 9) > 0 {
|
if (*state).Buttons & (1 << 9) > 0 {
|
||||||
BUTTON_PRESSES.zr.is_pressed = true;
|
BUTTON_PRESSES.zr.is_pressed = true;
|
||||||
}
|
}
|
||||||
if (*state).Buttons & ((1 << 12) | (1 << 16)) > 0 {
|
if (*state).Buttons & ((1 << 12) | (1 << 16)) > 0 {
|
||||||
BUTTON_PRESSES.left.is_pressed = true;
|
BUTTON_PRESSES.left.is_pressed = true;
|
||||||
}
|
}
|
||||||
if (*state).Buttons & ((1 << 14) | (1 << 18)) > 0 {
|
if (*state).Buttons & ((1 << 14) | (1 << 18)) > 0 {
|
||||||
BUTTON_PRESSES.right.is_pressed = true;
|
BUTTON_PRESSES.right.is_pressed = true;
|
||||||
}
|
}
|
||||||
if (*state).Buttons & ((1 << 15) | (1 << 19)) > 0 {
|
if (*state).Buttons & ((1 << 15) | (1 << 19)) > 0 {
|
||||||
BUTTON_PRESSES.down.is_pressed = true;
|
BUTTON_PRESSES.down.is_pressed = true;
|
||||||
}
|
}
|
||||||
if (*state).Buttons & ((1 << 13) | (1 << 17)) > 0 {
|
if (*state).Buttons & ((1 << 13) | (1 << 17)) > 0 {
|
||||||
BUTTON_PRESSES.up.is_pressed = true;
|
BUTTON_PRESSES.up.is_pressed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're here, remove all other Npad presses...
|
// If we're here, remove all other Npad presses...
|
||||||
// Should we exclude the home button?
|
// Should we exclude the home button?
|
||||||
(*state) = NpadGcState::default();
|
(*state) = NpadGcState::default();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "render_text_to_screen"]
|
#[link_name = "render_text_to_screen"]
|
||||||
pub fn render_text_to_screen_cstr(str: *const skyline::libc::c_char);
|
pub fn render_text_to_screen_cstr(str: *const skyline::libc::c_char);
|
||||||
|
|
||||||
#[link_name = "set_should_display_text_to_screen"]
|
#[link_name = "set_should_display_text_to_screen"]
|
||||||
pub fn set_should_display_text_to_screen(toggle: bool);
|
pub fn set_should_display_text_to_screen(toggle: bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! c_str {
|
macro_rules! c_str {
|
||||||
($l:tt) => {
|
($l:tt) => {
|
||||||
[$l.as_bytes(), "\u{0}".as_bytes()].concat().as_ptr()
|
[$l.as_bytes(), "\u{0}".as_bytes()].concat().as_ptr()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_text_to_screen(s: &str) {
|
pub fn render_text_to_screen(s: &str) {
|
||||||
unsafe {
|
unsafe {
|
||||||
render_text_to_screen_cstr(c_str!(s));
|
render_text_to_screen_cstr(c_str!(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn quick_menu_loop() {
|
pub unsafe fn quick_menu_loop() {
|
||||||
loop {
|
loop {
|
||||||
std::thread::sleep(std::time::Duration::from_secs(10));
|
std::thread::sleep(std::time::Duration::from_secs(10));
|
||||||
let menu = consts::get_menu();
|
let menu = consts::get_menu();
|
||||||
|
|
||||||
let mut app = training_mod_tui::App::new(menu);
|
let mut app = training_mod_tui::App::new(menu);
|
||||||
|
|
||||||
let backend = training_mod_tui::TestBackend::new(75, 15);
|
let backend = training_mod_tui::TestBackend::new(75, 15);
|
||||||
let mut terminal = training_mod_tui::Terminal::new(backend).unwrap();
|
let mut terminal = training_mod_tui::Terminal::new(backend).unwrap();
|
||||||
|
|
||||||
let mut has_slept_millis = 0;
|
let mut has_slept_millis = 0;
|
||||||
let render_frames = 5;
|
let render_frames = 5;
|
||||||
let mut json_response = String::new();
|
let mut json_response = String::new();
|
||||||
let button_presses = &mut menu::BUTTON_PRESSES;
|
let button_presses = &mut menu::BUTTON_PRESSES;
|
||||||
let mut received_input = true;
|
let mut received_input = true;
|
||||||
loop {
|
loop {
|
||||||
button_presses.a.read_press().then(|| {
|
button_presses.a.read_press().then(|| {
|
||||||
app.on_a();
|
app.on_a();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
let b_press = &mut button_presses.b;
|
let b_press = &mut button_presses.b;
|
||||||
b_press.read_press().then(|| {
|
b_press.read_press().then(|| {
|
||||||
received_input = true;
|
received_input = true;
|
||||||
if !app.outer_list {
|
if !app.outer_list {
|
||||||
app.on_b()
|
app.on_b()
|
||||||
} else if frame_counter::get_frame_count(menu::QUICK_MENU_FRAME_COUNTER_INDEX) == 0
|
} else if frame_counter::get_frame_count(menu::QUICK_MENU_FRAME_COUNTER_INDEX) == 0
|
||||||
{
|
{
|
||||||
// Leave menu.
|
// Leave menu.
|
||||||
menu::QUICK_MENU_ACTIVE = false;
|
menu::QUICK_MENU_ACTIVE = false;
|
||||||
menu::set_menu_from_json(&json_response);
|
menu::set_menu_from_json(&json_response);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
button_presses.zl.read_press().then(|| {
|
button_presses.zl.read_press().then(|| {
|
||||||
app.on_l();
|
app.on_l();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.zr.read_press().then(|| {
|
button_presses.zr.read_press().then(|| {
|
||||||
app.on_r();
|
app.on_r();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.left.read_press().then(|| {
|
button_presses.left.read_press().then(|| {
|
||||||
app.on_left();
|
app.on_left();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.right.read_press().then(|| {
|
button_presses.right.read_press().then(|| {
|
||||||
app.on_right();
|
app.on_right();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.up.read_press().then(|| {
|
button_presses.up.read_press().then(|| {
|
||||||
app.on_up();
|
app.on_up();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.down.read_press().then(|| {
|
button_presses.down.read_press().then(|| {
|
||||||
app.on_down();
|
app.on_down();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(16));
|
std::thread::sleep(std::time::Duration::from_millis(16));
|
||||||
has_slept_millis += 16;
|
has_slept_millis += 16;
|
||||||
if has_slept_millis < 16 * render_frames {
|
if has_slept_millis < 16 * render_frames {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
has_slept_millis = 16;
|
has_slept_millis = 16;
|
||||||
if !menu::QUICK_MENU_ACTIVE {
|
if !menu::QUICK_MENU_ACTIVE {
|
||||||
app = training_mod_tui::App::new(consts::get_menu());
|
app = training_mod_tui::App::new(consts::get_menu());
|
||||||
set_should_display_text_to_screen(false);
|
set_should_display_text_to_screen(false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if !received_input {
|
if !received_input {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut view = String::new();
|
let mut view = String::new();
|
||||||
|
|
||||||
let frame_res = terminal
|
let frame_res = terminal
|
||||||
.draw(|f| json_response = training_mod_tui::ui(f, &mut app))
|
.draw(|f| json_response = training_mod_tui::ui(f, &mut app))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
for (i, cell) in frame_res.buffer.content().iter().enumerate() {
|
for (i, cell) in frame_res.buffer.content().iter().enumerate() {
|
||||||
match cell.fg {
|
match cell.fg {
|
||||||
Color::Black => write!(&mut view, "{}", &cell.symbol.black()),
|
Color::Black => write!(&mut view, "{}", &cell.symbol.black()),
|
||||||
Color::Blue => write!(&mut view, "{}", &cell.symbol.blue()),
|
Color::Blue => write!(&mut view, "{}", &cell.symbol.blue()),
|
||||||
Color::LightBlue => write!(&mut view, "{}", &cell.symbol.bright_blue()),
|
Color::LightBlue => write!(&mut view, "{}", &cell.symbol.bright_blue()),
|
||||||
Color::Cyan => write!(&mut view, "{}", &cell.symbol.cyan()),
|
Color::Cyan => write!(&mut view, "{}", &cell.symbol.cyan()),
|
||||||
Color::LightCyan => write!(&mut view, "{}", &cell.symbol.cyan()),
|
Color::LightCyan => write!(&mut view, "{}", &cell.symbol.cyan()),
|
||||||
Color::Red => write!(&mut view, "{}", &cell.symbol.red()),
|
Color::Red => write!(&mut view, "{}", &cell.symbol.red()),
|
||||||
Color::LightRed => write!(&mut view, "{}", &cell.symbol.bright_red()),
|
Color::LightRed => write!(&mut view, "{}", &cell.symbol.bright_red()),
|
||||||
Color::LightGreen => write!(&mut view, "{}", &cell.symbol.bright_green()),
|
Color::LightGreen => write!(&mut view, "{}", &cell.symbol.bright_green()),
|
||||||
Color::Green => write!(&mut view, "{}", &cell.symbol.green()),
|
Color::Green => write!(&mut view, "{}", &cell.symbol.green()),
|
||||||
Color::Yellow => write!(&mut view, "{}", &cell.symbol.yellow()),
|
Color::Yellow => write!(&mut view, "{}", &cell.symbol.yellow()),
|
||||||
Color::LightYellow => write!(&mut view, "{}", &cell.symbol.bright_yellow()),
|
Color::LightYellow => write!(&mut view, "{}", &cell.symbol.bright_yellow()),
|
||||||
Color::Magenta => write!(&mut view, "{}", &cell.symbol.magenta()),
|
Color::Magenta => write!(&mut view, "{}", &cell.symbol.magenta()),
|
||||||
Color::LightMagenta => {
|
Color::LightMagenta => {
|
||||||
write!(&mut view, "{}", &cell.symbol.bright_magenta())
|
write!(&mut view, "{}", &cell.symbol.bright_magenta())
|
||||||
}
|
}
|
||||||
_ => write!(&mut view, "{}", &cell.symbol),
|
_ => write!(&mut view, "{}", &cell.symbol),
|
||||||
}
|
}
|
||||||
.unwrap();
|
.unwrap();
|
||||||
if i % frame_res.area.width as usize == frame_res.area.width as usize - 1 {
|
if i % frame_res.area.width as usize == frame_res.area.width as usize - 1 {
|
||||||
writeln!(&mut view).unwrap();
|
writeln!(&mut view).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeln!(&mut view).unwrap();
|
writeln!(&mut view).unwrap();
|
||||||
|
|
||||||
render_text_to_screen(view.as_str());
|
render_text_to_screen(view.as_str());
|
||||||
received_input = false;
|
received_input = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut WEB_MENU_ACTIVE: bool = false;
|
static mut WEB_MENU_ACTIVE: bool = false;
|
||||||
|
|
||||||
pub unsafe fn web_session_loop() {
|
pub unsafe fn web_session_loop() {
|
||||||
// Don't query the fightermanager too early otherwise it will crash...
|
// Don't query the FighterManager too early otherwise it will crash...
|
||||||
std::thread::sleep(std::time::Duration::new(30, 0)); // sleep for 30 secs on bootup
|
std::thread::sleep(std::time::Duration::new(30, 0)); // sleep for 30 secs on bootup
|
||||||
let mut web_session: Option<WebSession> = None;
|
let mut web_session: Option<WebSession> = None;
|
||||||
loop {
|
loop {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
if is_ready_go() & is_training_mode() {
|
if (is_ready_go() || entry_count() > 0) && is_training_mode() {
|
||||||
if web_session.is_some() {
|
if web_session.is_some() {
|
||||||
if WEB_MENU_ACTIVE {
|
if WEB_MENU_ACTIVE {
|
||||||
println!("[Training Modpack] Opening menu session...");
|
println!("[Training Modpack] Opening menu session...");
|
||||||
let session = web_session.unwrap();
|
let session = web_session.unwrap();
|
||||||
let message_send = MenuJsonStruct {
|
let message_send = MenuJsonStruct {
|
||||||
menu: MENU,
|
menu: MENU,
|
||||||
defaults_menu: DEFAULTS_MENU,
|
defaults_menu: DEFAULTS_MENU,
|
||||||
};
|
};
|
||||||
session.send_json(&message_send);
|
session.send_json(&message_send);
|
||||||
println!(
|
println!(
|
||||||
"[Training Modpack] Sending message:\n{}",
|
"[Training Modpack] Sending message:\n{}",
|
||||||
serde_json::to_string_pretty(&message_send).unwrap()
|
serde_json::to_string_pretty(&message_send).unwrap()
|
||||||
);
|
);
|
||||||
session.show();
|
session.show();
|
||||||
let message_recv = session.recv();
|
let message_recv = session.recv();
|
||||||
println!(
|
println!(
|
||||||
"[Training Modpack] Received menu from web:\n{}",
|
"[Training Modpack] Received menu from web:\n{}",
|
||||||
&message_recv
|
&message_recv
|
||||||
);
|
);
|
||||||
println!("[Training Modpack] Tearing down Training Modpack menu session");
|
println!("[Training Modpack] Tearing down Training Modpack menu session");
|
||||||
session.exit();
|
session.exit();
|
||||||
session.wait_for_exit();
|
session.wait_for_exit();
|
||||||
web_session = None;
|
web_session = None;
|
||||||
set_menu_from_json(&message_recv);
|
set_menu_from_json(&message_recv);
|
||||||
WEB_MENU_ACTIVE = false;
|
WEB_MENU_ACTIVE = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
// TODO
|
||||||
// Starting a new session causes some ingame lag.
|
// Starting a new session causes some ingame lag.
|
||||||
// Investigate whether we can minimize this lag by
|
// Investigate whether we can minimize this lag by
|
||||||
// waiting until the player is idle or using CPU boost mode
|
// waiting until the player is idle or using CPU boost mode
|
||||||
println!("[Training Modpack] Starting new menu session...");
|
println!("[Training Modpack] Starting new menu session...");
|
||||||
web_session = Some(
|
web_session = Some(
|
||||||
Webpage::new()
|
Webpage::new()
|
||||||
.background(Background::BlurredScreenshot)
|
.background(Background::BlurredScreenshot)
|
||||||
.htdocs_dir("training_modpack")
|
.htdocs_dir("training_modpack")
|
||||||
.start_page("training_menu.html")
|
.start_page("training_menu.html")
|
||||||
.open_session(WebSessionBootMode::InitiallyHidden)
|
.open_session(WebSessionBootMode::InitiallyHidden)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No longer in training mode, tear down the session.
|
// No longer in training mode, tear down the session.
|
||||||
// This will avoid conflicts with other web plugins, and helps with stability.
|
// This will avoid conflicts with other web plugins, and helps with stability.
|
||||||
// Having the session open too long, especially if the switch has been put to sleep, can cause freezes
|
// Having the session open too long, especially if the switch has been put to sleep, can cause freezes
|
||||||
if web_session.is_some() {
|
if let Some(web_session_to_kill) = web_session {
|
||||||
println!("[Training Modpack] Tearing down Training Modpack menu session");
|
println!("[Training Modpack] Tearing down Training Modpack menu session");
|
||||||
web_session.unwrap().exit();
|
web_session_to_kill.exit();
|
||||||
}
|
web_session_to_kill.wait_for_exit();
|
||||||
web_session = None;
|
}
|
||||||
}
|
web_session = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,149 +1,155 @@
|
||||||
pub mod consts;
|
pub mod consts;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod menu;
|
pub mod menu;
|
||||||
pub mod raygun_printer;
|
pub mod raygun_printer;
|
||||||
pub mod release;
|
pub mod release;
|
||||||
|
|
||||||
use crate::common::consts::*;
|
use crate::common::consts::*;
|
||||||
use smash::app::{self, lua_bind::*};
|
use smash::app::{self, lua_bind::*};
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
|
||||||
pub use crate::common::consts::MENU;
|
pub use crate::common::consts::MENU;
|
||||||
pub static mut DEFAULTS_MENU: TrainingModpackMenu = crate::common::consts::DEFAULTS_MENU;
|
pub static mut DEFAULTS_MENU: TrainingModpackMenu = crate::common::consts::DEFAULTS_MENU;
|
||||||
pub static mut BASE_MENU: TrainingModpackMenu = unsafe { DEFAULTS_MENU };
|
pub static mut BASE_MENU: TrainingModpackMenu = unsafe { DEFAULTS_MENU };
|
||||||
pub static mut FIGHTER_MANAGER_ADDR: usize = 0;
|
pub static mut FIGHTER_MANAGER_ADDR: usize = 0;
|
||||||
pub static mut ITEM_MANAGER_ADDR: usize = 0;
|
pub static mut ITEM_MANAGER_ADDR: usize = 0;
|
||||||
pub static mut STAGE_MANAGER_ADDR: usize = 0;
|
pub static mut STAGE_MANAGER_ADDR: usize = 0;
|
||||||
|
|
||||||
#[cfg(not(feature = "outside_training_mode"))]
|
#[cfg(not(feature = "outside_training_mode"))]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = "\u{1}_ZN3app9smashball16is_training_modeEv"]
|
#[link_name = "\u{1}_ZN3app9smashball16is_training_modeEv"]
|
||||||
pub fn is_training_mode() -> bool;
|
pub fn is_training_mode() -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "outside_training_mode")]
|
#[cfg(feature = "outside_training_mode")]
|
||||||
pub fn is_training_mode() -> bool {
|
pub fn is_training_mode() -> bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_category(module_accessor: &mut app::BattleObjectModuleAccessor) -> i32 {
|
pub fn get_category(module_accessor: &mut app::BattleObjectModuleAccessor) -> i32 {
|
||||||
(module_accessor.info >> 28) as u8 as i32
|
(module_accessor.info >> 28) as u8 as i32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_emulator() -> bool {
|
pub fn is_emulator() -> bool {
|
||||||
unsafe { skyline::hooks::getRegionAddress(skyline::hooks::Region::Text) as u64 == 0x8004000 }
|
unsafe { skyline::hooks::getRegionAddress(skyline::hooks::Region::Text) as u64 == 0x8004000 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_module_accessor(fighter_id: FighterId) -> *mut app::BattleObjectModuleAccessor {
|
pub fn get_module_accessor(fighter_id: FighterId) -> *mut app::BattleObjectModuleAccessor {
|
||||||
let entry_id_int = fighter_id as i32;
|
let entry_id_int = fighter_id as i32;
|
||||||
let entry_id = app::FighterEntryID(entry_id_int);
|
let entry_id = app::FighterEntryID(entry_id_int);
|
||||||
unsafe {
|
unsafe {
|
||||||
let mgr = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
|
let mgr = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
|
||||||
let fighter_entry =
|
let fighter_entry =
|
||||||
FighterManager::get_fighter_entry(mgr, entry_id) as *mut app::FighterEntry;
|
FighterManager::get_fighter_entry(mgr, entry_id) as *mut app::FighterEntry;
|
||||||
let current_fighter_id = FighterEntry::current_fighter_id(fighter_entry);
|
let current_fighter_id = FighterEntry::current_fighter_id(fighter_entry);
|
||||||
app::sv_battle_object::module_accessor(current_fighter_id as u32)
|
app::sv_battle_object::module_accessor(current_fighter_id as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_fighter(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
pub fn is_fighter(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||||
get_category(module_accessor) == BATTLE_OBJECT_CATEGORY_FIGHTER
|
get_category(module_accessor) == BATTLE_OBJECT_CATEGORY_FIGHTER
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_operation_cpu(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
pub fn is_operation_cpu(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
if !is_fighter(module_accessor) {
|
if !is_fighter(module_accessor) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry_id_int =
|
let entry_id_int =
|
||||||
WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID) as i32;
|
WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID) as i32;
|
||||||
|
|
||||||
if entry_id_int == 0 {
|
if entry_id_int == 0 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry_id = app::FighterEntryID(entry_id_int);
|
let entry_id = app::FighterEntryID(entry_id_int);
|
||||||
let mgr = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
|
let mgr = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
|
||||||
let fighter_information =
|
let fighter_information =
|
||||||
FighterManager::get_fighter_information(mgr, entry_id) as *mut app::FighterInformation;
|
FighterManager::get_fighter_information(mgr, entry_id) as *mut app::FighterInformation;
|
||||||
|
|
||||||
FighterInformation::is_operation_cpu(fighter_information)
|
FighterInformation::is_operation_cpu(fighter_information)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_grounded(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
pub fn is_grounded(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||||
let situation_kind = unsafe { StatusModule::situation_kind(module_accessor) as i32 };
|
let situation_kind = unsafe { StatusModule::situation_kind(module_accessor) as i32 };
|
||||||
|
|
||||||
situation_kind == SITUATION_KIND_GROUND
|
situation_kind == SITUATION_KIND_GROUND
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_airborne(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
pub fn is_airborne(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||||
let situation_kind = unsafe { StatusModule::situation_kind(module_accessor) as i32 };
|
let situation_kind = unsafe { StatusModule::situation_kind(module_accessor) as i32 };
|
||||||
|
|
||||||
situation_kind == SITUATION_KIND_AIR
|
situation_kind == SITUATION_KIND_AIR
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_idle(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
pub fn is_idle(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||||
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
|
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
|
||||||
|
|
||||||
status_kind == FIGHTER_STATUS_KIND_WAIT
|
status_kind == FIGHTER_STATUS_KIND_WAIT
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_in_hitstun(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
pub fn is_in_hitstun(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||||
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
|
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
|
||||||
|
|
||||||
(*FIGHTER_STATUS_KIND_DAMAGE..*FIGHTER_STATUS_KIND_DAMAGE_FALL).contains(&status_kind)
|
(*FIGHTER_STATUS_KIND_DAMAGE..*FIGHTER_STATUS_KIND_DAMAGE_FALL).contains(&status_kind)
|
||||||
}
|
}
|
||||||
pub fn is_in_footstool(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
pub fn is_in_footstool(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||||
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
|
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
|
||||||
|
|
||||||
(*FIGHTER_STATUS_KIND_TREAD_DAMAGE..=*FIGHTER_STATUS_KIND_TREAD_FALL).contains(&status_kind)
|
(*FIGHTER_STATUS_KIND_TREAD_DAMAGE..=*FIGHTER_STATUS_KIND_TREAD_FALL).contains(&status_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_shielding(module_accessor: *mut app::BattleObjectModuleAccessor) -> bool {
|
pub fn is_shielding(module_accessor: *mut app::BattleObjectModuleAccessor) -> bool {
|
||||||
let status_kind = unsafe { StatusModule::status_kind(module_accessor) as i32 };
|
let status_kind = unsafe { StatusModule::status_kind(module_accessor) as i32 };
|
||||||
|
|
||||||
(*FIGHTER_STATUS_KIND_GUARD_ON..=*FIGHTER_STATUS_KIND_GUARD_DAMAGE).contains(&status_kind)
|
(*FIGHTER_STATUS_KIND_GUARD_ON..=*FIGHTER_STATUS_KIND_GUARD_DAMAGE).contains(&status_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_in_shieldstun(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
pub fn is_in_shieldstun(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||||
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
|
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
|
||||||
let prev_status = unsafe { StatusModule::prev_status_kind(module_accessor, 0) };
|
let prev_status = unsafe { StatusModule::prev_status_kind(module_accessor, 0) };
|
||||||
|
|
||||||
// If we are taking shield damage or we are droping shield from taking shield damage we are in hitstun
|
// If we are taking shield damage or we are droping shield from taking shield damage we are in hitstun
|
||||||
status_kind == FIGHTER_STATUS_KIND_GUARD_DAMAGE
|
status_kind == FIGHTER_STATUS_KIND_GUARD_DAMAGE
|
||||||
|| (prev_status == FIGHTER_STATUS_KIND_GUARD_DAMAGE
|
|| (prev_status == FIGHTER_STATUS_KIND_GUARD_DAMAGE
|
||||||
&& status_kind == FIGHTER_STATUS_KIND_GUARD_OFF)
|
&& status_kind == FIGHTER_STATUS_KIND_GUARD_OFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn is_dead(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
pub unsafe fn is_dead(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||||
let fighter_kind = app::utility::get_kind(module_accessor);
|
let fighter_kind = app::utility::get_kind(module_accessor);
|
||||||
let fighter_is_ptrainer = [
|
let fighter_is_ptrainer = [
|
||||||
*FIGHTER_KIND_PZENIGAME,
|
*FIGHTER_KIND_PZENIGAME,
|
||||||
*FIGHTER_KIND_PFUSHIGISOU,
|
*FIGHTER_KIND_PFUSHIGISOU,
|
||||||
*FIGHTER_KIND_PLIZARDON,
|
*FIGHTER_KIND_PLIZARDON,
|
||||||
]
|
]
|
||||||
.contains(&fighter_kind);
|
.contains(&fighter_kind);
|
||||||
let status_kind = StatusModule::status_kind(module_accessor) as i32;
|
let status_kind = StatusModule::status_kind(module_accessor) as i32;
|
||||||
let prev_status_kind = StatusModule::prev_status_kind(module_accessor, 0);
|
let prev_status_kind = StatusModule::prev_status_kind(module_accessor, 0);
|
||||||
// Pokemon trainer enters FIGHTER_STATUS_KIND_WAIT for one frame during their respawn animation
|
// Pokemon trainer enters FIGHTER_STATUS_KIND_WAIT for one frame during their respawn animation
|
||||||
// And the previous status is FIGHTER_STATUS_NONE
|
// And the previous status is FIGHTER_STATUS_NONE
|
||||||
if fighter_is_ptrainer {
|
if fighter_is_ptrainer {
|
||||||
[*FIGHTER_STATUS_KIND_DEAD, *FIGHTER_STATUS_KIND_STANDBY].contains(&status_kind)
|
[*FIGHTER_STATUS_KIND_DEAD, *FIGHTER_STATUS_KIND_STANDBY].contains(&status_kind)
|
||||||
|| (status_kind == FIGHTER_STATUS_KIND_WAIT
|
|| (status_kind == FIGHTER_STATUS_KIND_WAIT
|
||||||
&& prev_status_kind == FIGHTER_STATUS_KIND_NONE)
|
&& prev_status_kind == FIGHTER_STATUS_KIND_NONE)
|
||||||
} else {
|
} else {
|
||||||
[*FIGHTER_STATUS_KIND_DEAD, *FIGHTER_STATUS_KIND_STANDBY].contains(&status_kind)
|
[*FIGHTER_STATUS_KIND_DEAD, *FIGHTER_STATUS_KIND_STANDBY].contains(&status_kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn is_in_clatter(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
pub unsafe fn is_in_clatter(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||||
ControlModule::get_clatter_time(module_accessor, 0) > 0.0
|
ControlModule::get_clatter_time(module_accessor, 0) > 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if a match is currently active
|
// Returns true if a match is currently active
|
||||||
pub unsafe fn is_ready_go() -> bool {
|
pub unsafe fn is_ready_go() -> bool {
|
||||||
let fighter_manager = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
|
let fighter_manager = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
|
||||||
FighterManager::is_ready_go(fighter_manager)
|
FighterManager::is_ready_go(fighter_manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if a match is currently active
|
||||||
|
pub unsafe fn entry_count() -> i32 {
|
||||||
|
let fighter_manager = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
|
||||||
|
FighterManager::entry_count(fighter_manager)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue