1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2025-03-22 22:36:10 +00:00

Open Menu with Start Press (#598)

* Initial

* Another fix

* Don't allow opening our menu when vanilla menu is active

* Add menu option ; remove delay to close menu

* Fix issues when closing menu

* Show button config first, log fade

* Fix test

* Fix test again

* Fix initial notification, turn off hitbox visualization by default
This commit is contained in:
jugeeya 2023-08-22 16:12:12 -07:00 committed by GitHub
parent 58f699b285
commit 00f2284397
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 221 additions and 87 deletions

2
ryujinx_build.ps1 vendored
View file

@ -7,7 +7,7 @@ $LOCAL_LAYOUT_ARC_PATH="C:\Users\Josh\Documents\Games\UltimateTrainingModpack\sr
$RYUJINX_PLUGIN_PATH="C:\Users\Josh\AppData\Roaming\Ryujinx\mods\contents\01006a800016e000\romfs\skyline\plugins\libtraining_modpack.nro" $RYUJINX_PLUGIN_PATH="C:\Users\Josh\AppData\Roaming\Ryujinx\mods\contents\01006a800016e000\romfs\skyline\plugins\libtraining_modpack.nro"
$LOCAL_PLUGIN_PATH="C:\Users\Josh\Documents\Games\UltimateTrainingModpack\target\aarch64-skyline-switch\release\libtraining_modpack.nro" $LOCAL_PLUGIN_PATH="C:\Users\Josh\Documents\Games\UltimateTrainingModpack\target\aarch64-skyline-switch\release\libtraining_modpack.nro"
$RYUJINX_EXE_PATH="C:\Users\Josh\Documents\Games\Ryujinx\publish\Ryujinx.exe" $RYUJINX_EXE_PATH="C:\Users\Josh\Documents\Games\Ryujinx\ryujinx-1.1.999-win_x64\publish\Ryujinx.exe"
$SMASH_NSP_PATH='C:\Users\Josh\Documents\Games\ROMs\Super Smash Bros Ultimate [Base Game]\Super Smash Bros Ultimate[01006A800016E000][US][v0].nsp' $SMASH_NSP_PATH='C:\Users\Josh\Documents\Games\ROMs\Super Smash Bros Ultimate [Base Game]\Super Smash Bros Ultimate[01006A800016E000][US][v0].nsp'

View file

@ -2,12 +2,16 @@ use std::collections::HashMap;
use crate::common::*; use crate::common::*;
use crate::input::{ControllerStyle::*, *}; use crate::input::{ControllerStyle::*, *};
use crate::training::frame_counter;
use crate::training::ui::menu::VANILLA_MENU_ACTIVE;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use parking_lot::Mutex; use parking_lot::Mutex;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use strum_macros::EnumIter; use strum_macros::EnumIter;
use super::menu::QUICK_MENU_ACTIVE;
pub fn button_mapping( pub fn button_mapping(
button_config: ButtonConfig, button_config: ButtonConfig,
style: ControllerStyle, style: ControllerStyle,
@ -55,9 +59,12 @@ pub enum ButtonCombo {
InputPlayback, InputPlayback,
} }
pub const DEFAULT_OPEN_MENU_CONFIG: ButtonConfig = ButtonConfig::B.union(ButtonConfig::DPAD_UP);
unsafe fn get_combo_keys(combo: ButtonCombo) -> ButtonConfig { unsafe fn get_combo_keys(combo: ButtonCombo) -> ButtonConfig {
match combo { match combo {
ButtonCombo::OpenMenu => MENU.menu_open, // For OpenMenu, have a default in addition to accepting start press
ButtonCombo::OpenMenu => DEFAULT_OPEN_MENU_CONFIG,
ButtonCombo::SaveState => MENU.save_state_save, ButtonCombo::SaveState => MENU.save_state_save,
ButtonCombo::LoadState => MENU.save_state_load, ButtonCombo::LoadState => MENU.save_state_load,
ButtonCombo::InputRecord => MENU.input_record, ButtonCombo::InputRecord => MENU.input_record,
@ -74,6 +81,7 @@ lazy_static! {
(ButtonCombo::InputRecord, false), (ButtonCombo::InputRecord, false),
(ButtonCombo::InputPlayback, false), (ButtonCombo::InputPlayback, false),
])); ]));
static ref START_HOLD_FRAMES: Mutex<u32> = Mutex::new(0);
} }
fn combo_passes(p1_controller: Controller, combo: ButtonCombo) -> bool { fn combo_passes(p1_controller: Controller, combo: ButtonCombo) -> bool {
@ -124,15 +132,53 @@ pub fn combo_passes_exclusive(combo: ButtonCombo) -> bool {
} }
} }
pub fn handle_final_input_mapping(player_idx: i32, controller_struct: &SomeControllerStruct) { pub fn handle_final_input_mapping(player_idx: i32, controller_struct: &mut SomeControllerStruct) {
if player_idx == 0 { if player_idx == 0 {
let p1_controller = *controller_struct.controller; let p1_controller = &mut *controller_struct.controller;
let mut start_menu_request = false;
let menu_close_wait_frame =
unsafe { frame_counter::get_frame_count(menu::FRAME_COUNTER_INDEX) };
if unsafe { MENU.menu_open_start_press == OnOff::On } {
let start_hold_frames = &mut *START_HOLD_FRAMES.lock();
if p1_controller.current_buttons.plus() {
*start_hold_frames += 1;
p1_controller.previous_buttons.set_plus(false);
p1_controller.current_buttons.set_plus(false);
p1_controller.just_down.set_plus(false);
p1_controller.just_release.set_plus(false);
} else {
if *start_hold_frames > 0 && menu_close_wait_frame == 0 {
// Here, we just finished holding start
if *start_hold_frames < 10
&& unsafe { !VANILLA_MENU_ACTIVE }
&& menu_close_wait_frame == 0
{
// If we held for fewer than 10 frames, let's open the training mod menu
start_menu_request = true;
} else if unsafe { !QUICK_MENU_ACTIVE } {
// Otherwise, let's let the game know that we had pressed start
// So long as our menu isn't active
p1_controller.current_buttons.set_plus(true);
p1_controller.just_down.set_plus(true);
unsafe {
VANILLA_MENU_ACTIVE = true;
}
}
}
*start_hold_frames = 0;
}
}
let button_combo_requests = &mut *BUTTON_COMBO_REQUESTS.lock(); let button_combo_requests = &mut *BUTTON_COMBO_REQUESTS.lock();
button_combo_requests button_combo_requests
.iter_mut() .iter_mut()
.for_each(|(combo, is_request)| { .for_each(|(combo, is_request)| {
if !*is_request { if !*is_request {
*is_request = _combo_passes_exclusive(p1_controller, *combo); *is_request = _combo_passes_exclusive(*p1_controller, *combo);
if *combo == button_config::ButtonCombo::OpenMenu && start_menu_request {
*is_request = true;
}
} }
}) })
} }

View file

@ -267,7 +267,7 @@ pub struct SomeControllerStruct {
} }
// Define struct used for final controller inputs // Define struct used for final controller inputs
#[derive(Copy, Clone)] #[derive(Copy, Clone, Debug)]
#[repr(C)] #[repr(C)]
pub struct MappedInputs { pub struct MappedInputs {
pub buttons: Buttons, pub buttons: Buttons,

View file

@ -13,13 +13,18 @@ use crate::consts::MENU_OPTIONS_PATH;
use crate::events::{Event, EVENT_QUEUE}; use crate::events::{Event, EVENT_QUEUE};
use crate::input::*; use crate::input::*;
use crate::logging::*; use crate::logging::*;
use crate::training::frame_counter;
// This is a special frame counter that will tick on draw() pub static mut FRAME_COUNTER_INDEX: usize = 0;
// We'll count how long the menu has been open pub const MENU_CLOSE_WAIT_FRAMES: u32 = 15;
pub static mut FRAME_COUNTER: u32 = 0;
const MENU_CLOSE_WAIT_FRAMES: u32 = 60;
pub static mut QUICK_MENU_ACTIVE: bool = false; pub static mut QUICK_MENU_ACTIVE: bool = false;
pub fn init() {
unsafe {
FRAME_COUNTER_INDEX = frame_counter::register_counter_no_reset();
}
}
pub unsafe fn menu_condition() -> bool { pub unsafe fn menu_condition() -> bool {
button_config::combo_passes_exclusive(button_config::ButtonCombo::OpenMenu) button_config::combo_passes_exclusive(button_config::ButtonCombo::OpenMenu)
} }
@ -72,23 +77,18 @@ pub unsafe fn set_menu_from_json(message: &str) {
pub fn spawn_menu() { pub fn spawn_menu() {
unsafe { unsafe {
FRAME_COUNTER = 0;
QUICK_MENU_ACTIVE = true; QUICK_MENU_ACTIVE = true;
} }
} }
#[derive(Eq, PartialEq, Hash, Copy, Clone)] #[derive(Eq, PartialEq, Hash, Copy, Clone)]
enum DirectionButton { enum DirectionButton {
DpadLeft,
LLeft, LLeft,
RLeft, RLeft,
DpadDown,
LDown, LDown,
RDown, RDown,
DpadRight,
LRight, LRight,
RRight, RRight,
DpadUp,
LUp, LUp,
RUp, RUp,
} }
@ -107,16 +107,12 @@ lazy_static! {
static ref DIRECTION_HOLD_FRAMES: Mutex<HashMap<DirectionButton, u32>> = { static ref DIRECTION_HOLD_FRAMES: Mutex<HashMap<DirectionButton, u32>> = {
use DirectionButton::*; use DirectionButton::*;
Mutex::new(HashMap::from([ Mutex::new(HashMap::from([
(DpadLeft, 0),
(LLeft, 0), (LLeft, 0),
(RLeft, 0), (RLeft, 0),
(DpadDown, 0),
(LDown, 0), (LDown, 0),
(RDown, 0), (RDown, 0),
(DpadRight, 0),
(LRight, 0), (LRight, 0),
(RRight, 0), (RRight, 0),
(DpadUp, 0),
(LUp, 0), (LUp, 0),
(RUp, 0), (RUp, 0),
])) ]))
@ -125,13 +121,28 @@ lazy_static! {
pub fn handle_final_input_mapping( pub fn handle_final_input_mapping(
player_idx: i32, player_idx: i32,
controller_struct: &SomeControllerStruct, controller_struct: &mut SomeControllerStruct,
out: *mut MappedInputs, out: *mut MappedInputs,
) { ) {
unsafe { unsafe {
if player_idx == 0 { if player_idx == 0 {
let p1_controller = *controller_struct.controller; let p1_controller = &mut *controller_struct.controller;
*P1_CONTROLLER_STYLE.lock() = p1_controller.style; *P1_CONTROLLER_STYLE.lock() = p1_controller.style;
if frame_counter::get_frame_count(FRAME_COUNTER_INDEX) > 0
&& frame_counter::get_frame_count(FRAME_COUNTER_INDEX) < MENU_CLOSE_WAIT_FRAMES
{
// If we just closed the menu, kill all inputs to avoid accidental presses
*out = MappedInputs::empty();
p1_controller.current_buttons = ButtonBitfield::default();
p1_controller.previous_buttons = ButtonBitfield::default();
p1_controller.just_down = ButtonBitfield::default();
p1_controller.just_release = ButtonBitfield::default();
} else if frame_counter::get_frame_count(FRAME_COUNTER_INDEX) >= MENU_CLOSE_WAIT_FRAMES
{
frame_counter::reset_frame_count(FRAME_COUNTER_INDEX);
frame_counter::stop_counting(FRAME_COUNTER_INDEX);
}
if QUICK_MENU_ACTIVE { if QUICK_MENU_ACTIVE {
// If we're here, remove all other presses // If we're here, remove all other presses
*out = MappedInputs::empty(); *out = MappedInputs::empty();
@ -161,16 +172,12 @@ pub fn handle_final_input_mapping(
.iter_mut() .iter_mut()
.for_each(|(direction, frames)| { .for_each(|(direction, frames)| {
let still_held = match direction { let still_held = match direction {
DpadLeft => button_current_held.dpad_left(),
LLeft => button_current_held.l_left(), LLeft => button_current_held.l_left(),
RLeft => button_current_held.r_left(), RLeft => button_current_held.r_left(),
DpadDown => button_current_held.dpad_down(),
LDown => button_current_held.l_down(), LDown => button_current_held.l_down(),
RDown => button_current_held.r_down(), RDown => button_current_held.r_down(),
DpadRight => button_current_held.dpad_right(),
LRight => button_current_held.l_right(), LRight => button_current_held.l_right(),
RRight => button_current_held.r_right(), RRight => button_current_held.r_right(),
DpadUp => button_current_held.dpad_up(),
LUp => button_current_held.l_up(), LUp => button_current_held.l_up(),
RUp => button_current_held.r_up(), RUp => button_current_held.r_up(),
}; };
@ -190,15 +197,24 @@ pub fn handle_final_input_mapping(
received_input = true; received_input = true;
if app.page != AppPage::SUBMENU { if app.page != AppPage::SUBMENU {
app.on_b() app.on_b()
} else if FRAME_COUNTER > MENU_CLOSE_WAIT_FRAMES { } else {
// Leave menu. // Leave menu.
frame_counter::start_counting(FRAME_COUNTER_INDEX);
QUICK_MENU_ACTIVE = false; QUICK_MENU_ACTIVE = false;
FRAME_COUNTER = 0;
let menu_json = app.get_menu_selections(); let menu_json = app.get_menu_selections();
set_menu_from_json(&menu_json); set_menu_from_json(&menu_json);
EVENT_QUEUE.push(Event::menu_open(menu_json)); EVENT_QUEUE.push(Event::menu_open(menu_json));
} }
}); });
button_mapping(ButtonConfig::PLUS, style, button_presses).then(|| {
received_input = true;
// Leave menu.
frame_counter::start_counting(FRAME_COUNTER_INDEX);
QUICK_MENU_ACTIVE = false;
let menu_json = app.get_menu_selections();
set_menu_from_json(&menu_json);
EVENT_QUEUE.push(Event::menu_open(menu_json));
});
button_mapping(ButtonConfig::X, style, button_presses).then(|| { button_mapping(ButtonConfig::X, style, button_presses).then(|| {
app.save_defaults(); app.save_defaults();
received_input = true; received_input = true;
@ -227,7 +243,7 @@ pub fn handle_final_input_mapping(
(button_presses.dpad_left() (button_presses.dpad_left()
|| button_presses.l_left() || button_presses.l_left()
|| button_presses.r_left() || button_presses.r_left()
|| [DpadLeft, LLeft, RLeft].iter().any(hold_condition)) || [LLeft, RLeft].iter().any(hold_condition))
.then(|| { .then(|| {
received_input = true; received_input = true;
app.on_left(); app.on_left();
@ -235,7 +251,7 @@ pub fn handle_final_input_mapping(
(button_presses.dpad_right() (button_presses.dpad_right()
|| button_presses.l_right() || button_presses.l_right()
|| button_presses.r_right() || button_presses.r_right()
|| [DpadRight, LRight, RRight].iter().any(hold_condition)) || [LRight, RRight].iter().any(hold_condition))
.then(|| { .then(|| {
received_input = true; received_input = true;
app.on_right(); app.on_right();
@ -243,7 +259,7 @@ pub fn handle_final_input_mapping(
(button_presses.dpad_up() (button_presses.dpad_up()
|| button_presses.l_up() || button_presses.l_up()
|| button_presses.r_up() || button_presses.r_up()
|| [DpadUp, LUp, RUp].iter().any(hold_condition)) || [LUp, RUp].iter().any(hold_condition))
.then(|| { .then(|| {
received_input = true; received_input = true;
app.on_up(); app.on_up();
@ -251,7 +267,7 @@ pub fn handle_final_input_mapping(
(button_presses.dpad_down() (button_presses.dpad_down()
|| button_presses.l_down() || button_presses.l_down()
|| button_presses.r_down() || button_presses.r_down()
|| [DpadDown, LDown, RDown].iter().any(hold_condition)) || [LDown, RDown].iter().any(hold_condition))
.then(|| { .then(|| {
received_input = true; received_input = true;
app.on_down(); app.on_down();

View file

@ -18,8 +18,9 @@ use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use skyline::nro::{self, NroInfo}; use skyline::nro::{self, NroInfo};
use training_mod_consts::LEGACY_TRAINING_MODPACK_ROOT; use training_mod_consts::{OnOff, LEGACY_TRAINING_MODPACK_ROOT};
use crate::common::button_config::DEFAULT_OPEN_MENU_CONFIG;
use crate::common::events::events_loop; use crate::common::events::events_loop;
use crate::common::*; use crate::common::*;
use crate::consts::TRAINING_MODPACK_ROOT; use crate::consts::TRAINING_MODPACK_ROOT;
@ -117,7 +118,15 @@ pub fn main() {
unsafe { unsafe {
notification("Training Modpack".to_string(), "Welcome!".to_string(), 60); notification("Training Modpack".to_string(), "Welcome!".to_string(), 60);
notification("Open Menu".to_string(), MENU.menu_open.to_string(), 120); notification(
"Open Menu".to_string(),
if MENU.menu_open_start_press == OnOff::On {
"Start".to_string()
} else {
DEFAULT_OPEN_MENU_CONFIG.to_string()
},
120,
);
notification( notification(
"Save State".to_string(), "Save State".to_string(),
MENU.save_state_save.to_string(), MENU.save_state_save.to_string(),

View file

@ -1,17 +1,27 @@
static mut SHOULD_COUNT: Vec<bool> = vec![]; static mut SHOULD_COUNT: Vec<bool> = vec![];
static mut NO_RESET: Vec<bool> = vec![];
static mut COUNTERS: Vec<u32> = vec![]; static mut COUNTERS: Vec<u32> = vec![];
pub fn register_counter() -> usize { fn _register_counter(no_reset: bool) -> usize {
unsafe { unsafe {
let index = COUNTERS.len(); let index = COUNTERS.len();
COUNTERS.push(0); COUNTERS.push(0);
SHOULD_COUNT.push(false); SHOULD_COUNT.push(false);
NO_RESET.push(no_reset);
index index
} }
} }
pub fn register_counter_no_reset() -> usize {
_register_counter(true)
}
pub fn register_counter() -> usize {
_register_counter(false)
}
pub fn start_counting(index: usize) { pub fn start_counting(index: usize) {
unsafe { unsafe {
SHOULD_COUNT[index] = true; SHOULD_COUNT[index] = true;
@ -81,6 +91,9 @@ pub fn tick() {
pub fn reset_all() { pub fn reset_all() {
unsafe { unsafe {
for (index, _frame) in COUNTERS.iter().enumerate() { for (index, _frame) in COUNTERS.iter().enumerate() {
if NO_RESET[index] {
continue;
}
full_reset(index); full_reset(index);
} }
} }

View file

@ -701,8 +701,8 @@ unsafe fn handle_final_input_mapping(
if !is_training_mode() { if !is_training_mode() {
return; return;
} }
button_config::handle_final_input_mapping(player_idx, controller_struct);
menu::handle_final_input_mapping(player_idx, controller_struct, out); menu::handle_final_input_mapping(player_idx, controller_struct, out);
button_config::handle_final_input_mapping(player_idx, controller_struct);
dev_config::handle_final_input_mapping(player_idx, controller_struct); dev_config::handle_final_input_mapping(player_idx, controller_struct);
input_delay::handle_final_input_mapping(player_idx, out); input_delay::handle_final_input_mapping(player_idx, out);
input_record::handle_final_input_mapping(player_idx, out); input_record::handle_final_input_mapping(player_idx, out);
@ -800,4 +800,5 @@ pub fn training_mods() {
tech::init(); tech::init();
input_record::init(); input_record::init();
ui::init(); ui::init();
menu::init();
} }

View file

@ -6,8 +6,12 @@ use smash::ui2d::{SmashPane, SmashTextBox};
use training_mod_tui::gauge::GaugeState; use training_mod_tui::gauge::GaugeState;
use training_mod_tui::{App, AppPage, NUM_LISTS}; use training_mod_tui::{App, AppPage, NUM_LISTS};
use crate::common::menu::{self, MENU_CLOSE_WAIT_FRAMES};
use crate::training::frame_counter;
use crate::{common, common::menu::QUICK_MENU_ACTIVE, input::*}; use crate::{common, common::menu::QUICK_MENU_ACTIVE, input::*};
use super::fade_out;
pub static NUM_MENU_TEXT_OPTIONS: usize = 32; pub static NUM_MENU_TEXT_OPTIONS: usize = 32;
pub static _NUM_MENU_TABS: usize = 3; pub static _NUM_MENU_TABS: usize = 3;
@ -53,6 +57,8 @@ const BG_LEFT_SELECTED_WHITE_COLOR: ResColor = ResColor {
a: 255, a: 255,
}; };
pub static mut VANILLA_MENU_ACTIVE: bool = false;
lazy_static! { lazy_static! {
static ref GCC_BUTTON_MAPPING: HashMap<&'static str, u16> = HashMap::from([ static ref GCC_BUTTON_MAPPING: HashMap<&'static str, u16> = HashMap::from([
("L", 0xE204), ("L", 0xE204),
@ -346,6 +352,15 @@ unsafe fn render_slider_page(app: &App, root_pane: &Pane) {
} }
pub unsafe fn draw(root_pane: &Pane) { pub unsafe fn draw(root_pane: &Pane) {
// Determine if we're in the menu by seeing if the "help" footer has
// begun moving upward. It starts at -80 and moves to 0 over 10 frames
// in info_training_in_menu.bflan
VANILLA_MENU_ACTIVE = root_pane
.find_pane_by_name_recursive("L_staying_help")
.unwrap()
.pos_y
!= -80.0;
// Update menu display // Update menu display
// Grabbing lock as read-only, essentially // Grabbing lock as read-only, essentially
let app = &*crate::common::menu::QUICK_MENU_APP.data_ptr(); let app = &*crate::common::menu::QUICK_MENU_APP.data_ptr();
@ -357,12 +372,21 @@ pub unsafe fn draw(root_pane: &Pane) {
} }
} }
root_pane let overall_parent_pane = root_pane.find_pane_by_name_recursive("TrModMenu").unwrap();
.find_pane_by_name_recursive("TrModMenu") overall_parent_pane.set_visible(true);
.unwrap() let menu_close_wait_frame = frame_counter::get_frame_count(menu::FRAME_COUNTER_INDEX);
.set_visible(QUICK_MENU_ACTIVE);
if QUICK_MENU_ACTIVE { if QUICK_MENU_ACTIVE {
common::menu::FRAME_COUNTER += 1; overall_parent_pane.alpha = 255;
overall_parent_pane.global_alpha = 255;
} else if menu_close_wait_frame > 0 {
fade_out(
overall_parent_pane,
MENU_CLOSE_WAIT_FRAMES - menu_close_wait_frame,
MENU_CLOSE_WAIT_FRAMES,
);
} else {
overall_parent_pane.alpha = 0;
overall_parent_pane.global_alpha = 0;
} }
// Make all invisible first // Make all invisible first

View file

@ -10,9 +10,27 @@ use crate::consts::LAYOUT_ARC_PATH;
mod damage; mod damage;
mod display; mod display;
mod menu; pub mod menu;
pub mod notifications; pub mod notifications;
pub fn fade_out(pane: &mut Pane, current_frame: u32, total_frames: u32) {
if current_frame < total_frames {
// Logarithmic fade out
let alpha = ((255.0 / (total_frames as f32 + 1.0).log10())
* (current_frame as f32 + 1.0).log10()) as u8;
pane.alpha = alpha;
pane.global_alpha = alpha;
// Linear fade out
// let alpha = ((current_frame as f32 / 100.0) * 255.0) as u8;
// pane.alpha = alpha;
// pane.global_alpha = alpha;
} else {
pane.alpha = 0;
pane.global_alpha = 0;
}
}
#[skyline::hook(offset = 0x4b620)] #[skyline::hook(offset = 0x4b620)]
pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) { pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) {
let layout_name = skyline::from_c_str((*layout).layout_name); let layout_name = skyline::from_c_str((*layout).layout_name);

View file

@ -83,7 +83,7 @@ pub struct TrainingModpackMenu {
pub hitstun_playback: HitstunPlayback, pub hitstun_playback: HitstunPlayback,
pub playback_mash: OnOff, pub playback_mash: OnOff,
pub playback_loop: OnOff, pub playback_loop: OnOff,
pub menu_open: ButtonConfig, pub menu_open_start_press: OnOff,
pub save_state_save: ButtonConfig, pub save_state_save: ButtonConfig,
pub save_state_load: ButtonConfig, pub save_state_load: ButtonConfig,
pub input_record: ButtonConfig, pub input_record: ButtonConfig,
@ -139,7 +139,7 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu {
follow_up: Action::empty(), follow_up: Action::empty(),
frame_advantage: OnOff::Off, frame_advantage: OnOff::Off,
full_hop: BoolFlag::TRUE, full_hop: BoolFlag::TRUE,
hitbox_vis: OnOff::On, hitbox_vis: OnOff::Off,
hud: OnOff::On, hud: OnOff::On,
input_delay: Delay::D0, input_delay: Delay::D0,
ledge_delay: LongDelay::empty(), ledge_delay: LongDelay::empty(),
@ -188,7 +188,7 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu {
hitstun_playback: HitstunPlayback::Hitstun, hitstun_playback: HitstunPlayback::Hitstun,
playback_mash: OnOff::On, playback_mash: OnOff::On,
playback_loop: OnOff::Off, playback_loop: OnOff::Off,
menu_open: ButtonConfig::B.union(ButtonConfig::DPAD_UP), menu_open_start_press: OnOff::On,
save_state_save: ButtonConfig::ZL.union(ButtonConfig::DPAD_DOWN), save_state_save: ButtonConfig::ZL.union(ButtonConfig::DPAD_DOWN),
save_state_load: ButtonConfig::ZL.union(ButtonConfig::DPAD_UP), save_state_load: ButtonConfig::ZL.union(ButtonConfig::DPAD_UP),
input_record: ButtonConfig::ZR.union(ButtonConfig::DPAD_DOWN), input_record: ButtonConfig::ZR.union(ButtonConfig::DPAD_DOWN),
@ -339,6 +339,48 @@ pub struct UiMenu {
pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu { pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu {
let mut overall_menu = UiMenu { tabs: Vec::new() }; let mut overall_menu = UiMenu { tabs: Vec::new() };
let mut button_tab = Tab {
tab_id: "button".to_string(),
tab_title: "Button Config".to_string(),
tab_submenus: Vec::new(),
};
button_tab.add_submenu_with_toggles::<OnOff>(
"Menu Open Start Press".to_string(),
"menu_open_start_press".to_string(),
"Menu Open Start Press: Press start to open the mod menu. To open the original menu, hold start.\nThe default menu open option is always available as Hold B + Press DPad Up.".to_string(),
true,
&(menu.menu_open_start_press as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Save State Save".to_string(),
"save_state_save".to_string(),
"Save State Save: Hold any one button and press the others to trigger".to_string(),
false,
&(menu.save_state_save.bits() as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Save State Load".to_string(),
"save_state_load".to_string(),
"Save State Load: Hold any one button and press the others to trigger".to_string(),
false,
&(menu.save_state_load.bits() as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Input Record".to_string(),
"input_record".to_string(),
"Input Record: Hold any one button and press the others to trigger".to_string(),
false,
&(menu.input_record.bits() as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Input Playback".to_string(),
"input_playback".to_string(),
"Input Playback: Hold any one button and press the others to trigger".to_string(),
false,
&(menu.input_playback.bits() as u32),
);
overall_menu.tabs.push(button_tab);
let mut mash_tab = Tab { let mut mash_tab = Tab {
tab_id: "mash".to_string(), tab_id: "mash".to_string(),
tab_title: "Mash Settings".to_string(), tab_title: "Mash Settings".to_string(),
@ -851,48 +893,5 @@ pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu {
); );
overall_menu.tabs.push(input_tab); overall_menu.tabs.push(input_tab);
let mut button_tab = Tab {
tab_id: "button".to_string(),
tab_title: "Button Config".to_string(),
tab_submenus: Vec::new(),
};
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Menu Open".to_string(),
"menu_open".to_string(),
"Menu Open: Hold: Hold any one button and press the others to trigger".to_string(),
false,
&(menu.menu_open.bits() as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Save State Save".to_string(),
"save_state_save".to_string(),
"Save State Save: Hold any one button and press the others to trigger".to_string(),
false,
&(menu.save_state_save.bits() as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Save State Load".to_string(),
"save_state_load".to_string(),
"Save State Load: Hold any one button and press the others to trigger".to_string(),
false,
&(menu.save_state_load.bits() as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Input Record".to_string(),
"input_record".to_string(),
"Input Record: Hold any one button and press the others to trigger".to_string(),
false,
&(menu.input_record.bits() as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Input Playback".to_string(),
"input_playback".to_string(),
"Input Playback: Hold any one button and press the others to trigger".to_string(),
false,
&(menu.input_playback.bits() as u32),
);
overall_menu.tabs.push(button_tab);
overall_menu overall_menu
} }

View file

@ -48,6 +48,8 @@ fn test_set_airdodge() -> Result<(), Box<dyn Error>> {
} }
let (_terminal, mut app) = test_backend_setup(menu, menu_defaults)?; let (_terminal, mut app) = test_backend_setup(menu, menu_defaults)?;
// Enter Mash Section
app.next_tab();
// Enter Mash Toggles // Enter Mash Toggles
app.on_a(); app.on_a();
// Set Mash Airdodge // Set Mash Airdodge
@ -103,6 +105,8 @@ fn test_save_and_reset_defaults() -> Result<(), Box<dyn Error>> {
let (_terminal, mut app) = test_backend_setup(menu, menu_defaults)?; let (_terminal, mut app) = test_backend_setup(menu, menu_defaults)?;
// Enter Mash Section
app.next_tab();
// Enter Mash Toggles // Enter Mash Toggles
app.on_a(); app.on_a();
// Set Mash Airdodge // Set Mash Airdodge
@ -146,6 +150,8 @@ fn test_save_and_reset_defaults() -> Result<(), Box<dyn Error>> {
"The menu should have Mash Airdodge" "The menu should have Mash Airdodge"
); );
// Enter Mash Section
app.next_tab();
// Enter Mash Toggles // Enter Mash Toggles
app.on_a(); app.on_a();
// Unset Mash Airdodge // Unset Mash Airdodge
@ -216,6 +222,8 @@ fn test_toggle_naming() -> Result<(), Box<dyn Error>> {
} }
let (mut terminal, mut app) = test_backend_setup(menu, menu_defaults)?; let (mut terminal, mut app) = test_backend_setup(menu, menu_defaults)?;
// Enter Mash Section
app.next_tab();
// Enter Mash Toggles // Enter Mash Toggles
app.on_a(); app.on_a();
// Set Mash Airdodge // Set Mash Airdodge