1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2025-03-22 22:36:10 +00:00

Followups (#108)

* Fix Late Mash

Fixed being a frame late
Flag is now immediately returned until the action is performed

Also restore Airdodge =>  Shield when grounded behavior

* Update TrainingModpackOverlay

* Add Follow Ups WIP

Attack followups will currently overwrite the aerial toggle

* Simplify Shield

Extra attack handling is no longer needed

* Apply Action Enum

Replacing Mash

* Fix Random OOS

* Implement Queued Mashes

* Update Shield Suspension

Removed need for frame counter.
Update shield suspension when the mash buffer is updated.

Fixes follow ups oos

* Cleanup

* Cleanup

* Update Aerial Flags

* Fix Aerial Flag

* Fix Copy Paste Error

* Use Mash Toggles For Ledge Jump

Moved menu logic to buffer_menu_mash
This commit is contained in:
sidschingis 2020-07-05 22:13:54 +02:00 committed by GitHub
parent a19245e126
commit 0fc8fdf999
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 283 additions and 200 deletions

@ -1 +1 @@
Subproject commit 4393224a14cf6cca1cd1ff7f4e8517ca58071505 Subproject commit 1bede8c899d015e8cad641926680c2da385fd5dd

View file

@ -112,21 +112,6 @@ impl From<i32> for Attack {
} }
} }
impl Attack {
pub fn into_attack_air_kind(&self) -> Option<i32> {
use Attack::*;
Some(match self {
Nair => *FIGHTER_COMMAND_ATTACK_AIR_KIND_N,
Fair => *FIGHTER_COMMAND_ATTACK_AIR_KIND_F,
Bair => *FIGHTER_COMMAND_ATTACK_AIR_KIND_B,
Dair => *FIGHTER_COMMAND_ATTACK_AIR_KIND_LW,
UpAir => *FIGHTER_COMMAND_ATTACK_AIR_KIND_HI,
_ => return None,
})
}
}
// Ledge Option // Ledge Option
#[repr(i32)] #[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
@ -268,12 +253,92 @@ pub enum OnOff {
On = 1, On = 1,
} }
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Action {
Nothing = 0,
Airdodge = 1,
Jump = 2,
Spotdodge = 3,
RollForward = 4,
RollBack = 5,
Nair = 6,
Fair = 7,
Bair = 8,
UpAir = 9,
Dair = 10,
NeutralB = 11,
SideB = 12,
UpB = 13,
DownB = 14,
UpSmash = 15,
FSmash = 16,
DSmash = 17,
Grab = 18,
Jab = 19,
Ftilt = 20,
Utilt = 21,
Dtilt = 22,
Shield = 99,
}
impl Action {
pub fn into_attack_air_kind(&self) -> Option<i32> {
use Action::*;
Some(match self {
Nair => *FIGHTER_COMMAND_ATTACK_AIR_KIND_N,
Fair => *FIGHTER_COMMAND_ATTACK_AIR_KIND_F,
Bair => *FIGHTER_COMMAND_ATTACK_AIR_KIND_B,
Dair => *FIGHTER_COMMAND_ATTACK_AIR_KIND_LW,
UpAir => *FIGHTER_COMMAND_ATTACK_AIR_KIND_HI,
_ => return None,
})
}
}
// To satisfy the unused warning
impl From<i32> for Action {
fn from(x: i32) -> Self {
use Action::*;
match x {
0 => Nothing,
1 => Airdodge,
2 => Jump,
3 => Spotdodge,
4 => RollForward,
5 => RollBack,
6 => Nair,
7 => Fair,
8 => Bair,
9 => UpAir,
10 => Dair,
11 => NeutralB,
12 => SideB,
13 => UpB,
14 => DownB,
15 => UpSmash,
16 => FSmash,
17 => DSmash,
18 => Grab,
19 => Jab,
20 => Ftilt,
21 => Utilt,
22 => Dtilt,
99 => Action::Shield,
_ => Nothing,
}
}
}
#[repr(C)] #[repr(C)]
pub struct TrainingModpackMenu { pub struct TrainingModpackMenu {
pub hitbox_vis: HitboxVisualization, pub hitbox_vis: HitboxVisualization,
pub di_state: Direction, pub di_state: Direction,
pub left_stick: Direction, // Currently only used for air dodge direction pub left_stick: Direction, // Currently only used for air dodge direction
pub mash_attack_state: Attack, pub mash_attack_state: Attack,
pub follow_up: Action,
pub ledge_state: LedgeOption, pub ledge_state: LedgeOption,
pub tech_state: TechOption, pub tech_state: TechOption,
pub mash_state: Mash, pub mash_state: Mash,

View file

@ -9,6 +9,7 @@ pub static mut MENU_STRUCT: consts::TrainingModpackMenu = consts::TrainingModpac
di_state: Direction::None, di_state: Direction::None,
left_stick: Direction::None, left_stick: Direction::None,
mash_attack_state: Attack::Nair, mash_attack_state: Attack::Nair,
follow_up: Action::Nothing,
ledge_state: LedgeOption::Random, ledge_state: LedgeOption::Random,
tech_state: TechOption::Random, tech_state: TechOption::Random,
mash_state: Mash::None, mash_state: Mash::None,

View file

@ -40,7 +40,12 @@ pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor
status = new_status; status = new_status;
} }
mash::perform_defensive_option(); match ledge_case {
LedgeOption::Jump => {
mash::buffer_menu_mash(module_accessor);
}
_ => mash::perform_defensive_option(),
}
StatusModule::change_status_request_from_script(module_accessor, status, true); StatusModule::change_status_request_from_script(module_accessor, status, true);
} }

View file

@ -6,43 +6,60 @@ use smash::app::{self, lua_bind::*};
use smash::hash40; use smash::hash40;
use smash::lib::lua_const::*; use smash::lib::lua_const::*;
static mut BUFFERED_ACTION: Mash = Mash::None; static mut CURRENT_AERIAL: Action = Action::Nair;
static mut BUFFERED_ATTACK: Attack = Attack::Nair; static mut QUEUE: Vec<Action> = vec![];
pub fn buffer_action(action: Mash) { pub fn buffer_action(action: Action) {
unsafe { unsafe {
if BUFFERED_ACTION != Mash::None { if QUEUE.len() > 0 {
return; return;
} }
} }
unsafe { unsafe {
BUFFERED_ACTION = action; QUEUE.insert(0, action);
buffer_follow_up();
} }
} }
pub fn get_current_buffer() -> Mash { pub fn buffer_follow_up() {
unsafe { BUFFERED_ACTION } let action;
}
pub fn set_attack(attack: Attack) {
unsafe { unsafe {
if BUFFERED_ATTACK == attack { action = MENU.follow_up;
}
if action == Action::Nothing {
return; return;
} }
}
unsafe { unsafe {
BUFFERED_ATTACK = attack; QUEUE.insert(0, action);
} }
} }
pub fn get_current_attack() -> Attack { pub fn get_current_buffer() -> Action {
unsafe { BUFFERED_ATTACK } unsafe {
let current = QUEUE.last().unwrap_or(&Action::Nothing);
*current
}
} }
pub fn reset() { pub fn reset() {
unsafe { unsafe {
BUFFERED_ACTION = Mash::None; QUEUE.pop();
}
shield::suspend_shield(get_current_buffer());
}
pub fn set_aerial(attack: Action) {
if !shield::is_aerial(attack) {
return;
}
unsafe {
CURRENT_AERIAL = attack;
} }
} }
@ -57,7 +74,7 @@ pub unsafe fn get_attack_air_kind(
return None; return None;
} }
BUFFERED_ATTACK.into_attack_air_kind() CURRENT_AERIAL.into_attack_air_kind()
} }
pub unsafe fn get_command_flag_cat( pub unsafe fn get_command_flag_cat(
@ -83,7 +100,7 @@ pub unsafe fn get_command_flag_cat(
} }
unsafe fn check_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) { unsafe fn check_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) {
if BUFFERED_ACTION != Mash::None { if QUEUE.len() > 0 {
return; return;
} }
@ -91,11 +108,41 @@ unsafe fn check_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) {
return; return;
} }
let mut action = MENU.mash_state; buffer_menu_mash(module_accessor);
}
if action == Mash::Random { // Temp Translation
pub fn buffer_menu_mash(module_accessor: &mut app::BattleObjectModuleAccessor) -> Action {
unsafe {
let action;
if MENU.mash_state == Mash::Random {
action = get_random_action(module_accessor);
} else {
action = mash_to_action(MENU.mash_state);
}
buffer_action(action);
action
}
}
pub fn mash_to_action(mash: Mash) -> Action {
use Action::*;
match mash {
Mash::Airdodge => Airdodge,
Mash::Jump => Jump,
Mash::Spotdodge => Spotdodge,
Mash::RollForward => RollForward,
Mash::RollBack => RollBack,
Mash::Shield => Shield,
Mash::Attack => unsafe { attack_to_action(MENU.mash_attack_state) },
_ => Nothing,
}
}
fn get_random_action(module_accessor: &mut app::BattleObjectModuleAccessor) -> Action {
let mut random_cmds = vec![Mash::Jump, Mash::Attack]; let mut random_cmds = vec![Mash::Jump, Mash::Attack];
unsafe {
if is_airborne(module_accessor) { if is_airborne(module_accessor) {
random_cmds.push(Mash::Airdodge); random_cmds.push(Mash::Airdodge);
} }
@ -109,20 +156,45 @@ unsafe fn check_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) {
let random_cmd_index = let random_cmd_index =
app::sv_math::rand(hash40("fighter"), random_cmds.len() as i32) as usize; app::sv_math::rand(hash40("fighter"), random_cmds.len() as i32) as usize;
action = random_cmds[random_cmd_index]; mash_to_action(random_cmds[random_cmd_index])
}
} }
buffer_action(action); fn attack_to_action(attack: Attack) -> Action {
set_attack(MENU.mash_attack_state); use Action::*;
match attack {
Attack::Nair => Nair,
Attack::Fair => Fair,
Attack::Bair => Bair,
Attack::UpAir => UpAir,
Attack::Dair => Dair,
Attack::NeutralB => NeutralB,
Attack::SideB => SideB,
Attack::UpB => UpB,
Attack::DownB => DownB,
Attack::UpSmash => UpSmash,
Attack::FSmash => FSmash,
Attack::DSmash => DSmash,
Attack::Grab => Grab,
Attack::Jab => Jab,
Attack::Ftilt => Ftilt,
Attack::Utilt => Utilt,
Attack::Dtilt => Dtilt,
Attack::Nothing => Nothing,
}
} }
unsafe fn perform_action(module_accessor: &mut app::BattleObjectModuleAccessor) -> i32 { unsafe fn perform_action(module_accessor: &mut app::BattleObjectModuleAccessor) -> i32 {
match BUFFERED_ACTION { use Action::*;
Mash::Airdodge => {
let action = get_current_buffer();
match action {
Airdodge => {
// Shield if grounded instead // Shield if grounded instead
if is_grounded(module_accessor) { if is_grounded(module_accessor) {
reset(); reset();
buffer_action(Mash::Shield); buffer_action(Shield);
return 0; return 0;
} }
@ -132,50 +204,42 @@ unsafe fn perform_action(module_accessor: &mut app::BattleObjectModuleAccessor)
*FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE, *FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE,
); );
} }
Mash::Jump => { Jump => {
return update_jump_flag(module_accessor); return update_jump_flag(module_accessor);
} }
Mash::Spotdodge => { Spotdodge => {
return get_flag( return get_flag(
module_accessor, module_accessor,
*FIGHTER_STATUS_KIND_ESCAPE, *FIGHTER_STATUS_KIND_ESCAPE,
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE, *FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE,
); );
} }
Mash::RollForward => { RollForward => {
return get_flag( return get_flag(
module_accessor, module_accessor,
*FIGHTER_STATUS_KIND_ESCAPE_F, *FIGHTER_STATUS_KIND_ESCAPE_F,
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_F, *FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_F,
); );
} }
Mash::RollBack => { RollBack => {
return get_flag( return get_flag(
module_accessor, module_accessor,
*FIGHTER_STATUS_KIND_ESCAPE_B, *FIGHTER_STATUS_KIND_ESCAPE_B,
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_B, *FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_B,
); );
} }
Mash::Attack => { Shield => {
return get_attack_flag(module_accessor);
}
Mash::Shield => {
/* /*
Doesn't actually cause the shield, but will clear the buffer once shield is possible. Doesn't actually cause the shield, but will clear the buffer once shield is possible.
Shield hold is performed trough shield::should_hold_shield Shield hold is performed trough shield::should_hold_shield
*/ */
// return get_flag(
// module_accessor,
// *FIGHTER_STATUS_KIND_GUARD_ON,
// *FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE,
// );
return get_flag( return get_flag(
module_accessor, module_accessor,
*FIGHTER_STATUS_KIND_GUARD_ON, *FIGHTER_STATUS_KIND_GUARD_ON,
*FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE, *FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE,
); );
} }
_ => return 0, _ => return get_attack_flag(module_accessor, action),
} }
} }
@ -197,15 +261,18 @@ unsafe fn update_jump_flag(module_accessor: &mut app::BattleObjectModuleAccessor
); );
} }
unsafe fn get_attack_flag(module_accessor: &mut app::BattleObjectModuleAccessor) -> i32 { unsafe fn get_attack_flag(
use Attack::*; module_accessor: &mut app::BattleObjectModuleAccessor,
action: Action,
) -> i32 {
use Action::*;
let action_flag: i32; let action_flag: i32;
let status: i32; let status: i32;
match BUFFERED_ATTACK { match action {
Nair | Fair | Bair | UpAir | Dair => { Nair | Fair | Bair | UpAir | Dair => {
return get_aerial_flag(module_accessor, BUFFERED_ATTACK); return get_aerial_flag(module_accessor, action);
} }
NeutralB => { NeutralB => {
action_flag = *FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_N; action_flag = *FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_N;
@ -268,22 +335,16 @@ unsafe fn get_attack_flag(module_accessor: &mut app::BattleObjectModuleAccessor)
unsafe fn get_aerial_flag( unsafe fn get_aerial_flag(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut app::BattleObjectModuleAccessor,
attack: Attack, action: Action,
) -> i32 { ) -> i32 {
let mut flag: i32 = 0; let mut flag: i32 = 0;
// If we are grounded we also need to jump // If we are grounded we also need to jump
if is_grounded(module_accessor) { if is_grounded(module_accessor) {
flag += update_jump_flag(module_accessor); flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_JUMP_BUTTON;
if flag == 0 {
// Can't jump, return
return 0;
}
// Delay attack until we are airborne to get a full hop // Delay attack until we are airborne to get a full hop
if MENU.full_hop == OnOff::On { if MENU.full_hop == OnOff::On {
buffer_action(Mash::Attack);
return flag; return flag;
} }
} }
@ -291,38 +352,27 @@ unsafe fn get_aerial_flag(
let status = *FIGHTER_STATUS_KIND_ATTACK_AIR; let status = *FIGHTER_STATUS_KIND_ATTACK_AIR;
if MENU.falling_aerials == OnOff::On && !fast_fall::is_falling(module_accessor) { if MENU.falling_aerials == OnOff::On && !fast_fall::is_falling(module_accessor) {
// Keep Buffering until we are falling
buffer_action(Mash::Attack);
return flag; return flag;
} }
let action_flag: i32; let action_flag: i32;
use Action::*;
match attack { /*
Attack::Nair => { * We always trigger attack and change it later into the correct aerial
action_flag = *FIGHTER_COMMAND_ATTACK_AIR_KIND_N; * @see get_attack_air_kind()
} */
Attack::Fair => { match action {
// For some reason the game doesn't trigger the fair correctly Nair | Fair | Bair | UpAir | Dair => {
// action_flag = *FIGHTER_COMMAND_ATTACK_AIR_KIND_F; action_flag = *FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N;
action_flag = *FIGHTER_COMMAND_ATTACK_AIR_KIND_N;
}
Attack::Bair => {
action_flag = *FIGHTER_COMMAND_ATTACK_AIR_KIND_B;
}
Attack::UpAir => {
// For some reason the game doesn't trigger the uair correctly
// action_flag = *FIGHTER_COMMAND_ATTACK_AIR_KIND_HI;
action_flag = *FIGHTER_COMMAND_ATTACK_AIR_KIND_N;
}
Attack::Dair => {
action_flag = *FIGHTER_COMMAND_ATTACK_AIR_KIND_LW;
} }
_ => { _ => {
action_flag = 0; action_flag = 0;
} }
} }
set_aerial(action);
flag |= get_flag(module_accessor, status, action_flag); flag |= get_flag(module_accessor, status, action_flag);
flag flag
@ -347,7 +397,7 @@ unsafe fn get_flag(
pub unsafe fn perform_defensive_option() { pub unsafe fn perform_defensive_option() {
reset(); reset();
let mut shield_suspension_frames = 60; let action;
match MENU.defensive_state { match MENU.defensive_state {
Defensive::Random => { Defensive::Random => {
@ -361,28 +411,27 @@ pub unsafe fn perform_defensive_option() {
let random_cmd_index = let random_cmd_index =
app::sv_math::rand(hash40("fighter"), random_cmds.len() as i32) as usize; app::sv_math::rand(hash40("fighter"), random_cmds.len() as i32) as usize;
buffer_action(random_cmds[random_cmd_index]); action = mash_to_action(random_cmds[random_cmd_index]);
set_attack(Attack::Jab);
} }
Defensive::Roll => { Defensive::Roll => {
if app::sv_math::rand(hash40("fighter"), 2) == 0 { if app::sv_math::rand(hash40("fighter"), 2) == 0 {
buffer_action(Mash::RollForward); action = Action::RollForward;
} else { } else {
buffer_action(Mash::RollBack); action = Action::RollBack;
} }
} }
Defensive::Spotdodge => buffer_action(Mash::Spotdodge), Defensive::Spotdodge => action = Action::Spotdodge,
Defensive::Jab => { Defensive::Jab => {
buffer_action(Mash::Attack); action = Action::Jab;
set_attack(Attack::Jab);
} }
Defensive::Shield => { Defensive::Shield => {
shield_suspension_frames = 0; action = Action::Shield;
buffer_action(Mash::Shield);
} }
_ => (shield_suspension_frames = 0), _ => return,
} }
buffer_action(action);
// Suspend shield hold to allow for other defensive options // Suspend shield hold to allow for other defensive options
shield::suspend_shield(shield_suspension_frames); shield::suspend_shield(action);
} }

View file

@ -15,15 +15,13 @@ static mut MULTI_HIT_OFFSET: u32 = unsafe { MENU.oos_offset };
// Used to only decrease once per shieldstun change // Used to only decrease once per shieldstun change
static mut WAS_IN_SHIELDSTUN: bool = false; static mut WAS_IN_SHIELDSTUN: bool = false;
static mut FRAME_COUNTER_INDEX: usize = 0;
static mut REACTION_INDEX: usize = 0; static mut REACTION_INDEX: usize = 0;
// For how many frames should the shield hold be overwritten // For how many frames should the shield hold be overwritten
static mut SHIELD_SUSPEND_FRAMES: u32 = 0; static mut SUSPEND_SHIELD: bool = false;
pub fn init() { pub fn init() {
unsafe { unsafe {
FRAME_COUNTER_INDEX = frame_counter::register_counter();
REACTION_INDEX = frame_counter::register_counter(); REACTION_INDEX = frame_counter::register_counter();
} }
} }
@ -132,37 +130,23 @@ pub unsafe fn get_param_float(
None None
} }
pub unsafe fn should_hold_shield(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool { pub fn should_hold_shield() -> bool {
// Mash shield // Mash shield
if mash::get_current_buffer() == Mash::Shield { if mash::get_current_buffer() == Action::Shield {
return true; return true;
} }
let shield_state;
unsafe {
shield_state = &MENU.shield_state;
}
// We should hold shield if the state requires it // We should hold shield if the state requires it
if ![Shield::Hold, Shield::Infinite].contains(&MENU.shield_state) { if ![Shield::Hold, Shield::Infinite].contains(shield_state) {
return false; return false;
} }
// Hold shield while OOS is not allowed true
if !allow_oos() {
return true;
}
if !was_in_shieldstun(module_accessor) {
return true;
}
match mash::get_current_buffer() {
Mash::Attack => {} // Handle attack below
// If we are not mashing attack then we will always hold shield
_ => return true,
}
// We will hold shield if we are in shieldstun and our attack can be performed OOS
match mash::get_current_attack() {
Attack::Grab => return true, // Grab has 4 extra shield frames
_ => return false,
}
} }
#[skyline::hook(replace = smash::lua2cpp::L2CFighterCommon_sub_guard_cont)] #[skyline::hook(replace = smash::lua2cpp::L2CFighterCommon_sub_guard_cont)]
@ -198,43 +182,18 @@ unsafe fn mod_handle_sub_guard_cont(fighter: &mut L2CFighterCommon) {
return; return;
} }
let action = mash::buffer_menu_mash(module_accessor);
if handle_escape_option(fighter, module_accessor) { if handle_escape_option(fighter, module_accessor) {
return; return;
} }
mash::buffer_action(MENU.mash_state);
mash::set_attack(MENU.mash_attack_state);
if needs_oos_handling_drop_shield() { if needs_oos_handling_drop_shield() {
return; return;
} }
// Set shield suspension frames // Set shield suspension
match MENU.mash_state { suspend_shield(action);
Mash::Attack => match MENU.mash_attack_state {
Attack::UpSmash => {}
Attack::Grab => {}
_ => {
// Force shield drop
suspend_shield(15);
}
},
_ => {}
}
}
// Needed for shield drop options
pub fn suspend_shield(frames: u32) {
if frames <= 0 {
return;
}
unsafe {
SHIELD_SUSPEND_FRAMES = frames;
frame_counter::reset_frame_count(FRAME_COUNTER_INDEX);
frame_counter::start_counting(FRAME_COUNTER_INDEX);
}
} }
/** /**
@ -279,20 +238,20 @@ unsafe fn handle_escape_option(
return false; return false;
} }
match MENU.mash_state { match mash::get_current_buffer() {
Mash::Spotdodge => { Action::Spotdodge => {
fighter fighter
.fighter_base .fighter_base
.change_status(FIGHTER_STATUS_KIND_ESCAPE.as_lua_int(), LUA_TRUE); .change_status(FIGHTER_STATUS_KIND_ESCAPE.as_lua_int(), LUA_TRUE);
return true; return true;
} }
Mash::RollForward => { Action::RollForward => {
fighter fighter
.fighter_base .fighter_base
.change_status(FIGHTER_STATUS_KIND_ESCAPE_F.as_lua_int(), LUA_TRUE); .change_status(FIGHTER_STATUS_KIND_ESCAPE_F.as_lua_int(), LUA_TRUE);
return true; return true;
} }
Mash::RollBack => { Action::RollBack => {
fighter fighter
.fighter_base .fighter_base
.change_status(FIGHTER_STATUS_KIND_ESCAPE_B.as_lua_int(), LUA_TRUE); .change_status(FIGHTER_STATUS_KIND_ESCAPE_B.as_lua_int(), LUA_TRUE);
@ -306,55 +265,59 @@ unsafe fn handle_escape_option(
* Needed to allow these attacks to work OOS * Needed to allow these attacks to work OOS
*/ */
fn needs_oos_handling_drop_shield() -> bool { fn needs_oos_handling_drop_shield() -> bool {
match mash::get_current_buffer() { let action = mash::get_current_buffer();
Mash::Jump => return true,
Mash::Attack => { if action == Action::Jump {
let attack = mash::get_current_attack();
if is_aerial(attack) {
return true; return true;
} }
if attack == Attack::UpB { if is_aerial(action) {
return true; return true;
} }
}
_ => {} if action == Action::UpB {
return true;
} }
false false
} }
fn is_aerial(attack: Attack) -> bool { pub fn is_aerial(action: Action) -> bool {
match attack { match action {
Attack::Nair => return true, Action::Nair => return true,
Attack::Fair => return true, Action::Fair => return true,
Attack::Bair => return true, Action::Bair => return true,
Attack::UpAir => return true, Action::UpAir => return true,
Attack::Dair => return true, Action::Dair => return true,
_ => return false, _ => return false,
} }
} }
// Needed for shield drop options
pub fn suspend_shield(action: Action) {
unsafe {
SUSPEND_SHIELD = need_suspend_shield(action);
}
}
fn need_suspend_shield(action: Action) -> bool {
match action {
Action::UpSmash => false,
Action::Grab => false,
Action::Shield => false,
Action::Nothing => false,
_ => {
// Force shield drop
true
}
}
}
/** /**
* Needed for these options to work OOS * Needed for these options to work OOS
*/ */
unsafe fn shield_is_suspended() -> bool { fn shield_is_suspended() -> bool {
// Normal behavior when not mashing unsafe { SUSPEND_SHIELD }
if SHIELD_SUSPEND_FRAMES == 0 {
return false;
}
let resume_normal_behavior =
frame_counter::get_frame_count(FRAME_COUNTER_INDEX) > SHIELD_SUSPEND_FRAMES;
if resume_normal_behavior {
SHIELD_SUSPEND_FRAMES = 0;
frame_counter::stop_counting(FRAME_COUNTER_INDEX);
return false;
}
true
} }
/** /**
@ -376,7 +339,7 @@ unsafe fn should_return_none_in_check_button(
return true; return true;
} }
if !should_hold_shield(module_accessor) { if !should_hold_shield() {
return true; return true;
} }