1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2025-02-17 22:50:32 +00:00

Refactor Mash Module (#101)

* Add Frame Counter Module

* Allow Multiple Frame Counters

* Apply Frame Counter

* Add Enum For Fighter Id

* Simplify Calculation

* Restore Original Indentation

* Add Transition Checks

Check if the transition is possible before setting the flag

* Add Normal Attacks

* Update Mash

Recactored attack options
Extracted sub functions

* Remove deprecated function

* Update Mash Module

Handle all attack options through the mash module.

* Fix Some OOS Options

Jump/Aerial/UpB

* Update Mash Module

Return the flag in get_command_flag so we don't need to borrow a mut

Removed transition check for usmash for now

* Fix Multi Buffer

Fixed buffering more than once per shield interaction

* Fix drop shield options

Options that require shield drop now work

* Use Minimal Checks

Commented out unnecessary checks

* Fix USmash OOS

* Fix Roll/Dodge OOS

* Fix Aerials

Fixed starting 1 frame late

* Fix USmash OOS again

* Remove PrintLns

* Update TrainingModpackOverlay

* Remove unused Methods

* Default To FastFall Off

* Update Defensive Options

Remove Shield Button Checks outside shield module.

* Update Defensive Options

Now handled through mash buffer

* Formatting

* Cleanup

* Reimplement Random Mash

* Add ToDos
This commit is contained in:
sidschingis 2020-06-28 20:02:26 +02:00 committed by GitHub
parent 63a3358a0f
commit c6cf52af33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 506 additions and 414 deletions

@ -1 +1 @@
Subproject commit 88e4eb92387319ad3ceb398364ecb3ab52425e86
Subproject commit eff9297a01f3df86d5bc2a0e80d00c537f44e247

View file

@ -76,6 +76,10 @@ pub enum Attack {
DownB = 8,
UpSmash = 9,
Grab = 10,
Jab = 11,
Ftilt = 12, // @TODO implement
Utilt = 13, // @TODO implement
Dtilt = 14, // @TODO implement
}
impl From<i32> for Attack {
@ -192,6 +196,7 @@ pub enum Mash {
RollForward = 5,
RollBack = 6,
Random = 7,
Shield = 99,
}
impl From<i32> for Mash {

View file

@ -2,7 +2,6 @@ pub mod consts;
use crate::common::consts::*;
use smash::app::{self, lua_bind::*};
use smash::hash40;
use smash::lib::lua_const::*;
pub static mut MENU_STRUCT: consts::TrainingModpackMenu = consts::TrainingModpackMenu {
@ -17,7 +16,7 @@ pub static mut MENU_STRUCT: consts::TrainingModpackMenu = consts::TrainingModpac
defensive_state: Defensive::Random,
oos_offset: 0,
mash_in_neutral: MashInNeutral::Off,
fast_fall: FastFall::On,
fast_fall: FastFall::Off,
};
pub static mut MENU: &'static mut consts::TrainingModpackMenu = unsafe { &mut MENU_STRUCT };
@ -55,12 +54,12 @@ pub unsafe fn is_operation_cpu(module_accessor: &mut app::BattleObjectModuleAcce
FighterInformation::is_operation_cpu(fighter_information)
}
pub unsafe fn is_grounded(module_accessor: &mut app::BattleObjectModuleAccessor) ->bool{
pub unsafe fn is_grounded(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
let situation_kind = StatusModule::situation_kind(module_accessor) as i32;
situation_kind == SITUATION_KIND_GROUND
}
pub unsafe fn is_airborne(module_accessor: &mut app::BattleObjectModuleAccessor) ->bool{
pub unsafe fn is_airborne(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
let situation_kind = StatusModule::situation_kind(module_accessor) as i32;
situation_kind == SITUATION_KIND_AIR
}
@ -84,43 +83,3 @@ pub unsafe fn is_in_shieldstun(module_accessor: &mut app::BattleObjectModuleAcce
&& status_kind == FIGHTER_STATUS_KIND_GUARD_OFF)
}
pub unsafe fn is_in_landing(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
let status_kind = StatusModule::status_kind(module_accessor);
(*FIGHTER_STATUS_KIND_LANDING..=*FIGHTER_STATUS_KIND_LANDING_DAMAGE_LIGHT)
.contains(&status_kind)
}
pub unsafe fn is_in_footstool(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
let status_kind = StatusModule::status_kind(module_accessor);
(*FIGHTER_STATUS_KIND_TREAD_DAMAGE..=*FIGHTER_STATUS_KIND_TREAD_FALL).contains(&status_kind)
}
pub unsafe fn perform_defensive_option(
_module_accessor: &mut app::BattleObjectModuleAccessor,
flag: &mut i32,
) {
match MENU.defensive_state {
Defensive::Random => {
let random_cmds = vec![
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE,
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_F,
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_B,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N,
];
let random_cmd_index =
app::sv_math::rand(hash40("fighter"), random_cmds.len() as i32) as usize;
*flag |= random_cmds[random_cmd_index];
}
Defensive::Roll => {
if app::sv_math::rand(hash40("fighter"), 2) == 0 {
*flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_F;
} else {
*flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_B;
}
}
Defensive::Spotdodge => *flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE,
Defensive::Jab => *flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N,
_ => (),
}
}

View file

@ -1,5 +1,6 @@
use crate::common::consts::*;
use crate::common::*;
use crate::training::mash;
use smash::app::{self, lua_bind::*};
use smash::hash40;
use smash::lib::lua_const::*;
@ -39,75 +40,14 @@ pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor
status = new_status;
}
mash::perform_defensive_option();
StatusModule::change_status_request_from_script(module_accessor, status, true);
}
pub unsafe fn should_perform_defensive_option(
module_accessor: &mut app::BattleObjectModuleAccessor,
prev_status: i32,
status: i32,
) -> bool {
([
*FIGHTER_STATUS_KIND_CLIFF_CLIMB,
*FIGHTER_STATUS_KIND_CLIFF_ATTACK,
*FIGHTER_STATUS_KIND_CLIFF_ESCAPE,
]
.iter()
.any(|i| i == &status || i == &prev_status))
&& (WorkModule::is_enable_transition_term(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ESCAPE,
) || CancelModule::is_enable_cancel(module_accessor))
}
pub unsafe fn defensive_option(
module_accessor: &mut app::BattleObjectModuleAccessor,
_category: i32,
flag: &mut i32,
) {
let status = StatusModule::status_kind(module_accessor) as i32;
let prev_status = StatusModule::prev_status_kind(module_accessor, 0) as i32;
if !should_perform_defensive_option(module_accessor, prev_status, status) {
return;
}
perform_defensive_option(module_accessor, flag);
}
pub unsafe fn check_button_on(
module_accessor: &mut app::BattleObjectModuleAccessor,
button: i32,
) -> Option<bool> {
if !is_training_mode() {
return None;
}
if !is_operation_cpu(module_accessor) {
return None;
}
if ![*CONTROL_PAD_BUTTON_GUARD_HOLD, *CONTROL_PAD_BUTTON_GUARD].contains(&button) {
return None;
}
if MENU.defensive_state != Defensive::Shield {
return None;
}
let prev_status = StatusModule::prev_status_kind(module_accessor, 0) as i32;
let status = StatusModule::status_kind(module_accessor) as i32;
if !should_perform_defensive_option(module_accessor, prev_status, status) {
return None;
}
Some(true)
}
pub unsafe fn get_command_flag_cat(
module_accessor: &mut app::BattleObjectModuleAccessor,
category: i32,
flag: &mut i32,
_category: i32,
) {
if !is_training_mode() {
return;
@ -122,5 +62,4 @@ pub unsafe fn get_command_flag_cat(
}
force_option(module_accessor);
defensive_option(module_accessor, category, flag);
}

View file

@ -5,6 +5,46 @@ use smash::app::{self, lua_bind::*};
use smash::hash40;
use smash::lib::lua_const::*;
static mut BUFFERED_ACTION: Mash = Mash::None;
static mut BUFFERED_ATTACK: Attack = Attack::Nair;
pub fn buffer_action(action: Mash) {
unsafe {
if BUFFERED_ACTION != Mash::None {
return;
}
}
unsafe {
BUFFERED_ACTION = action;
}
}
pub fn get_current_buffer() -> Mash {
unsafe { BUFFERED_ACTION }
}
pub fn set_attack(attack: Attack) {
unsafe {
if BUFFERED_ATTACK == attack {
return;
}
}
unsafe {
BUFFERED_ATTACK = attack;
}
}
pub fn get_current_attack() -> Attack {
unsafe { BUFFERED_ATTACK }
}
pub fn reset() {
unsafe {
BUFFERED_ACTION = Mash::None;
}
}
pub unsafe fn get_attack_air_kind(
module_accessor: &mut app::BattleObjectModuleAccessor,
) -> Option<i32> {
@ -16,177 +56,296 @@ pub unsafe fn get_attack_air_kind(
return None;
}
match MENU.mash_state {
Mash::Attack => {
return MENU.mash_attack_state.into_attack_air_kind();
}
Mash::Random => {
return Some(app::sv_math::rand(hash40("fighter"), 5) + 1);
}
_ => {
return None;
}
}
BUFFERED_ATTACK.into_attack_air_kind()
}
pub unsafe fn get_command_flag_cat(
module_accessor: &mut app::BattleObjectModuleAccessor,
category: i32,
flag: &mut i32,
) {
) -> i32 {
// Only do once per frame
if category != FIGHTER_PAD_COMMAND_CATEGORY1 {
return;
return 0;
}
if !is_training_mode() {
return;
return 0;
}
if !is_operation_cpu(module_accessor) {
return 0;
}
check_buffer(module_accessor);
perform_action(module_accessor)
}
unsafe fn check_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) {
if BUFFERED_ACTION != Mash::None {
return;
}
// Check for OOS delay
if is_in_shieldstun(module_accessor) && !shield::allow_oos() {
if !is_in_hitstun(module_accessor) && MENU.mash_in_neutral != MashInNeutral::On {
return;
}
if !(is_in_hitstun(module_accessor)
|| is_in_landing(module_accessor)
|| is_in_shieldstun(module_accessor)
|| is_in_footstool(module_accessor)
|| MENU.mash_in_neutral == MashInNeutral::On
|| StatusModule::status_kind(module_accessor) == FIGHTER_STATUS_KIND_CLIFF_ROBBED)
{
return;
let mut action = MENU.mash_state;
if action == Mash::Random {
let mut random_cmds = vec![
Mash::Jump,
Mash::Attack,
];
if is_airborne(module_accessor){
random_cmds.push(Mash::Airdodge);
}
if is_grounded(module_accessor){
random_cmds.push(Mash::RollBack);
random_cmds.push(Mash::RollForward);
random_cmds.push(Mash::Spotdodge);
}
let random_cmd_index =
app::sv_math::rand(hash40("fighter"), random_cmds.len() as i32) as usize;
action = random_cmds[random_cmd_index];
}
match MENU.mash_state {
buffer_action(action);
set_attack(MENU.mash_attack_state);
}
unsafe fn perform_action(module_accessor: &mut app::BattleObjectModuleAccessor) -> i32 {
match BUFFERED_ACTION {
Mash::Airdodge => {
*flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE;
return get_flag(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ESCAPE_AIR,
*FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE,
);
}
Mash::Jump => {
if !is_in_landing(module_accessor) {
*flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_JUMP_BUTTON;
}
return update_jump_flag(module_accessor);
}
Mash::Spotdodge => {
*flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE;
return get_flag(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ESCAPE,
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE,
);
}
Mash::RollForward => {
*flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_F;
return get_flag(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ESCAPE_F,
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_F,
);
}
Mash::RollBack => {
*flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_B;
return get_flag(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ESCAPE_B,
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_B,
);
}
Mash::Attack => {
use Attack::*;
match MENU.mash_attack_state {
Nair | Fair | Bair | UpAir | Dair => {
*flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N;
// If we are shielding we also need to jump
if is_in_shieldstun(module_accessor)
|| (is_grounded(module_accessor)
&& MENU.mash_in_neutral == MashInNeutral::On)
{
*flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_JUMP_BUTTON;
}
}
NeutralB => *flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_N,
SideB => *flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_S,
UpB => *flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_HI,
DownB => *flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_LW,
UpSmash => *flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_HI4,
Grab => *flag |= *FIGHTER_PAD_CMD_CAT1_FLAG_CATCH,
}
return get_attack_flag(module_accessor);
}
Mash::Random => {
let random_commands = get_random_command_list(module_accessor);
Mash::Shield => {
/*
Doesn't actually cause the shield, but will clear the buffer once shield is possible.
Shield hold is performed trough shield::should_hold_shield
*/
return get_flag(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_GUARD_ON,
*FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE,
);
}
_ => return 0,
}
}
if random_commands.len() == 0 {
return;
}
unsafe fn update_jump_flag(module_accessor: &mut app::BattleObjectModuleAccessor) -> i32 {
let check_flag: i32;
if is_grounded(module_accessor) {
check_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_JUMP_SQUAT_BUTTON;
} else if is_airborne(module_accessor) {
check_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_JUMP_AERIAL_BUTTON;
} else {
check_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_CLIFF_JUMP_BUTTON;
}
return get_flag(
module_accessor,
check_flag,
*FIGHTER_PAD_CMD_CAT1_FLAG_JUMP_BUTTON,
);
}
unsafe fn get_attack_flag(module_accessor: &mut app::BattleObjectModuleAccessor) -> i32 {
use Attack::*;
let action_flag: i32;
let transition_flag: i32;
match BUFFERED_ATTACK {
Nair | Fair | Bair | UpAir | Dair => {
return get_aerial_flag(module_accessor, BUFFERED_ATTACK);
}
NeutralB => {
action_flag = *FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_N;
transition_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_SPECIAL_N;
}
SideB => {
action_flag = *FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_S;
transition_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_SPECIAL_S;
}
UpB => {
action_flag = *FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_HI;
transition_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_SPECIAL_HI;
}
DownB => {
action_flag = *FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_LW;
transition_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_SPECIAL_LW;
}
UpSmash => {
action_flag = *FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_HI4;
// ATTACK_HI4 transition returns false while in shield
// transition_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ATTACK_HI4;
transition_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_JUMP_SQUAT_BUTTON;
}
Grab => {
action_flag = *FIGHTER_PAD_CMD_CAT1_FLAG_CATCH;
transition_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_CATCH;
}
Jab => {
action_flag = *FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N;
transition_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ATTACK;
}
_ => return 0,
}
return get_flag(module_accessor, transition_flag, action_flag);
}
unsafe fn get_aerial_flag(
module_accessor: &mut app::BattleObjectModuleAccessor,
attack: Attack,
) -> i32 {
let mut flag: i32 = 0;
let transition_flag: i32;
// If we are grounded we also need to jump
if is_grounded(module_accessor) {
flag += update_jump_flag(module_accessor);
if flag == 0 {
// Can't jump, return
return 0;
}
transition_flag = 0;
} else {
transition_flag = *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ATTACK_AIR;
}
let action_flag: i32;
match attack {
Attack::Nair => {
action_flag = *FIGHTER_COMMAND_ATTACK_AIR_KIND_N;
}
Attack::Fair => {
// For some reason the game doesn't trigger the fair correctly
// action_flag = *FIGHTER_COMMAND_ATTACK_AIR_KIND_F;
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;
}
}
flag |= get_flag(module_accessor, transition_flag, action_flag);
flag
}
/**
* Updates the flag if the transition is valid
*
*/
unsafe fn get_flag(
module_accessor: &mut app::BattleObjectModuleAccessor,
transition_flag: i32,
action_flag: i32,
) -> i32 {
if transition_flag > 0
&& !WorkModule::is_enable_transition_term(module_accessor, transition_flag)
{
return 0;
}
// Reset Buffer
reset();
return action_flag;
}
pub unsafe fn perform_defensive_option() {
reset();
let mut shield_suspension_frames = 60;
match MENU.defensive_state {
Defensive::Random => {
let random_cmds = vec![
Mash::Spotdodge,
Mash::RollBack,
Mash::RollForward,
Mash::Attack,
];
let random_cmd_index =
app::sv_math::rand(hash40("fighter"), random_commands.len() as i32) as usize;
app::sv_math::rand(hash40("fighter"), random_cmds.len() as i32) as usize;
*flag |= random_commands[random_cmd_index];
buffer_action(random_cmds[random_cmd_index]);
set_attack(Attack::Jab);
}
_ => (),
Defensive::Roll => {
if app::sv_math::rand(hash40("fighter"), 2) == 0 {
buffer_action(Mash::RollForward);
} else {
buffer_action(Mash::RollBack);
}
}
Defensive::Spotdodge => buffer_action(Mash::Spotdodge),
Defensive::Jab => {
buffer_action(Mash::Attack);
set_attack(Attack::Jab);
}
Defensive::Shield => {
shield_suspension_frames = 0;
buffer_action(Mash::Shield);
}
_ => (shield_suspension_frames = 0),
}
}
unsafe fn get_random_command_list(
module_accessor: &mut app::BattleObjectModuleAccessor,
) -> Vec<i32> {
let situation_kind = StatusModule::situation_kind(module_accessor) as i32;
if situation_kind == SITUATION_KIND_AIR {
return vec![
*FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE,
*FIGHTER_PAD_CMD_CAT1_FLAG_JUMP_BUTTON,
// one for each aerial
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N,
*FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_N,
*FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_S,
*FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_HI,
*FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_LW,
];
}
if situation_kind == SITUATION_KIND_GROUND {
return vec![
*FIGHTER_PAD_CMD_CAT1_FLAG_JUMP_BUTTON,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_S3,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_HI3,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_LW3,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_S4,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_HI4,
*FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_LW4,
*FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_HI,
*FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_S,
*FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_HI,
*FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_LW,
*FIGHTER_PAD_CMD_CAT1_FLAG_CATCH,
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE,
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_F,
*FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_B,
];
}
return vec![];
}
pub unsafe fn check_button_on(
module_accessor: &mut app::BattleObjectModuleAccessor,
button: i32,
) -> Option<bool> {
if !is_training_mode() {
return None;
}
if !is_operation_cpu(module_accessor) {
return None;
}
if ![*CONTROL_PAD_BUTTON_GUARD_HOLD, *CONTROL_PAD_BUTTON_GUARD].contains(&button) {
return None;
}
if MENU.mash_state == Mash::Airdodge
&& (is_in_hitstun(module_accessor)
|| is_in_landing(module_accessor)
|| is_in_footstool(module_accessor))
{
return Some(true);
}
None
// Suspend shield hold to allow for other defensive options
shield::suspend_shield(shield_suspension_frames);
}

View file

@ -64,9 +64,9 @@ pub unsafe fn handle_get_command_flag_cat(
// if (replace) return ret;
shield::get_command_flag_cat(module_accessor);
mash::get_command_flag_cat(module_accessor, category, &mut flag);
ledge::get_command_flag_cat(module_accessor, category, &mut flag);
tech::get_command_flag_cat(module_accessor, category, &mut flag);
flag |= mash::get_command_flag_cat(module_accessor, category);
ledge::get_command_flag_cat(module_accessor, category);
tech::get_command_flag_cat(module_accessor, category);
hitbox_visualizer::get_command_flag_cat(module_accessor, category);
fast_fall::get_command_flag_cat(module_accessor, category);
@ -151,14 +151,8 @@ pub unsafe fn handle_check_button_on(
module_accessor: &mut app::BattleObjectModuleAccessor,
button: i32,
) -> bool {
shield::check_button_on(module_accessor, button).unwrap_or_else(|| {
mash::check_button_on(module_accessor, button).unwrap_or_else(|| {
tech::check_button_on(module_accessor, button).unwrap_or_else(|| {
ledge::check_button_on(module_accessor, button)
.unwrap_or_else(|| original!()(module_accessor, button))
})
})
})
shield::check_button_on(module_accessor, button).unwrap_or_else(
|| original!()(module_accessor, button))
}
#[skyline::hook(replace = ControlModule::check_button_off)]
@ -225,6 +219,7 @@ pub fn training_mods() {
);
combo::init();
shield::init();
// // Input recorder
// SaltySD_function_replace_sym(

View file

@ -1,4 +1,5 @@
use crate::common::*;
use crate::training::mash;
use smash::app::{self, lua_bind::*};
use smash::lib::lua_const::*;
use smash::phx::{Hash40, Vector3f};
@ -99,6 +100,7 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor,
SAVE_STATE_PLAYER_STATE = CameraMove;
SAVE_STATE_CPU_STATE = CameraMove;
}
mash::reset();
return;
}

View file

@ -1,5 +1,8 @@
use crate::common::consts::*;
use crate::common::*;
use crate::hitbox_visualizer;
use crate::training::frame_counter;
use crate::training::mash;
use smash::app;
use smash::app::lua_bind::*;
use smash::app::sv_system;
@ -13,6 +16,17 @@ static mut MULTI_HIT_OFFSET: i32 = unsafe { MENU.oos_offset };
// Used to only decrease once per shieldstun change
static mut WAS_IN_SHIELDSTUN: bool = false;
static mut FRAME_COUNTER_INDEX: usize = 0;
// For how many frames should the shield hold be overwritten
static mut SHIELD_SUSPEND_FRAMES: u32 = 0;
pub fn init() {
unsafe {
FRAME_COUNTER_INDEX = frame_counter::register_counter();
}
}
// Toggle for shield decay
static mut SHIELD_DECAY: bool = false;
@ -118,37 +132,44 @@ pub unsafe fn get_param_float(
}
pub unsafe fn should_hold_shield(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
// Mash shield
if mash::get_current_buffer() == Mash::Shield {
return true;
}
// We should hold shield if the state requires it
if ![Shield::Hold, Shield::Infinite].contains(&MENU.shield_state) {
return false;
}
// If we are not mashing attack then we will always hold shield
if MENU.mash_state != Mash::Attack {
return true;
}
// Hold shield while OOS is not allowed
if !allow_oos() {
return true;
}
if !is_in_shieldstun(module_accessor) {
if !was_in_shieldstun(module_accessor) {
return true;
}
// We will only drop shield if we are in shieldstun and our attack can be performed OOS
if MENU.mash_state == Mash::Attack {
if [Attack::NeutralB, Attack::SideB, Attack::DownB].contains(&MENU.mash_attack_state) {
return false;
}
if MENU.mash_attack_state == Attack::Grab {
return true;
}
match mash::get_current_buffer() {
Mash::Attack => {} // Handle attack below
// Mash::RollForward => {return true}
// Mash::RollBack => {return true}
// If we are not mashing attack then we will always hold shield
_ => return true,
}
false
// We will hold shield if we are in shieldstun and our attack can be performed OOS
match mash::get_current_attack() {
// Attack::UpSmash => return true,
Attack::Grab => return true,
// Attack::UpB => return true,
// Attack::Nair => return true,
// Attack::Fair => return true,
// Attack::UpAir => return true,
// Attack::Bair => return true,
_ => return false,
}
}
#[skyline::hook(replace = smash::lua2cpp::L2CFighterCommon_sub_guard_cont)]
@ -159,10 +180,11 @@ pub unsafe fn handle_sub_guard_cont(fighter: &mut L2CFighterCommon) -> L2CValue
unsafe fn mod_handle_sub_guard_cont(fighter: &mut L2CFighterCommon) {
let module_accessor = sv_system::battle_object_module_accessor(fighter.lua_state_agent);
if !is_training_mode()
|| !is_operation_cpu(module_accessor)
|| StatusModule::prev_status_kind(module_accessor, 0) != FIGHTER_STATUS_KIND_GUARD_DAMAGE
{
if !is_training_mode() || !is_operation_cpu(module_accessor) {
return;
}
if !was_in_shieldstun(module_accessor) {
return;
}
@ -174,93 +196,52 @@ unsafe fn mod_handle_sub_guard_cont(fighter: &mut L2CFighterCommon) {
return;
}
if MENU.mash_state == Mash::Attack {
handle_attack_option(fighter, module_accessor);
if !hitbox_visualizer::is_shielding(module_accessor) {
return;
}
if WorkModule::is_enable_transition_term(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ESCAPE,
) {
handle_escape_option(fighter);
if handle_escape_option(fighter, module_accessor) {
return;
}
}
unsafe fn handle_escape_option(fighter: &mut L2CFighterCommon) {
mash::buffer_action(MENU.mash_state);
mash::set_attack(MENU.mash_attack_state);
if needs_oos_handling_drop_shield() {
return;
}
// Set shield suspension frames
match MENU.mash_state {
Mash::Spotdodge => {
fighter.fighter_base.change_status(
FIGHTER_STATUS_KIND_ESCAPE.as_lua_int(),
LUA_TRUE,
);
}
Mash::RollForward => {
fighter.fighter_base.change_status(
FIGHTER_STATUS_KIND_ESCAPE_F.as_lua_int(),
LUA_TRUE,
);
}
Mash::RollBack => {
fighter.fighter_base.change_status(
FIGHTER_STATUS_KIND_ESCAPE_B.as_lua_int(),
LUA_TRUE,
);
}
_ => (),
Mash::Attack => match MENU.mash_attack_state {
Attack::UpSmash => {}
Attack::Grab => {}
_ => {
// Force shield drop
suspend_shield(15);
}
},
_ => {}
}
}
unsafe fn handle_attack_option(
fighter: &mut L2CFighterCommon,
module_accessor: &mut app::BattleObjectModuleAccessor,
) {
match MENU.mash_attack_state {
Attack::Grab => {
if !WorkModule::is_enable_transition_term(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_CATCH,
) || WorkModule::get_int(
module_accessor,
*FIGHTER_INSTANCE_WORK_ID_INT_INVALID_CATCH_FRAME,
) != 0
{
return;
}
// Needed for shield drop options
pub fn suspend_shield(frames: u32) {
if frames <= 0 {
return;
}
fighter.fighter_base.change_status(
FIGHTER_STATUS_KIND_CATCH.as_lua_int(),
LUA_TRUE,
);
}
Attack::UpB => {
if !WorkModule::is_enable_transition_term(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_JUMP_SQUAT_BUTTON,
) {
return;
}
fighter.fighter_base.change_status(
FIGHTER_STATUS_KIND_SPECIAL_HI.as_lua_int(),
LUA_TRUE,
);
}
Attack::UpSmash => {
if !WorkModule::is_enable_transition_term(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_JUMP_SQUAT_BUTTON,
) {
return;
}
fighter.fighter_base.change_status(
FIGHTER_STATUS_KIND_ATTACK_HI4_START.as_lua_int(),
LUA_TRUE,
);
}
_ => (),
unsafe {
SHIELD_SUSPEND_FRAMES = frames;
frame_counter::reset_frame_count(FRAME_COUNTER_INDEX);
frame_counter::start_counting(FRAME_COUNTER_INDEX);
}
}
/**
* This is needed to have the CPU put up shield
*/
pub unsafe fn check_button_on(
module_accessor: &mut app::BattleObjectModuleAccessor,
button: i32,
@ -271,16 +252,116 @@ pub unsafe fn check_button_on(
Some(true)
}
/**
* This is needed to prevent dropping shield immediately
*/
pub unsafe fn check_button_off(
module_accessor: &mut app::BattleObjectModuleAccessor,
button: i32,
) -> Option<bool> {
if should_return_none_in_check_button(module_accessor, button) {
if should_return_none_in_check_button(module_accessor, button)
|| needs_oos_handling_drop_shield()
{
return None;
}
Some(false)
}
/**
* Roll/Dodge doesn't work oos the normal way
*/
unsafe fn handle_escape_option(
fighter: &mut L2CFighterCommon,
module_accessor: &mut app::BattleObjectModuleAccessor,
) -> bool {
if !WorkModule::is_enable_transition_term(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_ESCAPE,
) {
return false;
}
match MENU.mash_state {
Mash::Spotdodge => {
fighter
.fighter_base
.change_status(FIGHTER_STATUS_KIND_ESCAPE.as_lua_int(), LUA_TRUE);
return true;
}
Mash::RollForward => {
fighter
.fighter_base
.change_status(FIGHTER_STATUS_KIND_ESCAPE_F.as_lua_int(), LUA_TRUE);
return true;
}
Mash::RollBack => {
fighter
.fighter_base
.change_status(FIGHTER_STATUS_KIND_ESCAPE_B.as_lua_int(), LUA_TRUE);
return true;
}
_ => return false,
}
}
/**
* Needed to allow these attacks to work OOS
*/
fn needs_oos_handling_drop_shield() -> bool {
match 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 {
return true;
}
}
_ => {},
}
false
}
fn is_aerial(attack: Attack) -> bool {
match attack {
Attack::Nair => return true,
Attack::Fair => return true,
Attack::Bair => return true,
Attack::UpAir => return true,
Attack::Dair => return true,
_ => return false,
}
}
/**
* Needed for these options to work OOS
*/
unsafe fn shield_is_suspended() -> bool {
// Normal behavior when not mashing
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
}
/**
* AKA should the cpu hold the shield button
*/
unsafe fn should_return_none_in_check_button(
module_accessor: &mut app::BattleObjectModuleAccessor,
button: i32,
@ -301,5 +382,15 @@ unsafe fn should_return_none_in_check_button(
return true;
}
if shield_is_suspended() {
return true;
}
false
}
fn was_in_shieldstun(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
unsafe {
StatusModule::prev_status_kind(module_accessor, 0) == FIGHTER_STATUS_KIND_GUARD_DAMAGE
}
}

View file

@ -1,5 +1,6 @@
use crate::common::consts::*;
use crate::common::*;
use crate::training::mash;
use smash::app::sv_system;
use smash::app::{self, lua_bind::*};
use smash::hash40;
@ -76,6 +77,8 @@ unsafe fn mod_handle_change_status(
_ => (),
}
mash::perform_defensive_option();
return;
}
@ -98,36 +101,9 @@ unsafe fn mod_handle_change_status(
}
}
pub unsafe fn should_perform_defensive_option(
module_accessor: &mut app::BattleObjectModuleAccessor,
prev_status: i32,
status: i32,
) -> bool {
([
*FIGHTER_STATUS_KIND_PASSIVE,
*FIGHTER_STATUS_KIND_PASSIVE_FB,
*FIGHTER_STATUS_KIND_DOWN_STAND,
*FIGHTER_STATUS_KIND_DOWN_STAND_FB,
*FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK,
]
.contains(&prev_status)
|| [
*FIGHTER_STATUS_KIND_DOWN_STAND,
*FIGHTER_STATUS_KIND_DOWN_STAND_FB,
*FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK,
]
.contains(&status))
&& (WorkModule::is_enable_transition_term(
module_accessor,
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_GUARD_ON,
) || MotionModule::is_end(module_accessor)
|| CancelModule::is_enable_cancel(module_accessor))
}
pub unsafe fn get_command_flag_cat(
module_accessor: &mut app::BattleObjectModuleAccessor,
_category: i32,
flag: &mut i32,
) {
if !is_training_mode() {
return;
@ -150,9 +126,9 @@ pub unsafe fn get_command_flag_cat(
.contains(&status)
{
let random_statuses = vec![
*FIGHTER_STATUS_KIND_DOWN_STAND,
*FIGHTER_STATUS_KIND_DOWN_STAND_FB,
*FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK,
*FIGHTER_STATUS_KIND_DOWN_STAND, // Normal Getup
*FIGHTER_STATUS_KIND_DOWN_STAND_FB, // Getup Roll
*FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK, // Getup Attack
];
let random_status_index =
@ -164,42 +140,8 @@ pub unsafe fn get_command_flag_cat(
);
return;
}
let prev_status = StatusModule::prev_status_kind(module_accessor, 0) as i32;
if should_perform_defensive_option(module_accessor, prev_status, status) {
perform_defensive_option(module_accessor, flag);
}
}
pub unsafe fn check_button_on(
module_accessor: &mut app::BattleObjectModuleAccessor,
button: i32,
) -> Option<bool> {
if !is_training_mode() {
return None;
}
if !is_operation_cpu(module_accessor) {
return None;
}
if ![*CONTROL_PAD_BUTTON_GUARD_HOLD, *CONTROL_PAD_BUTTON_GUARD].contains(&button) {
return None;
}
if !(MENU.defensive_state == Defensive::Shield) {
return None;
}
let prev_status = StatusModule::prev_status_kind(module_accessor, 0) as i32;
let status = StatusModule::status_kind(module_accessor) as i32;
if !should_perform_defensive_option(module_accessor, prev_status, status) {
return None;
}
return Some(true);
}
pub unsafe fn change_motion(
module_accessor: &mut app::BattleObjectModuleAccessor,