mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2025-03-23 06:46:11 +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:
parent
a19245e126
commit
0fc8fdf999
6 changed files with 283 additions and 200 deletions
|
@ -1 +1 @@
|
||||||
Subproject commit 4393224a14cf6cca1cd1ff7f4e8517ca58071505
|
Subproject commit 1bede8c899d015e8cad641926680c2da385fd5dd
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action == Action::Nothing {
|
||||||
|
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
|
||||||
let mut random_cmds = vec![Mash::Jump, Mash::Attack];
|
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];
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)]
|
||||||
|
@ -194,47 +178,22 @@ unsafe fn mod_handle_sub_guard_cont(fighter: &mut L2CFighterCommon) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if frame_counter::should_delay(MENU.reaction_time, REACTION_INDEX){
|
if frame_counter::should_delay(MENU.reaction_time, REACTION_INDEX) {
|
||||||
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 => {
|
|
||||||
let attack = mash::get_current_attack();
|
|
||||||
if is_aerial(attack) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if attack == Attack::UpB {
|
if action == Action::Jump {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {}
|
if is_aerial(action) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue