diff --git a/src/training/combo.rs b/src/training/combo.rs index 3c94289..57cfd15 100644 --- a/src/training/combo.rs +++ b/src/training/combo.rs @@ -2,6 +2,7 @@ use skyline::nn::ui2d::ResColor; use training_mod_consts::OnOff; use crate::common::*; +use crate::consts::Action; use crate::sync::*; use crate::training::ui::notifications; use crate::training::*; @@ -37,9 +38,9 @@ unsafe fn is_actionable(module_accessor: *mut BattleObjectModuleAccessor) -> boo [ FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ESCAPE_AIR, // Airdodge FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ATTACK_AIR, // Aerial - FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_GUARD_ON, // Shield - FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ESCAPE, // Spotdodge/Roll - FIGHTER_STATUS_TRANSITION_TERM_ID_DOWN_STAND, // Neutral Getup from Tech/Slip + FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_GUARD_ON, // Shield + FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ESCAPE, // Spotdodge/Roll + FIGHTER_STATUS_TRANSITION_TERM_ID_DOWN_STAND, // Neutral Getup from Tech/Slip ] .iter() .any(|actionable_transition| { @@ -90,48 +91,69 @@ pub unsafe fn once_per_frame(module_accessor: &mut BattleObjectModuleAccessor) { } let player_module_accessor = get_module_accessor(FighterId::Player); let cpu_module_accessor = get_module_accessor(FighterId::CPU); - + let player_is_actionable = is_actionable(player_module_accessor); + let player_was_actionable = read_rwlock(&PLAYER_WAS_ACTIONABLE); + let player_just_actionable = !player_was_actionable && player_is_actionable; + let cpu_is_actionable = is_actionable(cpu_module_accessor); + let cpu_was_actionable = read_rwlock(&CPU_WAS_ACTIONABLE); + let cpu_just_actionable = !cpu_was_actionable && cpu_is_actionable; let is_counting = frame_counter::is_counting(*PLAYER_FRAME_COUNTER_INDEX) || frame_counter::is_counting(*CPU_FRAME_COUNTER_INDEX); + if !is_counting { - if (!was_in_shieldstun(cpu_module_accessor) && is_in_shieldstun(cpu_module_accessor)) - || (!was_in_hitstun(cpu_module_accessor) && is_in_hitstun(cpu_module_accessor)) + if MENU.mash_state == Action::empty() + && !player_is_actionable + && !cpu_is_actionable + && (!was_in_shieldstun(cpu_module_accessor) && is_in_shieldstun(cpu_module_accessor) + || (!was_in_hitstun(cpu_module_accessor) && is_in_hitstun(cpu_module_accessor))) { - // start counting + // Start counting when: + // 1. We have no mash option selected AND + // 2. Neither fighter is currently actionable AND + // 3. Either + // a. the CPU has just entered shieldstun + // b. the CPU has just entered hitstun + // + // If a mash option is selected, this can interfere with our ability to determine when + // a character becomes actionable. So don't ever start counting if we can't reliably stop. + // + // Since our "just_actionable" checks assume that neither character is already actionable, + // we need to guard against instances where the player is already actionable by the time that + // the CPU get hit, such as if the player threw a projectile from far away. + // Otherwise our "just_actionable" checks are not valid. + // + // We also need to guard against instances where the CPU's status is in hitstun but they are actually actionable. + // I dunno, makes no sense to me either. Can trigger this edge case with PAC-MAN jab 1 against Lucas at 0%. + // This shows up as the count restarting immediately after the last one ended. frame_counter::reset_frame_count(*PLAYER_FRAME_COUNTER_INDEX); frame_counter::reset_frame_count(*CPU_FRAME_COUNTER_INDEX); frame_counter::start_counting(*PLAYER_FRAME_COUNTER_INDEX); frame_counter::start_counting(*CPU_FRAME_COUNTER_INDEX); } } else { - let player_is_actionable = is_actionable(player_module_accessor); - let player_was_actionable = read_rwlock(&PLAYER_WAS_ACTIONABLE); - let player_just_actionable = !player_was_actionable && player_is_actionable; - let cpu_is_actionable = is_actionable(cpu_module_accessor); - let cpu_was_actionable = read_rwlock(&CPU_WAS_ACTIONABLE); - let cpu_just_actionable = !cpu_was_actionable && cpu_is_actionable; + // Uncomment this if you want some frame logging + // if (player_is_actionable && cpu_is_actionable) { + // info!("!"); + // } else if (!player_is_actionable && cpu_is_actionable) { + // info!("-"); + // } else if (player_is_actionable && !cpu_is_actionable) { + // info!("+"); + // } else { + // info!("."); + // } - // if (player_is_actionable && cpu_is_actionable) { warn!("!"); } - // else if (!player_is_actionable && cpu_is_actionable) { warn!("-"); } - // else if (player_is_actionable && !cpu_is_actionable) { warn!("+"); } - // else { warn!("."); } - - // Check if either player has become actionable and should stop counting + // Stop counting as soon as each fighter becomes actionable if player_just_actionable { - warn!("Player just actionable"); frame_counter::stop_counting(*PLAYER_FRAME_COUNTER_INDEX); } if cpu_just_actionable { - warn!("CPU just actionable"); frame_counter::stop_counting(*CPU_FRAME_COUNTER_INDEX); } - // Check if we just finished counting: - // Neither counter is actively counting, and someone just became actionable - // Then display the frame advantage - if (!frame_counter::is_counting(*PLAYER_FRAME_COUNTER_INDEX) - && !frame_counter::is_counting(*CPU_FRAME_COUNTER_INDEX)) + // If we just finished counting for the second fighter, then display frame advantage + if !frame_counter::is_counting(*PLAYER_FRAME_COUNTER_INDEX) + && !frame_counter::is_counting(*CPU_FRAME_COUNTER_INDEX) && (player_just_actionable || cpu_just_actionable) { update_frame_advantage( diff --git a/src/training/frame_counter.rs b/src/training/frame_counter.rs index 91ce51c..645bb6a 100644 --- a/src/training/frame_counter.rs +++ b/src/training/frame_counter.rs @@ -76,7 +76,7 @@ pub fn should_delay(delay: u32, index: usize) -> bool { } pub fn get_frame_count(index: usize) -> u32 { - let counters_guard = lock_write_rwlock(&COUNTERS); + let counters_guard = lock_read_rwlock(&COUNTERS); (*counters_guard)[index].count }