From 3a40d46fca4f77df8e73291abba21a9ad588f981 Mon Sep 17 00:00:00 2001 From: jugeeya Date: Wed, 2 Aug 2023 10:27:50 -0700 Subject: [PATCH] Add input recording slots as menu options, randomize playback slots (#553) --- src/training/input_record.rs | 32 +++++++++------ training_mod_consts/src/lib.rs | 64 +++++++++++++++--------------- training_mod_consts/src/options.rs | 44 ++++++++------------ 3 files changed, 67 insertions(+), 73 deletions(-) diff --git a/src/training/input_record.rs b/src/training/input_record.rs index d171c89..a9e24e7 100644 --- a/src/training/input_record.rs +++ b/src/training/input_record.rs @@ -59,14 +59,14 @@ pub static mut RECORDED_LR: f32 = 1.0; // The direction the CPU was facing befor pub static mut CURRENT_LR: f32 = 1.0; // The direction the CPU was facing at the beginning of this playback pub static mut STARTING_STATUS: i32 = 0; // The first status entered in the recording outside of waits // used to calculate if the input playback should begin before hitstun would normally end (hitstun cancel, monado art?) -pub static mut _CURRENT_RECORD_SLOT: usize = 0; // Which slot is being used for recording right now? Want to make sure this is synced with menu choices, maybe just use menu instead +pub static mut CURRENT_RECORD_SLOT: usize = 0; // Which slot is being used for recording right now? Want to make sure this is synced with menu choices, maybe just use menu instead pub static mut CURRENT_PLAYBACK_SLOT: usize = 0; // Which slot is being used for playback right now? lazy_static! { - static ref P1_FINAL_MAPPING: Mutex<[MappedInputs; FINAL_RECORD_MAX]> = - Mutex::new([{ + static ref P1_FINAL_MAPPING: Mutex<[[MappedInputs; FINAL_RECORD_MAX]; TOTAL_SLOT_COUNT]> = + Mutex::new([[{ MappedInputs::default() - }; FINAL_RECORD_MAX]); + }; FINAL_RECORD_MAX]; TOTAL_SLOT_COUNT]); static ref P1_STARTING_STATUSES: Mutex<[StartingStatus; TOTAL_SLOT_COUNT]> = Mutex::new([{StartingStatus::Other}; TOTAL_SLOT_COUNT]); } @@ -105,10 +105,8 @@ unsafe fn should_mash_playback() { should_playback = true; } // if we're in hitstun and want to wait till FAF to act, then we want to match our starting status to the correct transition term to see if we can hitstun cancel - if MENU.hitstun_playback == HitstunPlayback::Hitstun { - if can_transition(cpu_module_accessor) { - should_playback = true; - } + if MENU.hitstun_playback == HitstunPlayback::Hitstun && can_transition(cpu_module_accessor) { + should_playback = true; } } else if is_in_shieldstun(&mut *cpu_module_accessor) { // TODO: Add instant shieldstun toggle for shield art out of electric hitstun? Idk that's so specific @@ -171,6 +169,8 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces let fighter_kind = utility::get_kind(module_accessor); let fighter_is_nana = fighter_kind == *FIGHTER_KIND_NANA; + CURRENT_RECORD_SLOT = MENU.recording_slot.into_idx(); + if entry_id_int == 0 && !fighter_is_nana { // Attack + Dpad Right: Playback if ControlModule::check_button_on(module_accessor, *CONTROL_PAD_BUTTON_ATTACK) @@ -218,7 +218,7 @@ pub unsafe fn lockout_record() { INPUT_RECORD = Pause; INPUT_RECORD_FRAME = 0; POSSESSION = Lockout; - P1_FINAL_MAPPING.lock().iter_mut().for_each(|mapped_input| { + P1_FINAL_MAPPING.lock()[CURRENT_RECORD_SLOT].iter_mut().for_each(|mapped_input| { *mapped_input = MappedInputs::default(); }); LOCKOUT_FRAME = 30; // This needs to be this high or issues occur dropping shield - but does this cause problems when trying to record ledge? @@ -233,7 +233,7 @@ pub unsafe fn _record() { INPUT_RECORD = Record; POSSESSION = Cpu; // Reset mappings to nothing, and then start recording. Likely want to reset in case we cut off recording early. - P1_FINAL_MAPPING.lock().iter_mut().for_each(|mapped_input| { + P1_FINAL_MAPPING.lock()[CURRENT_RECORD_SLOT].iter_mut().for_each(|mapped_input| { *mapped_input = MappedInputs::default(); }); INPUT_RECORD_FRAME = 0; @@ -246,6 +246,7 @@ pub unsafe fn playback() { println!("Tried to playback during lockout!"); return; } + CURRENT_PLAYBACK_SLOT = MENU.playback_slot.get_random().into_idx().unwrap(); INPUT_RECORD = Playback; POSSESSION = Player; INPUT_RECORD_FRAME = 0; @@ -280,7 +281,7 @@ pub unsafe fn stop_playback() { pub unsafe fn is_end_standby() -> bool { // Returns whether we should be done with standby this frame (if any significant controller input has been made) - let first_frame_input = P1_FINAL_MAPPING.lock()[0]; + let first_frame_input = P1_FINAL_MAPPING.lock()[CURRENT_RECORD_SLOT][0]; let clamped_lstick_x = ((first_frame_input.lstick_x as f32) * STICK_CLAMP_MULTIPLIER).clamp(-1.0, 1.0); let clamped_lstick_y = ((first_frame_input.lstick_y as f32) * STICK_CLAMP_MULTIPLIER).clamp(-1.0, 1.0); @@ -322,7 +323,7 @@ unsafe fn handle_final_input_mapping( STARTING_STATUS = StatusModule::status_kind(cpu_module_accessor); // TODO: Handle this based on slot later instead } - P1_FINAL_MAPPING.lock()[INPUT_RECORD_FRAME] = *out; + P1_FINAL_MAPPING.lock()[CURRENT_RECORD_SLOT][INPUT_RECORD_FRAME] = *out; *out = MappedInputs::default(); // don't control player while recording println!("Stored Player Input! Frame: {}",INPUT_RECORD_FRAME); } @@ -357,7 +358,12 @@ unsafe fn set_cpu_controls(p_data: *mut *mut u8) { if INPUT_RECORD == Record || INPUT_RECORD == Playback { let x_input_multiplier = RECORDED_LR * CURRENT_LR; // if we aren't facing the way we were when we initially recorded, we reverse horizontal inputs println!("Overriding Cpu Player: {}, Frame: {}, BUFFER_FRAME: {}, STARTING_STATUS: {}, INPUT_RECORD: {:#?}, POSSESSION: {:#?}", controller_no, INPUT_RECORD_FRAME, BUFFER_FRAME, STARTING_STATUS, INPUT_RECORD, POSSESSION); - let mut saved_mapped_inputs = P1_FINAL_MAPPING.lock()[INPUT_RECORD_FRAME]; + + let mut saved_mapped_inputs = P1_FINAL_MAPPING.lock()[if INPUT_RECORD == Record { + CURRENT_RECORD_SLOT + } else { + CURRENT_PLAYBACK_SLOT + }][INPUT_RECORD_FRAME]; if BUFFER_FRAME <= 3 && BUFFER_FRAME > 0 { // Our option is already buffered, now we need to 0 out inputs to make sure our future controls act like flicks/presses instead of holding the button diff --git a/training_mod_consts/src/lib.rs b/training_mod_consts/src/lib.rs index c2dd72d..aada46b 100644 --- a/training_mod_consts/src/lib.rs +++ b/training_mod_consts/src/lib.rs @@ -73,8 +73,8 @@ pub struct TrainingModpackMenu { pub landing_override: Action, pub trump_override: Action, pub save_state_playback: OnOff, - //pub recording_slot: RecordSlot, - //pub playback_slot: PlaybackSlot, + pub recording_slot: RecordSlot, + pub playback_slot: PlaybackSlot, pub playback_mash: OnOff, pub record_trigger: RecordTrigger, pub hitstun_playback: HitstunPlayback, @@ -169,8 +169,8 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu { landing_override: Action::empty(), trump_override: Action::empty(), save_state_playback: OnOff::Off, - //recording_slot: RecordSlot::S1, - //playback_slot: PlaybackSlot::S1, + recording_slot: RecordSlot::S1, + playback_slot: PlaybackSlot::S1, playback_mash: OnOff::On, record_trigger: RecordTrigger::None, //Command? hitstun_playback: HitstunPlayback::Hitstun, @@ -745,33 +745,12 @@ pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu<'static> { tab_title: "Input Recording", tab_submenus: Vec::new(), }; - input_tab.add_submenu_with_toggles::( - "Save State Playback", - "save_state_playback", - "Save State Playback: Begin recorded input playback upon loading a save state", + input_tab.add_submenu_with_toggles::( + "Recording Slot", + "recording_slot", + "Recording Slot: Choose which slot to record into", true, - &(menu.save_state_playback as u32), - ); - // input_tab.add_submenu_with_toggles::( - // "Recording Slot", - // "recording_slot", - // "Recording Slot: Choose which slot to record into", - // true, - // &(menu.recording_slot as u32), - // ); - // input_tab.add_submenu_with_toggles::( // TODO: This menu should really be a submenu inside Action menus, probably want to be able to customize for each action - // "Playback Slots", - // "playback_slot", - // "Playback Slots: Choose which slots to choose between for playback when this action is triggered", - // false, - // &(menu.playback_slot.bits() as u32), - // ); - input_tab.add_submenu_with_toggles::( - "Mash Ends Playback", - "playback_mash", - "Mash Ends Playback: End input recording playback when a mash trigger occurs", - true, - &(menu.playback_mash as u32), + &(menu.recording_slot as u32), ); input_tab.add_submenu_with_toggles::( "Recording Trigger", @@ -780,10 +759,31 @@ pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu<'static> { true, &(menu.record_trigger as u32), ); + input_tab.add_submenu_with_toggles::( + "Save State Playback", + "save_state_playback", + "Save State Playback: Begin recorded input playback upon loading a save state", + true, + &(menu.save_state_playback as u32), + ); + input_tab.add_submenu_with_toggles::( // TODO: This menu should really be a submenu inside Action menus, probably want to be able to customize for each action + "Playback Slots", + "playback_slot", + "Playback Slots: Choose which slots to choose between for playback when this action is triggered", + false, + &(menu.playback_slot.bits() as u32), + ); + input_tab.add_submenu_with_toggles::( + "Mash Ends Playback", + "playback_mash", + "Mash Ends Playback: End input recording playback when a mash trigger occurs", + true, + &(menu.playback_mash as u32), + ); input_tab.add_submenu_with_toggles::( - "Hitstun Playback Trigger", + "Playback Hitstun Timing", "hitstun_playback", - "Hitstun Playback Trigger: When to begin playing back inputs on hitstun mash trigger", + "Playback Hitstun Timing: When to begin playing back inputs on hitstun mash trigger", true, &(menu.hitstun_playback as u32), ); diff --git a/training_mod_consts/src/options.rs b/training_mod_consts/src/options.rs index 7674d3c..c5fe470 100644 --- a/training_mod_consts/src/options.rs +++ b/training_mod_consts/src/options.rs @@ -1168,20 +1168,14 @@ pub enum RecordSlot { } impl RecordSlot { - pub fn into_int(self) -> Option { // TODO: Do I need an into_int here? - #[cfg(feature = "smash")] - { - Some(match self { - RecordSlot::S1 => 1, - RecordSlot::S2 => 2, - RecordSlot::S3 => 3, - RecordSlot::S4 => 4, - RecordSlot::S5 => 5, - }) + pub fn into_idx(self) -> usize { + match self { + RecordSlot::S1 => 0, + RecordSlot::S2 => 1, + RecordSlot::S3 => 2, + RecordSlot::S4 => 3, + RecordSlot::S5 => 4, } - - #[cfg(not(feature = "smash"))] - None } pub fn as_str(self) -> Option<&'static str> { @@ -1220,21 +1214,15 @@ bitflags! { } impl PlaybackSlot { - pub fn into_int(self) -> Option { - #[cfg(feature = "smash")] - { - Some(match self { - PlaybackSlot::S1 => 1, - PlaybackSlot::S2 => 2, - PlaybackSlot::S3 => 3, - PlaybackSlot::S4 => 4, - PlaybackSlot::S5 => 5, - _ => return None, - }) - } - - #[cfg(not(feature = "smash"))] - None + pub fn into_idx(self) -> Option { + Some(match self { + PlaybackSlot::S1 => 0, + PlaybackSlot::S2 => 1, + PlaybackSlot::S3 => 2, + PlaybackSlot::S4 => 3, + PlaybackSlot::S5 => 4, + _ => return None, + }) } pub fn as_str(self) -> Option<&'static str> {