From 338a83496f3c9934bdff8620b41161456160b3e6 Mon Sep 17 00:00:00 2001
From: jugeeya <jugeeya@live.com>
Date: Fri, 4 Aug 2023 19:10:48 -0700
Subject: [PATCH] Inital attempt

---
 src/training/input_record.rs       | 31 +++++-----------
 training_mod_consts/src/lib.rs     |  9 +++++
 training_mod_consts/src/options.rs | 58 ++++++++++++++++++++++++++++++
 3 files changed, 76 insertions(+), 22 deletions(-)

diff --git a/src/training/input_record.rs b/src/training/input_record.rs
index 82ace20..acecad8 100644
--- a/src/training/input_record.rs
+++ b/src/training/input_record.rs
@@ -48,9 +48,8 @@ use PossessionState::*;
 
 const STICK_NEUTRAL: f32 = 0.2;
 const STICK_CLAMP_MULTIPLIER: f32 = 1.0 / 120.0; // 120.0 = CLAMP_MAX
-const FINAL_RECORD_MAX: usize = 150; // Maximum length for input recording sequences (capacity)
+const FINAL_RECORD_MAX: usize = 600; // Maximum length for input recording sequences (capacity)
 const TOTAL_SLOT_COUNT: usize = 5; // Total number of input recording slots
-pub static mut FINAL_RECORD_FRAME: usize = FINAL_RECORD_MAX; // The final frame to play back of the currently recorded sequence (size)
 pub static mut INPUT_RECORD: InputRecordState = InputRecordState::None;
 pub static mut INPUT_RECORD_FRAME: usize = 0;
 pub static mut POSSESSION: PossessionState = PossessionState::Player;
@@ -62,10 +61,13 @@ pub static mut STARTING_STATUS: i32 = 0; // The first status entered in the reco
                                          //     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_PLAYBACK_SLOT: usize = 0; // Which slot is being used for playback right now?
+pub static mut CURRENT_FRAME_LENGTH: usize = 60;
 
 lazy_static! {
     static ref P1_FINAL_MAPPING: Mutex<[[MappedInputs; FINAL_RECORD_MAX]; TOTAL_SLOT_COUNT]> =
         Mutex::new([[{ MappedInputs::default() }; FINAL_RECORD_MAX]; TOTAL_SLOT_COUNT]);
+    static ref P1_FRAME_LENGTH_MAPPING: Mutex<[usize; TOTAL_SLOT_COUNT]> =
+        Mutex::new([60usize; TOTAL_SLOT_COUNT]);
     static ref P1_STARTING_STATUSES: Mutex<[StartingStatus; TOTAL_SLOT_COUNT]> =
         Mutex::new([{ StartingStatus::Other }; TOTAL_SLOT_COUNT]);
 }
@@ -182,23 +184,19 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces
             module_accessor,
             button_config::ButtonCombo::InputPlayback,
         ) {
-            //crate::common::raygun_printer::print_string(&mut *module_accessor, "PLAYBACK");
             playback(MENU.playback_slot.get_random().into_idx().unwrap_or(0));
-            println!("Playback Command Received!"); //debug
         }
         // Attack + Dpad Left: Record
         else if button_config::combo_passes_exclusive(
             module_accessor,
             button_config::ButtonCombo::InputRecord,
         ) {
-            //crate::common::raygun_printer::print_string(&mut *module_accessor, "RECORDING");
             lockout_record();
-            println!("Record Command Received!"); //debug
         }
 
         // may need to move this to another func
         if (INPUT_RECORD == Record || INPUT_RECORD == Playback)
-            && INPUT_RECORD_FRAME >= FINAL_RECORD_FRAME - 1
+            && INPUT_RECORD_FRAME >= CURRENT_FRAME_LENGTH - 1
         {
             INPUT_RECORD = None;
             POSSESSION = Player;
@@ -282,6 +280,8 @@ pub unsafe fn lockout_record() {
         .for_each(|mapped_input| {
             *mapped_input = MappedInputs::default();
         });
+    CURRENT_FRAME_LENGTH = MENU.recording_frames as usize;
+    P1_FRAME_LENGTH_MAPPING.lock()[CURRENT_RECORD_SLOT] = CURRENT_FRAME_LENGTH;
     LOCKOUT_FRAME = 30; // This needs to be this high or issues occur dropping shield - but does this cause problems when trying to record ledge?
     BUFFER_FRAME = 0;
     // Store the direction the CPU is facing when we initially record, so we can turn their inputs around if needed
@@ -290,20 +290,6 @@ pub unsafe fn lockout_record() {
     CURRENT_LR = RECORDED_LR;
 }
 
-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()[CURRENT_RECORD_SLOT]
-        .iter_mut()
-        .for_each(|mapped_input| {
-            *mapped_input = MappedInputs::default();
-        });
-    INPUT_RECORD_FRAME = 0;
-    LOCKOUT_FRAME = 0;
-    BUFFER_FRAME = 0;
-}
-
 pub unsafe fn playback(slot: usize) {
     if INPUT_RECORD == Pause {
         println!("Tried to playback during lockout!");
@@ -328,6 +314,7 @@ pub unsafe fn playback(slot: usize) {
     );
 
     CURRENT_PLAYBACK_SLOT = slot;
+    CURRENT_FRAME_LENGTH = P1_FRAME_LENGTH_MAPPING.lock()[CURRENT_RECORD_SLOT];
     INPUT_RECORD = Playback;
     POSSESSION = Player;
     INPUT_RECORD_FRAME = 0;
@@ -524,7 +511,7 @@ unsafe fn set_cpu_controls(p_data: *mut *mut u8) {
         // When buffering an option, we keep inputting the first frame of input during the buffer window
         if BUFFER_FRAME > 0 {
             BUFFER_FRAME -= 1;
-        } else if INPUT_RECORD_FRAME < FINAL_RECORD_FRAME - 1 && POSSESSION != Standby {
+        } else if INPUT_RECORD_FRAME < CURRENT_FRAME_LENGTH - 1 && POSSESSION != Standby {
             INPUT_RECORD_FRAME += 1;
         }
     }
diff --git a/training_mod_consts/src/lib.rs b/training_mod_consts/src/lib.rs
index 3717258..00b6b47 100644
--- a/training_mod_consts/src/lib.rs
+++ b/training_mod_consts/src/lib.rs
@@ -77,6 +77,7 @@ pub struct TrainingModpackMenu {
     pub playback_slot: PlaybackSlot,
     pub playback_mash: OnOff,
     pub record_trigger: RecordTrigger,
+    pub recording_frames: RecordingFrames,
     pub hitstun_playback: HitstunPlayback,
 }
 
@@ -173,6 +174,7 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu {
     playback_slot: PlaybackSlot::S1,
     playback_mash: OnOff::On,
     record_trigger: RecordTrigger::None, //Command?
+    recording_frames: RecordingFrames::F150,
     hitstun_playback: HitstunPlayback::Hitstun,
     // TODO: alphabetize
 };
@@ -759,6 +761,13 @@ pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu<'static> {
         true,
         &(menu.record_trigger as u32),
     );
+    input_tab.add_submenu_with_toggles::<RecordingFrames>(
+        "Recording Frames",
+        "recording_frames",
+        "Recording Frames: Number of frames to record for in the current slot",
+        true,
+        &(menu.recording_frames as u32),
+    );
     input_tab.add_submenu_with_toggles::<OnOff>(
         "Save State Playback",
         "save_state_playback",
diff --git a/training_mod_consts/src/options.rs b/training_mod_consts/src/options.rs
index 26c979c..2f9c8fa 100644
--- a/training_mod_consts/src/options.rs
+++ b/training_mod_consts/src/options.rs
@@ -1410,3 +1410,61 @@ impl ToggleTrait for HitstunPlayback {
         HitstunPlayback::iter().map(|i| i as u32).collect()
     }
 }
+
+#[repr(u32)]
+#[derive(
+    Debug, Clone, Copy, PartialEq, FromPrimitive, EnumIter, Serialize_repr, Deserialize_repr,
+)]
+pub enum RecordingFrames {
+    F60 = 0x1,
+    F90 = 0x2,
+    F120 = 0x4,
+    F150 = 0x8,
+    F180 = 0x10,
+    F210 = 0x20,
+    F240 = 0x40,
+    F300 = 0x80,
+    F360 = 0x100,
+    F420 = 0x200,
+    F480 = 0x400,
+    F540 = 0x800,
+    F600 = 0x1000,
+}
+
+impl RecordingFrames {
+    pub fn as_str(self) -> Option<&'static str> {
+        use RecordingFrames::*;
+        Some(match self {
+            F60 => "60",
+            F90 => "90",
+            F120 => "120",
+            F150 => "150",
+            F180 => "180",
+            F210 => "210",
+            F240 => "240",
+            F300 => "300",
+            F360 => "360",
+            F420 => "420",
+            F480 => "480",
+            F540 => "540",
+            F600 => "600",
+            _ => return None,
+        })
+    }
+
+    pub fn into_frames(self) -> usize {
+        (log_2(self as u32) as usize * 30) + 60
+    }
+}
+
+impl ToggleTrait for RecordingFrames {
+    fn to_toggle_strs() -> Vec<&'static str> {
+        RecordingFrames::iter()
+            .map(|i| i.as_str().unwrap_or(""))
+            .collect()
+    }
+
+    fn to_toggle_vals() -> Vec<u32> {
+        RecordingFrames::iter().map(|i| i as u32).collect()
+    }
+}