diff --git a/ryujinx_build.ps1 b/ryujinx_build.ps1 index 316c6b9..fd736b7 100644 --- a/ryujinx_build.ps1 +++ b/ryujinx_build.ps1 @@ -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" $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' diff --git a/src/common/button_config.rs b/src/common/button_config.rs index 8c6508d..a9079a8 100644 --- a/src/common/button_config.rs +++ b/src/common/button_config.rs @@ -2,12 +2,16 @@ use std::collections::HashMap; use crate::common::*; use crate::input::{ControllerStyle::*, *}; +use crate::training::frame_counter; +use crate::training::ui::menu::VANILLA_MENU_ACTIVE; use lazy_static::lazy_static; use parking_lot::Mutex; use strum::IntoEnumIterator; use strum_macros::EnumIter; +use super::menu::QUICK_MENU_ACTIVE; + pub fn button_mapping( button_config: ButtonConfig, style: ControllerStyle, @@ -55,9 +59,12 @@ pub enum ButtonCombo { InputPlayback, } +pub const DEFAULT_OPEN_MENU_CONFIG: ButtonConfig = ButtonConfig::B.union(ButtonConfig::DPAD_UP); + unsafe fn get_combo_keys(combo: ButtonCombo) -> ButtonConfig { 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::LoadState => MENU.save_state_load, ButtonCombo::InputRecord => MENU.input_record, @@ -74,6 +81,7 @@ lazy_static! { (ButtonCombo::InputRecord, false), (ButtonCombo::InputPlayback, false), ])); + static ref START_HOLD_FRAMES: Mutex = Mutex::new(0); } 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 { - 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(); button_combo_requests .iter_mut() .for_each(|(combo, 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; + } } }) } diff --git a/src/common/input.rs b/src/common/input.rs index 21cbf69..10681a2 100644 --- a/src/common/input.rs +++ b/src/common/input.rs @@ -267,7 +267,7 @@ pub struct SomeControllerStruct { } // Define struct used for final controller inputs -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] #[repr(C)] pub struct MappedInputs { pub buttons: Buttons, diff --git a/src/common/menu.rs b/src/common/menu.rs index 023f76e..951bf0a 100644 --- a/src/common/menu.rs +++ b/src/common/menu.rs @@ -13,13 +13,18 @@ use crate::consts::MENU_OPTIONS_PATH; use crate::events::{Event, EVENT_QUEUE}; use crate::input::*; use crate::logging::*; +use crate::training::frame_counter; -// This is a special frame counter that will tick on draw() -// We'll count how long the menu has been open -pub static mut FRAME_COUNTER: u32 = 0; -const MENU_CLOSE_WAIT_FRAMES: u32 = 60; +pub static mut FRAME_COUNTER_INDEX: usize = 0; +pub const MENU_CLOSE_WAIT_FRAMES: u32 = 15; 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 { 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() { unsafe { - FRAME_COUNTER = 0; QUICK_MENU_ACTIVE = true; } } #[derive(Eq, PartialEq, Hash, Copy, Clone)] enum DirectionButton { - DpadLeft, LLeft, RLeft, - DpadDown, LDown, RDown, - DpadRight, LRight, RRight, - DpadUp, LUp, RUp, } @@ -107,16 +107,12 @@ lazy_static! { static ref DIRECTION_HOLD_FRAMES: Mutex> = { use DirectionButton::*; Mutex::new(HashMap::from([ - (DpadLeft, 0), (LLeft, 0), (RLeft, 0), - (DpadDown, 0), (LDown, 0), (RDown, 0), - (DpadRight, 0), (LRight, 0), (RRight, 0), - (DpadUp, 0), (LUp, 0), (RUp, 0), ])) @@ -125,13 +121,28 @@ lazy_static! { pub fn handle_final_input_mapping( player_idx: i32, - controller_struct: &SomeControllerStruct, + controller_struct: &mut SomeControllerStruct, out: *mut MappedInputs, ) { unsafe { if player_idx == 0 { - let p1_controller = *controller_struct.controller; + let p1_controller = &mut *controller_struct.controller; *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 we're here, remove all other presses *out = MappedInputs::empty(); @@ -161,16 +172,12 @@ pub fn handle_final_input_mapping( .iter_mut() .for_each(|(direction, frames)| { let still_held = match direction { - DpadLeft => button_current_held.dpad_left(), LLeft => button_current_held.l_left(), RLeft => button_current_held.r_left(), - DpadDown => button_current_held.dpad_down(), LDown => button_current_held.l_down(), RDown => button_current_held.r_down(), - DpadRight => button_current_held.dpad_right(), LRight => button_current_held.l_right(), RRight => button_current_held.r_right(), - DpadUp => button_current_held.dpad_up(), LUp => button_current_held.l_up(), RUp => button_current_held.r_up(), }; @@ -190,15 +197,24 @@ pub fn handle_final_input_mapping( received_input = true; if app.page != AppPage::SUBMENU { app.on_b() - } else if FRAME_COUNTER > MENU_CLOSE_WAIT_FRAMES { + } else { // Leave menu. + frame_counter::start_counting(FRAME_COUNTER_INDEX); QUICK_MENU_ACTIVE = false; - FRAME_COUNTER = 0; let menu_json = app.get_menu_selections(); set_menu_from_json(&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(|| { app.save_defaults(); received_input = true; @@ -227,7 +243,7 @@ pub fn handle_final_input_mapping( (button_presses.dpad_left() || button_presses.l_left() || button_presses.r_left() - || [DpadLeft, LLeft, RLeft].iter().any(hold_condition)) + || [LLeft, RLeft].iter().any(hold_condition)) .then(|| { received_input = true; app.on_left(); @@ -235,7 +251,7 @@ pub fn handle_final_input_mapping( (button_presses.dpad_right() || button_presses.l_right() || button_presses.r_right() - || [DpadRight, LRight, RRight].iter().any(hold_condition)) + || [LRight, RRight].iter().any(hold_condition)) .then(|| { received_input = true; app.on_right(); @@ -243,7 +259,7 @@ pub fn handle_final_input_mapping( (button_presses.dpad_up() || button_presses.l_up() || button_presses.r_up() - || [DpadUp, LUp, RUp].iter().any(hold_condition)) + || [LUp, RUp].iter().any(hold_condition)) .then(|| { received_input = true; app.on_up(); @@ -251,7 +267,7 @@ pub fn handle_final_input_mapping( (button_presses.dpad_down() || button_presses.l_down() || button_presses.r_down() - || [DpadDown, LDown, RDown].iter().any(hold_condition)) + || [LDown, RDown].iter().any(hold_condition)) .then(|| { received_input = true; app.on_down(); diff --git a/src/lib.rs b/src/lib.rs index 218034d..9ecf83a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,8 +18,9 @@ use std::fs; use std::path::PathBuf; 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::*; use crate::consts::TRAINING_MODPACK_ROOT; @@ -117,7 +118,15 @@ pub fn main() { unsafe { 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( "Save State".to_string(), MENU.save_state_save.to_string(), diff --git a/src/training/frame_counter.rs b/src/training/frame_counter.rs index bbb8e84..93ead54 100644 --- a/src/training/frame_counter.rs +++ b/src/training/frame_counter.rs @@ -1,17 +1,27 @@ static mut SHOULD_COUNT: Vec = vec![]; +static mut NO_RESET: Vec = vec![]; static mut COUNTERS: Vec = vec![]; -pub fn register_counter() -> usize { +fn _register_counter(no_reset: bool) -> usize { unsafe { let index = COUNTERS.len(); COUNTERS.push(0); SHOULD_COUNT.push(false); + NO_RESET.push(no_reset); 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) { unsafe { SHOULD_COUNT[index] = true; @@ -81,6 +91,9 @@ pub fn tick() { pub fn reset_all() { unsafe { for (index, _frame) in COUNTERS.iter().enumerate() { + if NO_RESET[index] { + continue; + } full_reset(index); } } diff --git a/src/training/mod.rs b/src/training/mod.rs index d6d9900..bf784c4 100644 --- a/src/training/mod.rs +++ b/src/training/mod.rs @@ -701,8 +701,8 @@ unsafe fn handle_final_input_mapping( if !is_training_mode() { return; } - button_config::handle_final_input_mapping(player_idx, controller_struct); 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); input_delay::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(); input_record::init(); ui::init(); + menu::init(); } diff --git a/src/training/ui/menu.rs b/src/training/ui/menu.rs index 2cb2191..6ce70af 100644 --- a/src/training/ui/menu.rs +++ b/src/training/ui/menu.rs @@ -6,8 +6,12 @@ use smash::ui2d::{SmashPane, SmashTextBox}; use training_mod_tui::gauge::GaugeState; 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 super::fade_out; + pub static NUM_MENU_TEXT_OPTIONS: usize = 32; pub static _NUM_MENU_TABS: usize = 3; @@ -53,6 +57,8 @@ const BG_LEFT_SELECTED_WHITE_COLOR: ResColor = ResColor { a: 255, }; +pub static mut VANILLA_MENU_ACTIVE: bool = false; + lazy_static! { static ref GCC_BUTTON_MAPPING: HashMap<&'static str, u16> = HashMap::from([ ("L", 0xE204), @@ -346,6 +352,15 @@ unsafe fn render_slider_page(app: &App, 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 // Grabbing lock as read-only, essentially let app = &*crate::common::menu::QUICK_MENU_APP.data_ptr(); @@ -357,12 +372,21 @@ pub unsafe fn draw(root_pane: &Pane) { } } - root_pane - .find_pane_by_name_recursive("TrModMenu") - .unwrap() - .set_visible(QUICK_MENU_ACTIVE); + let overall_parent_pane = root_pane.find_pane_by_name_recursive("TrModMenu").unwrap(); + overall_parent_pane.set_visible(true); + let menu_close_wait_frame = frame_counter::get_frame_count(menu::FRAME_COUNTER_INDEX); 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 diff --git a/src/training/ui/mod.rs b/src/training/ui/mod.rs index e906910..7a8414f 100644 --- a/src/training/ui/mod.rs +++ b/src/training/ui/mod.rs @@ -10,9 +10,27 @@ use crate::consts::LAYOUT_ARC_PATH; mod damage; mod display; -mod menu; +pub mod menu; 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)] pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) { let layout_name = skyline::from_c_str((*layout).layout_name); diff --git a/training_mod_consts/src/lib.rs b/training_mod_consts/src/lib.rs index e368922..63dc01b 100644 --- a/training_mod_consts/src/lib.rs +++ b/training_mod_consts/src/lib.rs @@ -83,7 +83,7 @@ pub struct TrainingModpackMenu { pub hitstun_playback: HitstunPlayback, pub playback_mash: OnOff, pub playback_loop: OnOff, - pub menu_open: ButtonConfig, + pub menu_open_start_press: OnOff, pub save_state_save: ButtonConfig, pub save_state_load: ButtonConfig, pub input_record: ButtonConfig, @@ -139,7 +139,7 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu { follow_up: Action::empty(), frame_advantage: OnOff::Off, full_hop: BoolFlag::TRUE, - hitbox_vis: OnOff::On, + hitbox_vis: OnOff::Off, hud: OnOff::On, input_delay: Delay::D0, ledge_delay: LongDelay::empty(), @@ -188,7 +188,7 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu { hitstun_playback: HitstunPlayback::Hitstun, playback_mash: OnOff::On, 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_load: ButtonConfig::ZL.union(ButtonConfig::DPAD_UP), input_record: ButtonConfig::ZR.union(ButtonConfig::DPAD_DOWN), @@ -339,6 +339,48 @@ pub struct UiMenu { pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu { 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::( + "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::( + "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::( + "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::( + "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::( + "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 { tab_id: "mash".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); - 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::( - "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::( - "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::( - "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::( - "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::( - "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 } diff --git a/training_mod_tui/src/main.rs b/training_mod_tui/src/main.rs index ef7a6af..e1ecd1a 100644 --- a/training_mod_tui/src/main.rs +++ b/training_mod_tui/src/main.rs @@ -48,6 +48,8 @@ fn test_set_airdodge() -> Result<(), Box> { } let (_terminal, mut app) = test_backend_setup(menu, menu_defaults)?; + // Enter Mash Section + app.next_tab(); // Enter Mash Toggles app.on_a(); // Set Mash Airdodge @@ -103,6 +105,8 @@ fn test_save_and_reset_defaults() -> Result<(), Box> { let (_terminal, mut app) = test_backend_setup(menu, menu_defaults)?; + // Enter Mash Section + app.next_tab(); // Enter Mash Toggles app.on_a(); // Set Mash Airdodge @@ -146,6 +150,8 @@ fn test_save_and_reset_defaults() -> Result<(), Box> { "The menu should have Mash Airdodge" ); + // Enter Mash Section + app.next_tab(); // Enter Mash Toggles app.on_a(); // Unset Mash Airdodge @@ -216,6 +222,8 @@ fn test_toggle_naming() -> Result<(), Box> { } let (mut terminal, mut app) = test_backend_setup(menu, menu_defaults)?; + // Enter Mash Section + app.next_tab(); // Enter Mash Toggles app.on_a(); // Set Mash Airdodge