diff --git a/src/common/events.rs b/src/common/events.rs index 8bcd4e7..64c1ce2 100644 --- a/src/common/events.rs +++ b/src/common/events.rs @@ -41,12 +41,10 @@ pub struct Uuid { impl Uuid { pub fn to_str(&self) -> String { use std::fmt::Write; - self.data - .iter() - .fold(String::new(), |mut output, b| { - let _ = write!(output, "{b:02x}"); - output - }) + self.data.iter().fold(String::new(), |mut output, b| { + let _ = write!(output, "{b:02x}"); + output + }) } } diff --git a/src/training/full_hop.rs b/src/training/full_hop.rs index f408e95..ebeeb41 100644 --- a/src/training/full_hop.rs +++ b/src/training/full_hop.rs @@ -1,6 +1,6 @@ +use crate::training::input_record; use smash::app::{self, lua_bind::*}; use smash::lib::lua_const::*; -use crate::training::input_record; use crate::common::*; diff --git a/src/training/input_record.rs b/src/training/input_record.rs index 7838881..4b27e22 100644 --- a/src/training/input_record.rs +++ b/src/training/input_record.rs @@ -1,15 +1,14 @@ -use smash::app::{BattleObjectModuleAccessor, lua_bind::*, utility}; -use smash::lib::lua_const::*; +use crate::common::consts::{FighterId, HitstunPlayback, RecordTrigger}; +use crate::common::{get_module_accessor, is_in_hitstun, is_in_shieldstun, MENU}; +use crate::training::input_recording::structures::*; +use crate::training::mash; use lazy_static::lazy_static; use parking_lot::Mutex; +use smash::app::{lua_bind::*, utility, BattleObjectModuleAccessor}; +use smash::lib::lua_const::*; use std::cmp::Ordering; -use crate::training::input_recording::structures::*; -use crate::common::consts::{RecordTrigger, HitstunPlayback, FighterId}; -use crate::common::{MENU, get_module_accessor, is_in_hitstun, is_in_shieldstun}; -use crate::training::mash; -#[derive(PartialEq)] -#[derive(Debug)] +#[derive(PartialEq, Debug)] pub enum InputRecordState { None, Pause, @@ -17,8 +16,7 @@ pub enum InputRecordState { Playback, } -#[derive(PartialEq)] -#[derive(Debug)] +#[derive(PartialEq, Debug)] pub enum PossessionState { Player, Cpu, @@ -26,20 +24,19 @@ pub enum PossessionState { Standby, } -#[derive(PartialEq)] -#[derive(Copy, Clone)] +#[derive(PartialEq, Copy, Clone)] pub enum StartingStatus { Aerial, // FIGHTER_STATUS_KIND_ATTACK_AIR TODO: This shouldn't happen without starting input recording in the air - when would we want this? // Probably should lock input recordings to either the ground or the air Airdodge, // FIGHTER_STATUS_KIND_ESCAPE_AIR, FIGHTER_STATUS_KIND_ESCAPE_AIR_SLIDE // Other statuses cannot be used to hitstun cancel via damage_fly_attack_frame/damage_fly_escape_frame // Some statuses can leave shield earlier though, so we should check for this - SpecialHi, // Up B: FIGHTER_STATUS_KIND_SPECIAL_HI, - Jump, // FIGHTER_STATUS_KIND_JUMP_SQUAT + SpecialHi, // Up B: FIGHTER_STATUS_KIND_SPECIAL_HI, + Jump, // FIGHTER_STATUS_KIND_JUMP_SQUAT DoubleJump, //FIGHTER_STATUS_KIND_JUMP_AERIAL - Spotdodge, // FIGHTER_STATUS_KIND_ESCAPE - Roll, // FIGHTER_STATUS_KIND_ESCAPE_F, FIGHTER_STATUS_KIND_ESCAPE_B - Grab, // FIGHTER_STATUS_KIND_CATCH + Spotdodge, // FIGHTER_STATUS_KIND_ESCAPE + Roll, // FIGHTER_STATUS_KIND_ESCAPE_F, FIGHTER_STATUS_KIND_ESCAPE_B + Grab, // FIGHTER_STATUS_KIND_CATCH Other, } @@ -65,11 +62,9 @@ pub static mut CURRENT_PLAYBACK_SLOT: usize = 0; // Which slot is being used for 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]); + Mutex::new([[{ MappedInputs::default() }; FINAL_RECORD_MAX]; TOTAL_SLOT_COUNT]); static ref P1_STARTING_STATUSES: Mutex<[StartingStatus; TOTAL_SLOT_COUNT]> = - Mutex::new([{StartingStatus::Other}; TOTAL_SLOT_COUNT]); + Mutex::new([{ StartingStatus::Other }; TOTAL_SLOT_COUNT]); } unsafe fn can_transition(module_accessor: *mut BattleObjectModuleAccessor) -> bool { @@ -93,7 +88,7 @@ unsafe fn should_mash_playback() { let mut should_playback = false; let cpu_module_accessor = get_module_accessor(FighterId::CPU); // depending on our current status, we want to wait for different timings to begin playback - + // TODO: This isn't the best way to write this I'm sure, want to rewrite if is_in_hitstun(&mut *cpu_module_accessor) { @@ -102,11 +97,14 @@ unsafe fn should_mash_playback() { should_playback = true; } // if we want to wait until we exit hitstop and begin flying away for shield art etc, start if we're not in hitstop - if MENU.hitstun_playback == HitstunPlayback::Hitstop && !StopModule::is_stop(cpu_module_accessor) { + if MENU.hitstun_playback == HitstunPlayback::Hitstop + && !StopModule::is_stop(cpu_module_accessor) + { 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 && can_transition(cpu_module_accessor) { + if MENU.hitstun_playback == HitstunPlayback::Hitstun && can_transition(cpu_module_accessor) + { should_playback = true; } } else if is_in_shieldstun(&mut *cpu_module_accessor) { @@ -118,7 +116,6 @@ unsafe fn should_mash_playback() { should_playback = true; } - // how do we deal with buffering motion inputs out of shield? You can't complete them in one frame, but they can definitely be buffered during shield drop // probably need a separate standby setting for grounded, aerial, shield, where shield starts once you let go of shield, and aerial keeps you in the air? @@ -132,7 +129,9 @@ unsafe fn should_mash_playback() { fn into_starting_status(status: i32) -> StartingStatus { if status == *FIGHTER_STATUS_KIND_ATTACK_AIR { return StartingStatus::Aerial; - } else if (*FIGHTER_STATUS_KIND_ESCAPE_AIR..*FIGHTER_STATUS_KIND_ESCAPE_AIR_SLIDE).contains(&status) { + } else if (*FIGHTER_STATUS_KIND_ESCAPE_AIR..*FIGHTER_STATUS_KIND_ESCAPE_AIR_SLIDE) + .contains(&status) + { return StartingStatus::Airdodge; } else if status == *FIGHTER_STATUS_KIND_SPECIAL_HI { return StartingStatus::SpecialHi; @@ -146,7 +145,7 @@ fn into_starting_status(status: i32) -> StartingStatus { return StartingStatus::Roll; } else if status == *FIGHTER_STATUS_KIND_CATCH { return StartingStatus::Grab; - } + } StartingStatus::Other } @@ -169,7 +168,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces // an erroneous definition #[allow(clippy::unnecessary_cast)] 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; let fighter_kind = utility::get_kind(module_accessor); let fighter_is_nana = fighter_kind == *FIGHTER_KIND_NANA; @@ -178,7 +177,8 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces if entry_id_int == 0 && !fighter_is_nana { // Attack + Dpad Right: Playback if ControlModule::check_button_on(module_accessor, *CONTROL_PAD_BUTTON_ATTACK) - && ControlModule::check_button_trigger(module_accessor, *CONTROL_PAD_BUTTON_APPEAL_S_R) { + && ControlModule::check_button_trigger(module_accessor, *CONTROL_PAD_BUTTON_APPEAL_S_R) + { //crate::common::raygun_printer::print_string(&mut *module_accessor, "PLAYBACK"); playback(); println!("Playback Command Received!"); //debug @@ -188,14 +188,15 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces && ControlModule::check_button_trigger(module_accessor, *CONTROL_PAD_BUTTON_APPEAL_S_L) && MENU.record_trigger == RecordTrigger::Command { - //crate::common::raygun_printer::print_string(&mut *module_accessor, "RECORDING"); - lockout_record(); - println!("Record Command Received!"); //debug + //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 { + if (INPUT_RECORD == Record || INPUT_RECORD == Playback) + && INPUT_RECORD_FRAME >= FINAL_RECORD_FRAME - 1 + { INPUT_RECORD = None; POSSESSION = Player; INPUT_RECORD_FRAME = 0; @@ -208,11 +209,29 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces // Handle Possession Coloring //let model_color_type = *MODEL_COLOR_TYPE_COLOR_BLEND; if entry_id_int == 1 && POSSESSION == Lockout { - set_color_rgb_2(module_accessor,0.0,0.0,1.0,*MODEL_COLOR_TYPE_COLOR_BLEND); + set_color_rgb_2( + module_accessor, + 0.0, + 0.0, + 1.0, + *MODEL_COLOR_TYPE_COLOR_BLEND, + ); } else if entry_id_int == 1 && POSSESSION == Standby { - set_color_rgb_2(module_accessor,1.0,0.0,1.0,*MODEL_COLOR_TYPE_COLOR_BLEND); + set_color_rgb_2( + module_accessor, + 1.0, + 0.0, + 1.0, + *MODEL_COLOR_TYPE_COLOR_BLEND, + ); } else if entry_id_int == 1 && POSSESSION == Cpu { - set_color_rgb_2(module_accessor,1.0,0.0,0.0,*MODEL_COLOR_TYPE_COLOR_BLEND); + set_color_rgb_2( + module_accessor, + 1.0, + 0.0, + 0.0, + *MODEL_COLOR_TYPE_COLOR_BLEND, + ); } } @@ -220,9 +239,11 @@ pub unsafe fn lockout_record() { INPUT_RECORD = Pause; INPUT_RECORD_FRAME = 0; POSSESSION = Lockout; - P1_FINAL_MAPPING.lock()[CURRENT_RECORD_SLOT].iter_mut().for_each(|mapped_input| { - *mapped_input = MappedInputs::default(); - }); + 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? BUFFER_FRAME = 0; // Store the direction the CPU is facing when we initially record, so we can turn their inputs around if needed @@ -235,9 +256,11 @@ 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(); - }); + 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; @@ -266,8 +289,8 @@ pub unsafe fn playback_ledge() { POSSESSION = Player; INPUT_RECORD_FRAME = 0; BUFFER_FRAME = 5; // So we can make sure the option is buffered and won't get ledge trumped if delay is 0 - // drop down from ledge can't be buffered on the same frame as jump/attack/roll/ngu so we have to do this - // Need to buffer 1 less frame for non-lassos + // drop down from ledge can't be buffered on the same frame as jump/attack/roll/ngu so we have to do this + // Need to buffer 1 less frame for non-lassos let cpu_module_accessor = get_module_accessor(FighterId::CPU); let status_kind = StatusModule::status_kind(cpu_module_accessor) as i32; if status_kind == *FIGHTER_STATUS_KIND_CLIFF_CATCH { @@ -285,18 +308,24 @@ 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()[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); - let clamped_rstick_x = ((first_frame_input.rstick_x as f32) * STICK_CLAMP_MULTIPLIER).clamp(-1.0, 1.0); - let clamped_rstick_y = ((first_frame_input.rstick_y as f32) * STICK_CLAMP_MULTIPLIER).clamp(-1.0, 1.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); + let clamped_rstick_x = + ((first_frame_input.rstick_x as f32) * STICK_CLAMP_MULTIPLIER).clamp(-1.0, 1.0); + let clamped_rstick_y = + ((first_frame_input.rstick_y as f32) * STICK_CLAMP_MULTIPLIER).clamp(-1.0, 1.0); let buttons_pressed = !first_frame_input.buttons.is_empty(); - let lstick_movement = clamped_lstick_x.abs() >= STICK_NEUTRAL || clamped_lstick_y.abs() >= STICK_NEUTRAL; - let rstick_movement = clamped_rstick_x.abs() >= STICK_NEUTRAL || clamped_rstick_y.abs() >= STICK_NEUTRAL; + let lstick_movement = + clamped_lstick_x.abs() >= STICK_NEUTRAL || clamped_lstick_y.abs() >= STICK_NEUTRAL; + let rstick_movement = + clamped_rstick_x.abs() >= STICK_NEUTRAL || clamped_rstick_y.abs() >= STICK_NEUTRAL; lstick_movement || rstick_movement || buttons_pressed } -static FIM_OFFSET: usize = 0x17504a0; +static FIM_OFFSET: usize = 0x17504a0; // TODO: Should we define all of our offsets in one file? Should at least be a good start for changing to be based on ASM instructions #[skyline::hook(offset = FIM_OFFSET)] unsafe fn handle_final_input_mapping( @@ -304,11 +333,12 @@ unsafe fn handle_final_input_mapping( player_idx: i32, // Is this the player index, or plugged in controller index? Need to check, assuming player for now - is this 0 indexed or 1? out: *mut MappedInputs, controller_struct: &mut SomeControllerStruct, - arg: bool + arg: bool, ) { // go through the original mapping function first original!()(mappings, player_idx, out, controller_struct, arg); - if player_idx == 0 { // if player 1 + if player_idx == 0 { + // if player 1 if INPUT_RECORD == Record { // check for standby before starting action: if POSSESSION == Standby && is_end_standby() { @@ -321,22 +351,24 @@ unsafe fn handle_final_input_mapping( // We're on the second frame of recording, grabbing the status should give us the status that resulted from the first frame of input // We'll want to save this status so that we use the correct TRANSITION TERM for hitstun cancelling out of damage fly let cpu_module_accessor = get_module_accessor(FighterId::CPU); - P1_STARTING_STATUSES.lock()[CURRENT_PLAYBACK_SLOT] = into_starting_status(StatusModule::status_kind(cpu_module_accessor)); - STARTING_STATUS = StatusModule::status_kind(cpu_module_accessor); // TODO: Handle this based on slot later instead + P1_STARTING_STATUSES.lock()[CURRENT_PLAYBACK_SLOT] = + into_starting_status(StatusModule::status_kind(cpu_module_accessor)); + STARTING_STATUS = StatusModule::status_kind(cpu_module_accessor); + // TODO: Handle this based on slot later instead } 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); + println!("Stored Player Input! Frame: {}", INPUT_RECORD_FRAME); } - } + } } #[skyline::hook(offset = 0x2da180)] // After cpu controls are assigned from ai calls unsafe fn set_cpu_controls(p_data: *mut *mut u8) { call_original!(p_data); let controller_data = *p_data.add(1) as *mut ControlModuleInternal; - let controller_no = (*controller_data).controller_index; + let controller_no = (*controller_data).controller_index; // Check if we need to begin playback this frame due to a mash toggle // TODO: Setup STARTING_STATUS based on current playback slot here @@ -352,38 +384,49 @@ unsafe fn set_cpu_controls(p_data: *mut *mut u8) { Ordering::Equal => { INPUT_RECORD = Record; POSSESSION = Standby; - }, - Ordering::Less => println!("LOCKOUT_FRAME OUT OF BOUNDS") + } + Ordering::Less => println!("LOCKOUT_FRAME OUT OF BOUNDS"), } } 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()[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 saved_mapped_inputs = MappedInputs::default(); } (*controller_data).buttons = saved_mapped_inputs.buttons; - (*controller_data).stick_x = x_input_multiplier * ((saved_mapped_inputs.lstick_x as f32) / (i8::MAX as f32)); + (*controller_data).stick_x = + x_input_multiplier * ((saved_mapped_inputs.lstick_x as f32) / (i8::MAX as f32)); (*controller_data).stick_y = (saved_mapped_inputs.lstick_y as f32) / (i8::MAX as f32); // Clamp stick inputs for separate part of structure - let mut clamped_lstick_x = x_input_multiplier * ((saved_mapped_inputs.lstick_x as f32) * STICK_CLAMP_MULTIPLIER).clamp(-1.0, 1.0); - let mut clamped_lstick_y = ((saved_mapped_inputs.lstick_y as f32) * STICK_CLAMP_MULTIPLIER).clamp(-1.0, 1.0); - clamped_lstick_x = if clamped_lstick_x.abs() >= STICK_NEUTRAL { clamped_lstick_x } else { 0.0 }; - clamped_lstick_y = if clamped_lstick_y.abs() >= STICK_NEUTRAL { clamped_lstick_y } else { 0.0 }; + let mut clamped_lstick_x = x_input_multiplier + * ((saved_mapped_inputs.lstick_x as f32) * STICK_CLAMP_MULTIPLIER).clamp(-1.0, 1.0); + let mut clamped_lstick_y = + ((saved_mapped_inputs.lstick_y as f32) * STICK_CLAMP_MULTIPLIER).clamp(-1.0, 1.0); + clamped_lstick_x = if clamped_lstick_x.abs() >= STICK_NEUTRAL { + clamped_lstick_x + } else { + 0.0 + }; + clamped_lstick_y = if clamped_lstick_y.abs() >= STICK_NEUTRAL { + clamped_lstick_y + } else { + 0.0 + }; (*controller_data).clamped_lstick_x = clamped_lstick_x; (*controller_data).clamped_lstick_y = clamped_lstick_y; //println!("CPU Buttons: {:#018b}", (*controller_data).buttons); - + // Keep counting frames, unless we're in standby waiting for an input, or are buffering an option // When buffering an option, we keep inputting the first frame of input during the buffer window if BUFFER_FRAME > 0 { @@ -391,7 +434,7 @@ unsafe fn set_cpu_controls(p_data: *mut *mut u8) { } else if INPUT_RECORD_FRAME < FINAL_RECORD_FRAME - 1 && POSSESSION != Standby { INPUT_RECORD_FRAME += 1; } - } + } } pub unsafe fn is_playback() -> bool { @@ -406,7 +449,8 @@ pub unsafe fn is_standby() -> bool { POSSESSION == Standby || POSSESSION == Lockout } -extern "C" { // TODO: we should be using this from skyline +extern "C" { + // TODO: we should be using this from skyline #[link_name = "\u{1}_ZN3app8lua_bind31ModelModule__set_color_rgb_implEPNS_26BattleObjectModuleAccessorEfffNS_16MODEL_COLOR_TYPEE"] pub fn set_color_rgb_2( arg1: *mut BattleObjectModuleAccessor, @@ -418,8 +462,5 @@ extern "C" { // TODO: we should be using this from skyline } pub fn init() { - skyline::install_hooks!( - set_cpu_controls, - handle_final_input_mapping, - ); + skyline::install_hooks!(set_cpu_controls, handle_final_input_mapping,); } diff --git a/src/training/input_recording/mod.rs b/src/training/input_recording/mod.rs index 616d62b..dd3a638 100644 --- a/src/training/input_recording/mod.rs +++ b/src/training/input_recording/mod.rs @@ -1,2 +1,2 @@ #[macro_use] -pub mod structures; \ No newline at end of file +pub mod structures; diff --git a/src/training/input_recording/structures.rs b/src/training/input_recording/structures.rs index e757f64..ed21a04 100644 --- a/src/training/input_recording/structures.rs +++ b/src/training/input_recording/structures.rs @@ -1,8 +1,8 @@ #![allow(dead_code)] // TODO: Yeah don't do this -use bitflags::bitflags; -use crate::common::release::CURRENT_VERSION; use crate::common::events::smash_version; +use crate::common::release::CURRENT_VERSION; use crate::training::save_states::SavedState; +use bitflags::bitflags; use training_mod_consts::TrainingModpackMenu; use crate::default_save_state; @@ -10,7 +10,6 @@ use crate::training::character_specific::steve; use crate::training::charge::ChargeState; use crate::training::save_states::SaveState::NoAction; - // Need to define necesary structures here. Probably should move to consts or something. Realistically, should be in skyline smash prob tho. // Final final controls used for controlmodule @@ -33,7 +32,8 @@ pub struct ControlModuleInternal { } impl ControlModuleInternal { - pub fn _clear(&mut self) { // Try to nullify controls so we can't control player 1 during recording + pub fn _clear(&mut self) { + // Try to nullify controls so we can't control player 1 during recording self.stick_x = 0.0; self.stick_y = 0.0; self.buttons = Buttons::empty(); @@ -46,7 +46,8 @@ impl ControlModuleInternal { #[derive(Debug, Copy, Clone)] #[repr(C)] -pub struct ControlModuleStored { // Custom type for saving only necessary controls/not saving vtable +pub struct ControlModuleStored { + // Custom type for saving only necessary controls/not saving vtable pub buttons: Buttons, pub stick_x: f32, pub stick_y: f32, @@ -72,12 +73,12 @@ pub enum ControllerStyle { RightJoycon = 0x4, ProController = 0x5, DebugPad = 0x6, // probably - GCController = 0x7 + GCController = 0x7, } #[repr(C)] pub struct AutorepeatInfo { - field: [u8; 0x18] + field: [u8; 0x18], } // Can map any of these over any button - what does this mean? @@ -155,10 +156,9 @@ pub struct ControllerMapping { pub _31: u8, pub _32: u8, pub is_absmash: bool, - pub _34: [u8; 0x1C] + pub _34: [u8; 0x1C], } - //type Buttons = u32; // may need to actually implement (like label and such)? Not for now though bitflags! { pub struct Buttons: u32 { @@ -226,14 +226,14 @@ pub struct Controller { pub is_right_wired: bool, pub _x_c1: [u8; 3], pub npad_number: u32, - pub _x_c8: [u8; 8] + pub _x_c8: [u8; 8], } // SomeControllerStruct used in hooked function - need to ask blujay what this is again #[repr(C)] pub struct SomeControllerStruct { padding: [u8; 0x10], - controller: &'static mut Controller + controller: &'static mut Controller, } // Define struct used for final controller inputs @@ -244,17 +244,18 @@ pub struct MappedInputs { pub lstick_x: i8, pub lstick_y: i8, pub rstick_x: i8, - pub rstick_y: i8 + pub rstick_y: i8, } -impl MappedInputs { // pub needed? +impl MappedInputs { + // pub needed? pub fn default() -> MappedInputs { MappedInputs { buttons: Buttons::empty(), lstick_x: 0, lstick_y: 0, rstick_x: 0, - rstick_y: 0 + rstick_y: 0, } } } @@ -273,11 +274,11 @@ pub struct Scenario { pub menu: TrainingModpackMenu, pub save_states: Vec, pub player_char: i32, // fighter_kind - pub cpu_char: i32, // fighter_kind - pub stage: i32, // index of stage, but -1 = random + pub cpu_char: i32, // fighter_kind + pub stage: i32, // index of stage, but -1 = random pub title: String, pub description: String, - pub mod_version: String, + pub mod_version: String, pub smash_version: String, // depending on version, we need to modify newly added menu options, so that regardless of their defaults they reflect the previous version to minimize breakage of old scenarios // we may also add more scenario parts to the struct in the future etc. @@ -285,7 +286,6 @@ pub struct Scenario { // datetime? // author? // mirroring? - } impl Scenario { @@ -304,4 +304,4 @@ impl Scenario { smash_version: smash_version(), } } -} \ No newline at end of file +} diff --git a/src/training/ledge.rs b/src/training/ledge.rs index 97dbab0..39e1dd6 100644 --- a/src/training/ledge.rs +++ b/src/training/ledge.rs @@ -3,7 +3,7 @@ use smash::lib::lua_const::*; use crate::common::consts::*; use crate::common::*; -use crate::training::{frame_counter, mash, input_record}; +use crate::training::{frame_counter, input_record, mash}; const NOT_SET: u32 = 9001; static mut LEDGE_DELAY: u32 = NOT_SET; @@ -60,9 +60,11 @@ fn roll_ledge_case() { fn get_ledge_option() -> Option { unsafe { let mut override_action: Option = None; - let regular_action = if MENU.mash_triggers.contains(MashTrigger::LEDGE) - {Some(MENU.mash_state.get_random())} - else {None}; + let regular_action = if MENU.mash_triggers.contains(MashTrigger::LEDGE) { + Some(MENU.mash_state.get_random()) + } else { + None + }; match LEDGE_CASE { LedgeOption::NEUTRAL => { @@ -91,7 +93,6 @@ fn get_ledge_option() -> Option { } override_action.or(regular_action) } - } pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor) { @@ -118,9 +119,13 @@ pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor let should_buffer; let prev_status_kind = StatusModule::prev_status_kind(module_accessor, 0); - if status_kind == *FIGHTER_STATUS_KIND_CLIFF_WAIT && prev_status_kind == *FIGHTER_STATUS_KIND_CLIFF_CATCH { // For regular ledge grabs, we were just in catch and want to buffer on this frame + if status_kind == *FIGHTER_STATUS_KIND_CLIFF_WAIT + && prev_status_kind == *FIGHTER_STATUS_KIND_CLIFF_CATCH + { + // For regular ledge grabs, we were just in catch and want to buffer on this frame should_buffer = (LEDGE_DELAY == 0) && (current_frame == 19) && (!flag_cliff); - } else if status_kind == *FIGHTER_STATUS_KIND_CLIFF_WAIT { // otherwise we're in "wait" from grabbing with lasso, so we want to buffer on frame + } else if status_kind == *FIGHTER_STATUS_KIND_CLIFF_WAIT { + // otherwise we're in "wait" from grabbing with lasso, so we want to buffer on frame should_buffer = (LEDGE_DELAY == 0) && (current_frame == 18) && (flag_cliff); } else { should_buffer = false; @@ -132,7 +137,11 @@ pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor ) { // Not able to take any action yet // We buffer playback on frame 18 because we don't change status this frame from inputting on next frame; do we need to do one earlier for lasso? - if should_buffer_playback && LEDGE_CASE == LedgeOption::PLAYBACK && MENU.record_trigger != RecordTrigger::Ledge && MENU.ledge_delay != LongDelay::empty() { + if should_buffer_playback + && LEDGE_CASE == LedgeOption::PLAYBACK + && MENU.record_trigger != RecordTrigger::Ledge + && MENU.ledge_delay != LongDelay::empty() + { input_record::playback_ledge(); return; } @@ -183,7 +192,8 @@ pub unsafe fn is_enable_transition_term( } // Disallow the default cliff-climb if we are waiting or we wait as part of a recording - if (LEDGE_CASE == LedgeOption::WAIT || frame_counter::get_frame_count(LEDGE_DELAY_COUNTER) < LEDGE_DELAY) + if (LEDGE_CASE == LedgeOption::WAIT + || frame_counter::get_frame_count(LEDGE_DELAY_COUNTER) < LEDGE_DELAY) && term == *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_CLIFF_CLIMB { return Some(false); @@ -195,18 +205,25 @@ pub fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccesso if !is_operation_cpu(module_accessor) { return; } - + // Set up check for beginning of ledge grab unsafe { let current_frame = MotionModule::frame(module_accessor) as i32; // Frame 18 is right before actionability for cliff catch #[allow(clippy::unnecessary_cast)] - let just_grabbed_ledge = (StatusModule::status_kind(module_accessor) as i32 == *FIGHTER_STATUS_KIND_CLIFF_CATCH) && current_frame == 18; + let just_grabbed_ledge = (StatusModule::status_kind(module_accessor) as i32 + == *FIGHTER_STATUS_KIND_CLIFF_CATCH) + && current_frame == 18; // Needs to be a frame earlier for lasso grabs #[allow(clippy::unnecessary_cast)] - let just_lassoed_ledge = (StatusModule::status_kind(module_accessor) as i32 == *FIGHTER_STATUS_KIND_CLIFF_WAIT) && current_frame == 17; + let just_lassoed_ledge = (StatusModule::status_kind(module_accessor) as i32 + == *FIGHTER_STATUS_KIND_CLIFF_WAIT) + && current_frame == 17; // Begin recording on ledge if this is the recording trigger - if (just_grabbed_ledge || just_lassoed_ledge) && MENU.record_trigger == RecordTrigger::Ledge && !input_record::is_standby() { + if (just_grabbed_ledge || just_lassoed_ledge) + && MENU.record_trigger == RecordTrigger::Ledge + && !input_record::is_standby() + { input_record::lockout_record(); return; } diff --git a/src/training/mash.rs b/src/training/mash.rs index 9496732..98090b9 100644 --- a/src/training/mash.rs +++ b/src/training/mash.rs @@ -24,13 +24,16 @@ static mut AERIAL_DELAY_COUNTER: usize = 0; static mut AERIAL_DELAY: u32 = 0; // Track if we're about to do another command flag cat run in the same frame for a dash or dash attack -static mut IS_TRANSITIONING_DASH: bool = false; +static mut IS_TRANSITIONING_DASH: bool = false; unsafe fn is_beginning_dash_attack(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool { let current_status = StatusModule::status_kind(module_accessor); let is_dashing = current_status == *FIGHTER_STATUS_KIND_DASH; let is_dash_attacking = current_status == *FIGHTER_STATUS_KIND_ATTACK_DASH; - let can_cancel_dash_attack = WorkModule::is_enable_transition_term(module_accessor, *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_CATCH_DASH); + let can_cancel_dash_attack = WorkModule::is_enable_transition_term( + module_accessor, + *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_CATCH_DASH, + ); // We have to check the frame since the transition term is wrong early in the dash attack let motion_frame = MotionModule::frame(module_accessor); is_dashing || (is_dash_attacking && (can_cancel_dash_attack || motion_frame <= 2.0)) @@ -64,12 +67,18 @@ pub fn buffer_action(action: Action) { if action == Action::empty() { return; } - + // We want to allow for triggering a mash to end playback for neutral playbacks, but not for SDI/disadv playbacks - unsafe { - // exit playback if we want to perform mash actions out of it - // TODO: Figure out some way to deal with trying to playback into another playback - if MENU.playback_mash == OnOff::On && input_record::is_playback() && !input_record::is_recording() && !input_record::is_standby() && !is_playback_queued() && action != Action::PLAYBACK { + unsafe { + // exit playback if we want to perform mash actions out of it + // TODO: Figure out some way to deal with trying to playback into another playback + if MENU.playback_mash == OnOff::On + && input_record::is_playback() + && !input_record::is_recording() + && !input_record::is_standby() + && !is_playback_queued() + && action != Action::PLAYBACK + { println!("Stopping mash playback for menu option!"); input_record::stop_playback(); } @@ -487,7 +496,7 @@ unsafe fn get_attack_flag( try_change_status(module_accessor, *FIGHTER_STATUS_KIND_DASH, dash_transition); return 0; } - + command_flag = 0; status = *FIGHTER_STATUS_KIND_ATTACK_DASH; @@ -496,7 +505,8 @@ unsafe fn get_attack_flag( let is_motion_dash = curr_motion_kind == smash::hash40("dash"); let motion_frame = MotionModule::frame(module_accessor); - if current_status == *FIGHTER_STATUS_KIND_DASH && motion_frame == 0.0 && is_motion_dash { + if current_status == *FIGHTER_STATUS_KIND_DASH && motion_frame == 0.0 && is_motion_dash + { if !IS_TRANSITIONING_DASH { // The first time these conditions are met, we aren't ready to begin dash attacking, so get ready to transition next frame IS_TRANSITIONING_DASH = true; @@ -605,7 +615,10 @@ unsafe fn get_flag( ) -> i32 { // let current_status = StatusModule::prev_status_kind(module_accessor,0); let current_status = StatusModule::status_kind(module_accessor); - println!("Current Status: {}, Expected Status: {}", current_status, expected_status); + println!( + "Current Status: {}, Expected Status: {}", + current_status, expected_status + ); if current_status == expected_status { // Reset Buffer reset(); diff --git a/src/training/mod.rs b/src/training/mod.rs index 423372e..5f63da7 100644 --- a/src/training/mod.rs +++ b/src/training/mod.rs @@ -30,11 +30,11 @@ pub mod ui; mod air_dodge_direction; mod attack_angle; mod character_specific; -mod input_recording; mod fast_fall; mod full_hop; pub mod input_delay; mod input_record; +mod input_recording; mod mash; mod reset; pub mod save_states; diff --git a/src/training/save_states.rs b/src/training/save_states.rs index bfd77ba..8bcc21e 100644 --- a/src/training/save_states.rs +++ b/src/training/save_states.rs @@ -17,17 +17,17 @@ use crate::common::consts::get_random_float; use crate::common::consts::get_random_int; use crate::common::consts::FighterId; use crate::common::consts::OnOff; -use crate::common::consts::SaveStateMirroring; use crate::common::consts::RecordTrigger; +use crate::common::consts::SaveStateMirroring; //TODO: Cleanup above use crate::common::consts::SAVE_STATES_TOML_PATH; use crate::common::is_dead; use crate::common::MENU; use crate::is_operation_cpu; -use crate::training::input_record; use crate::training::buff; use crate::training::character_specific::steve; use crate::training::charge::{self, ChargeState}; +use crate::training::input_record; use crate::training::items::apply_item; use crate::training::reset; use crate::training::ui::notifications; diff --git a/src/training/shield.rs b/src/training/shield.rs index 35cd347..1d906ea 100644 --- a/src/training/shield.rs +++ b/src/training/shield.rs @@ -8,7 +8,7 @@ use smash::lua2cpp::L2CFighterCommon; use crate::common::consts::*; use crate::common::*; -use crate::training::{mash, frame_counter, save_states, input_record}; +use crate::training::{frame_counter, input_record, mash, save_states}; // How many hits to hold shield until picking an Out Of Shield option static mut MULTI_HIT_OFFSET: u32 = 0; @@ -105,7 +105,8 @@ pub unsafe fn get_param_float( param_type: u64, param_hash: u64, ) -> Option { - if !is_operation_cpu(module_accessor) || input_record::is_playback() { // shield normally during playback + if !is_operation_cpu(module_accessor) || input_record::is_playback() { + // shield normally during playback return None; } @@ -368,7 +369,7 @@ fn needs_oos_handling_drop_shield() -> bool { } return true; } - + if action == Action::SHIELD { let shield_state; unsafe { diff --git a/training_mod_consts/src/options.rs b/training_mod_consts/src/options.rs index c5fe470..9729cae 100644 --- a/training_mod_consts/src/options.rs +++ b/training_mod_consts/src/options.rs @@ -1153,7 +1153,6 @@ impl ToggleTrait for SaveStateSlot { } } - // Input Recording Slot #[repr(u32)] #[derive( @@ -1280,7 +1279,8 @@ impl ToggleTrait for RecordTrigger { #[derive( Debug, Clone, Copy, PartialEq, FromPrimitive, EnumIter, Serialize_repr, Deserialize_repr, )] -pub enum HitstunPlayback { // Should these start at 0? All of my new menu structs need some review, I'm just doing whatever atm +pub enum HitstunPlayback { + // Should these start at 0? All of my new menu structs need some review, I'm just doing whatever atm Hitstun = 0x1, Hitstop = 0x2, Instant = 0x4, @@ -1306,4 +1306,4 @@ impl ToggleTrait for HitstunPlayback { fn to_toggle_vals() -> Vec { HitstunPlayback::iter().map(|i| i as u32).collect() } -} \ No newline at end of file +}