diff --git a/README.md b/README.md
index 8a2f6d6..ece45b0 100644
--- a/README.md
+++ b/README.md
@@ -139,17 +139,16 @@ The CPU can be instructed to perform a wide array of different actions in respon
- Ledge: To be performed when hanging on the ledge
- Tech: To be performed when slammed into the ground or wall
- Miss Tech: To be performed after failing to tech
-- Defensive: To be performed after the ledge, tech, or miss tech option
The timing of the CPU option can be influenced by the following settings:
+- Mash Triggers
- Aerial Delay
- Ledge Delay
- OoS Offset
- Reaction Time
- Fast Fall Delay
- Falling Aerials
-- Mash in Neutral
-----
@@ -162,6 +161,7 @@ When multiple options are selected, one of the selected options will be chosen a
|:---:|:---:|:---|:---|
| Mash Settings | Mash Toggles | Actions to be performed as soon as possible out of hitstun or shieldstun | Airdodge, jump, shield, spotdodge, roll in, roll out, aerials, jab, tilts, smash attacks, grab, dash, dash attack |
| Mash Settings | Followup Toggles | Actions to be performed after the Mash option | Airdodge, jump, shield, spotdodge, roll in, roll out, aerials, jab, tilts, smash attacks, grab, dash, dash attack |
+| Mash Settings | Mash Triggers | Conditions which will cause the CPU to perform their mash action | Hitstun, shieldstun, parry, tumble, landing, ledge trump, footstool, clatter, ledge option, tech option, grounded, airborne, distance: close, distance: mid, distance: far, always |
| Mash Settings | Attack Angles | For attacks that can be angled, such as some forward tilts | Neutral, up, down |
| Mash Settings | Throw Options | Throw to be performed when a grab is landed | None, Forward Throw, Back Throw, Up Throw, Down Throw |
| Mash Settings | Throw Delay | How many frames to delay the throw option | 0 to 150 frames (2.5 seconds) in increments of 5 frames |
@@ -173,7 +173,6 @@ When multiple options are selected, one of the selected options will be chosen a
| Mash Settings | Fast Fall Delay | How many frames the CPU should delay their fastfall | 0 to 30 frames (0.5 seconds) |
| Mash Settings | OoS Offset | How many times the CPU shield can be hit before performing a Mash option | 0 to 30 hits |
| Mash Settings | Reaction Time | How many frames to delay before performing an option out of shield | 0 to 30 frames (0.5 seconds) |
-| Mash Settings | Mash in Neutral | Should Mash options be performed repeatedly or only when the CPU is hit | Yes, No |
| ----- | ----- | ----- | ----- |
| Defensive Settings | Airdodge Direction | Direction to angle airdodges | Neutral, out, up-out, up, up-in, in, down-in, down, down-out, left, right |
| Defensive Settings | DI Direction | Direction to angle the directional influence during hitlag | Neutral, out, up-out, up, up-in, in, down-in, down, down-out, left, right |
@@ -186,7 +185,6 @@ When multiple options are selected, one of the selected options will be chosen a
| Defensive Settings | Mistech Options | Actions to take after missing a tech | Neutral getup, getup attack, roll in, roll out |
| Defensive Settings | Shield Toggles | CPU Shield Behavior | None, Infinite (no shield damage or decay), Hold (no shield decay until the shield is hit for the first time), Constant (no shield decay) |
| Defensive Settings | Shield Tilt | Direction to tilt the shield | Neutral, out, up-out, up, up-in, in, down-in, down, down-out, left, right |
-| Defensive Settings | Defensive Options | Actions to take after a ledge option, tech option, or miss tech option | Spotdodge, roll in, roll out, jab, shield |
| Defensive Settings | Buff Options | Buff(s) to be applied to respective character when loading save states | Acceleratle, Oomph, Psyche Up, Bounce, Arsene, Deep Breathing, Limit, K.O. Punch, Wing |
| Defensive Settings | Character Item | CPU/Player item to hold when loading a save state | None, Player 1st Variation througher 8th variation, CPU 1st variation through 8th variation |
| ----- | ----- | ----- | ----- |
@@ -228,7 +226,6 @@ SD Card Root
│ │ ├── buff_state.svg
│ │ ├── check.svg
│ │ ├── clatter_strength.svg
- │ │ ├── defensive_state.svg
│ │ ├── di_state.svg
│ │ ├── falling_aerials.svg
│ │ ├── fast_fall.svg
@@ -239,8 +236,8 @@ SD Card Root
│ │ ├── input_delay.svg
│ │ ├── ledge_delay.svg
│ │ ├── ledge_state.svg
- │ │ ├── mash_in_neutral.svg
│ │ ├── mash_state.svg
+ │ │ ├── mash_triggers.svg
│ │ ├── miss_tech_state.svg
│ │ ├── oos_offset.svg
│ │ ├── pummel_delay.svg
diff --git a/src/common/mod.rs b/src/common/mod.rs
index 853c2aa..c581009 100644
--- a/src/common/mod.rs
+++ b/src/common/mod.rs
@@ -7,6 +7,7 @@ pub mod release;
use crate::common::consts::*;
use smash::app::{self, lua_bind::*};
use smash::lib::lua_const::*;
+use smash::hash40;
pub use crate::common::consts::MENU;
pub static mut DEFAULTS_MENU: TrainingModpackMenu = crate::common::consts::DEFAULTS_MENU;
@@ -92,7 +93,7 @@ pub fn is_idle(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
pub fn is_in_hitstun(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
-
+ // TODO: Should this be *FIGHTER_STATUS_KIND_DAMAGE..*FIGHTER_STATUS_KIND_DAMAGE_AIR ?
(*FIGHTER_STATUS_KIND_DAMAGE..*FIGHTER_STATUS_KIND_DAMAGE_FALL).contains(&status_kind)
}
pub fn is_in_footstool(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
@@ -142,6 +143,30 @@ pub unsafe fn is_in_clatter(module_accessor: &mut app::BattleObjectModuleAccesso
ControlModule::get_clatter_time(module_accessor, 0) > 0.0
}
+pub unsafe fn is_in_ledgetrump(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
+ let status_kind = StatusModule::status_kind(module_accessor);
+
+ status_kind == FIGHTER_STATUS_KIND_CLIFF_ROBBED
+}
+
+pub unsafe fn is_in_parry(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
+ let motion_kind = MotionModule::motion_kind(module_accessor);
+
+ motion_kind == hash40("just_shield_off")
+}
+
+pub unsafe fn is_in_tumble(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
+ let status_kind = StatusModule::status_kind(module_accessor);
+
+ (*FIGHTER_STATUS_KIND_DAMAGE_FLY..=*FIGHTER_STATUS_KIND_DAMAGE_FALL).contains(&status_kind)
+}
+
+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_LIGHT).contains(&status_kind)
+}
+
// Returns true if a match is currently active
pub unsafe fn is_ready_go() -> bool {
let fighter_manager = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
@@ -153,3 +178,18 @@ pub unsafe fn entry_count() -> i32 {
let fighter_manager = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
FighterManager::entry_count(fighter_manager)
}
+
+pub unsafe fn get_fighter_distance() -> f32 {
+ let player_module_accessor = get_module_accessor(FighterId::Player);
+ let cpu_module_accessor = get_module_accessor(FighterId::CPU);
+ let player_pos = *PostureModule::pos(player_module_accessor);
+ let cpu_pos = *PostureModule::pos(cpu_module_accessor);
+ app::sv_math::vec3_distance(
+ player_pos.x,
+ player_pos.y,
+ player_pos.z,
+ cpu_pos.x,
+ cpu_pos.y,
+ cpu_pos.z
+ )
+}
\ No newline at end of file
diff --git a/src/static/img/defensive_state.svg b/src/static/img/defensive_state.svg
deleted file mode 100644
index c7d6903..0000000
--- a/src/static/img/defensive_state.svg
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
diff --git a/src/static/img/mash_in_neutral.svg b/src/static/img/mash_in_neutral.svg
deleted file mode 100644
index 2ec302b..0000000
--- a/src/static/img/mash_in_neutral.svg
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
diff --git a/src/static/img/mash_triggers.svg b/src/static/img/mash_triggers.svg
new file mode 100644
index 0000000..0eea891
--- /dev/null
+++ b/src/static/img/mash_triggers.svg
@@ -0,0 +1,72 @@
+
+
diff --git a/src/training/clatter.rs b/src/training/clatter.rs
index dcba848..322fbfd 100644
--- a/src/training/clatter.rs
+++ b/src/training/clatter.rs
@@ -1,10 +1,13 @@
-use crate::common::{is_in_clatter, is_operation_cpu, is_training_mode, MENU};
+use crate::common::consts::*;
+use crate::common::*;
+use crate::training::mash;
use smash::app::lua_bind::{ControlModule, EffectModule};
use smash::app::BattleObjectModuleAccessor;
use smash::lib::lua_const::*;
use smash::phx::{Hash40, Vector3f};
static mut COUNTER: u32 = 0;
+static mut WAS_IN_CLATTER_FLAG: bool = false;
unsafe fn do_clatter_input(module_accessor: &mut BattleObjectModuleAccessor) {
ControlModule::add_clatter_time(module_accessor, -8.0, 0);
@@ -36,10 +39,14 @@ pub unsafe fn handle_clatter(module_accessor: &mut BattleObjectModuleAccessor) {
if !is_training_mode() || !is_operation_cpu(module_accessor) {
return;
}
-
if !is_in_clatter(module_accessor) {
+ if WAS_IN_CLATTER_FLAG && MENU.mash_triggers.contains(MashTrigger::CLATTER) {
+ mash::buffer_menu_mash();
+ }
+ WAS_IN_CLATTER_FLAG = false;
return;
}
+ WAS_IN_CLATTER_FLAG = true;
let repeat = MENU.clatter_strength.into_u32();
COUNTER = (COUNTER + 1) % repeat;
diff --git a/src/training/ledge.rs b/src/training/ledge.rs
index 96c452e..d4fe384 100644
--- a/src/training/ledge.rs
+++ b/src/training/ledge.rs
@@ -100,11 +100,8 @@ pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor
StatusModule::change_status_request_from_script(module_accessor, status, true);
- match LEDGE_CASE {
- LedgeOption::JUMP => {
- mash::buffer_menu_mash();
- }
- _ => mash::perform_defensive_option(),
+ if MENU.mash_triggers.contains(MashTrigger::LEDGE) {
+ mash::buffer_menu_mash();
}
}
diff --git a/src/training/mash.rs b/src/training/mash.rs
index d530c2d..62d67dc 100644
--- a/src/training/mash.rs
+++ b/src/training/mash.rs
@@ -9,6 +9,10 @@ use crate::training::shield;
use smash::app::{self, lua_bind::*};
use smash::lib::lua_const::*;
+const DISTANCE_CLOSE_THRESHOLD: f32 = 10.0;
+const DISTANCE_MID_THRESHOLD: f32 = 50.0;
+const DISTANCE_FAR_THRESHOLD: f32 = 100.0;
+
static mut CURRENT_AERIAL: Action = Action::NAIR;
static mut QUEUE: Vec = vec![];
@@ -137,22 +141,30 @@ unsafe fn check_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) {
buffer_menu_mash();
}
-fn should_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
- unsafe {
- if MENU.mash_in_neutral == OnOff::On {
- return true;
- }
+unsafe fn should_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
+ let fighter_distance = get_fighter_distance();
+ if MENU.mash_triggers.contains(MashTrigger::ALWAYS)
+ || (MENU.mash_triggers.contains(MashTrigger::HIT) && is_in_hitstun(module_accessor))
+ // BLOCK handled in shield.rs
+ || (MENU.mash_triggers.contains(MashTrigger::PARRY) && is_in_parry(module_accessor))
+ || (MENU.mash_triggers.contains(MashTrigger::TUMBLE) && is_in_tumble(module_accessor))
+ || (MENU.mash_triggers.contains(MashTrigger::LANDING) && is_in_landing(module_accessor))
+ || (MENU.mash_triggers.contains(MashTrigger::TRUMP) && is_in_ledgetrump(module_accessor))
+ || (MENU.mash_triggers.contains(MashTrigger::FOOTSTOOL) && is_in_footstool(module_accessor))
+ // CLATTER handled in clatter.rs
+ // LEDGE handled in ledge.rs
+ // TECH handled in tech.rs
+ // MISTECH handled in tech.rs
+ || (MENU.mash_triggers.contains(MashTrigger::GROUNDED) && is_grounded(module_accessor))
+ || (MENU.mash_triggers.contains(MashTrigger::AIRBORNE) && is_airborne(module_accessor))
+ || (MENU.mash_triggers.contains(MashTrigger::DISTANCE_CLOSE) && fighter_distance < DISTANCE_CLOSE_THRESHOLD)
+ || (MENU.mash_triggers.contains(MashTrigger::DISTANCE_MID) && fighter_distance < DISTANCE_MID_THRESHOLD)
+ || (MENU.mash_triggers.contains(MashTrigger::DISTANCE_FAR) && fighter_distance < DISTANCE_FAR_THRESHOLD)
+ {
+ true
+ } else {
+ false
}
-
- if is_in_hitstun(module_accessor) {
- return true;
- }
-
- if is_in_footstool(module_accessor) {
- return true;
- }
-
- false
}
// Temp Translation
@@ -160,7 +172,6 @@ pub fn buffer_menu_mash() {
unsafe {
let action = MENU.mash_state.get_random();
buffer_action(action);
-
full_hop::roll_full_hop();
fast_fall::roll_fast_fall();
FALLING_AERIAL = MENU.falling_aerials.get_random().into_bool();
@@ -169,7 +180,6 @@ pub fn buffer_menu_mash() {
unsafe fn perform_action(module_accessor: &mut app::BattleObjectModuleAccessor) -> i32 {
let action = get_current_buffer();
-
match action {
Action::AIR_DODGE => {
let (expected_status, command_flag) = if is_grounded(module_accessor) {
@@ -481,21 +491,3 @@ fn try_change_status(
true
}
-
-pub unsafe fn perform_defensive_option() {
- full_reset();
-
- let action = match MENU.defensive_state.get_random() {
- Defensive::ROLL_F => Action::ROLL_F,
- Defensive::ROLL_B => Action::ROLL_B,
- Defensive::SPOT_DODGE => Action::SPOT_DODGE,
- Defensive::JAB => Action::JAB,
- Defensive::SHIELD => Action::SHIELD,
- _ => Action::empty(),
- };
-
- buffer_action(action);
-
- // Suspend shield hold to allow for other defensive options
- shield::suspend_shield(action);
-}
diff --git a/src/training/mod.rs b/src/training/mod.rs
index 2f1217a..edb5c00 100644
--- a/src/training/mod.rs
+++ b/src/training/mod.rs
@@ -1,5 +1,5 @@
use crate::common::{
- is_training_mode, menu, FIGHTER_MANAGER_ADDR, ITEM_MANAGER_ADDR, STAGE_MANAGER_ADDR,
+ is_training_mode, menu, FIGHTER_MANAGER_ADDR, ITEM_MANAGER_ADDR, STAGE_MANAGER_ADDR
};
use crate::hitbox_visualizer;
use crate::training::character_specific::items;
diff --git a/src/training/shield.rs b/src/training/shield.rs
index 5f751df..18c0a9c 100644
--- a/src/training/shield.rs
+++ b/src/training/shield.rs
@@ -218,7 +218,9 @@ unsafe fn mod_handle_sub_guard_cont(fighter: &mut L2CFighterCommon) {
return;
}
- mash::buffer_menu_mash();
+ if MENU.mash_triggers.contains(MashTrigger::BLOCK) {
+ mash::buffer_menu_mash();
+ }
let action = mash::get_current_buffer();
if handle_escape_option(fighter, module_accessor) {
diff --git a/src/training/tech.rs b/src/training/tech.rs
index fc142aa..a33d49e 100644
--- a/src/training/tech.rs
+++ b/src/training/tech.rs
@@ -1,278 +1,269 @@
-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;
-use smash::lib::lua_const::*;
-use smash::lib::L2CValue;
-use smash::lua2cpp::L2CFighterBase;
-
-static mut TECH_ROLL_DIRECTION: Direction = Direction::empty();
-static mut MISS_TECH_ROLL_DIRECTION: Direction = Direction::empty();
-
-#[skyline::hook(replace = smash::lua2cpp::L2CFighterBase_change_status)]
-pub unsafe fn handle_change_status(
- fighter: &mut L2CFighterBase,
- status_kind: L2CValue,
- unk: L2CValue,
-) -> L2CValue {
- let mut status_kind = status_kind;
- let mut unk = unk;
-
- if is_training_mode() {
- mod_handle_change_status(fighter, &mut status_kind, &mut unk);
- }
-
- original!()(fighter, status_kind, unk)
-}
-
-unsafe fn mod_handle_change_status(
- fighter: &mut L2CFighterBase,
- status_kind: &mut L2CValue,
- unk: &mut L2CValue,
-) {
- let module_accessor = sv_system::battle_object_module_accessor(fighter.lua_state_agent);
- if !is_operation_cpu(module_accessor) {
- return;
- }
-
- let status_kind_int = status_kind
- .try_get_int()
- .unwrap_or(*FIGHTER_STATUS_KIND_WAIT as u64) as i32;
-
- let state: TechFlags = MENU.tech_state.get_random();
-
- if handle_grnd_tech(module_accessor, status_kind, unk, status_kind_int, state) {
- return;
- }
-
- if handle_wall_tech(module_accessor, status_kind, unk, status_kind_int, state) {
- return;
- }
-
- handle_ceil_tech(module_accessor, status_kind, unk, status_kind_int, state);
-}
-fn handle_grnd_tech(
- module_accessor: &mut app::BattleObjectModuleAccessor,
- status_kind: &mut L2CValue,
- unk: &mut L2CValue,
- status_kind_int: i32,
- state: TechFlags,
-) -> bool {
- if status_kind_int != *FIGHTER_STATUS_KIND_DOWN
- && status_kind_int != *FIGHTER_STATUS_KIND_DAMAGE_FLY_REFLECT_D
- {
- return false;
- }
-
- unsafe {
- // prev_status_kind(module_accessor, 0) gets the 1st previous status,
- // which is FIGHTER_STATUS_KIND_CATCHED_AIR_END_GANON for both aerial/grounded sideb
- // prev_status_kind(module_accessor, 1) gets the 2nd previous status,
- // which is FIGHTER_STATUS_KIND_CATCHED_GANON for grounded sideb
- // and FIGHTER_STATUS_KIND_CATCHED_AIR_GANON for aerial sideb
- let second_prev_status = StatusModule::prev_status_kind(module_accessor, 1);
- let can_tech = WorkModule::is_enable_transition_term(
- module_accessor,
- *FIGHTER_STATUS_TRANSITION_TERM_ID_PASSIVE,
- ) && (second_prev_status != FIGHTER_STATUS_KIND_CATCHED_AIR_FALL_GANON);
-
- if !can_tech {
- return false;
- }
- }
-
- match state {
- TechFlags::IN_PLACE => {
- *status_kind = FIGHTER_STATUS_KIND_PASSIVE.as_lua_int();
- *unk = LUA_TRUE;
- unsafe {
- mash::perform_defensive_option();
- }
- }
- TechFlags::ROLL_F => {
- *status_kind = FIGHTER_STATUS_KIND_PASSIVE_FB.as_lua_int();
- *unk = LUA_TRUE;
- unsafe {
- TECH_ROLL_DIRECTION = Direction::IN; // = In
- mash::perform_defensive_option();
- }
- }
- TechFlags::ROLL_B => {
- *status_kind = FIGHTER_STATUS_KIND_PASSIVE_FB.as_lua_int();
- *unk = LUA_TRUE;
- unsafe {
- TECH_ROLL_DIRECTION = Direction::OUT; // = Away
- mash::perform_defensive_option();
- }
- }
- _ => (),
- }
-
- true
-}
-
-fn handle_wall_tech(
- module_accessor: &mut app::BattleObjectModuleAccessor,
- status_kind: &mut L2CValue,
- unk: &mut L2CValue,
- status_kind_int: i32,
- state: TechFlags,
-) -> bool {
- if status_kind_int != *FIGHTER_STATUS_KIND_STOP_WALL
- && status_kind_int != *FIGHTER_STATUS_KIND_DAMAGE_FLY_REFLECT_LR
- {
- return false;
- }
-
- if state == TechFlags::NO_TECH {
- return false;
- }
-
- unsafe {
- let can_tech = WorkModule::is_enable_transition_term(
- module_accessor,
- *FIGHTER_STATUS_TRANSITION_TERM_ID_PASSIVE_WALL,
- );
-
- if !can_tech {
- return false;
- }
- }
-
- match state {
- TechFlags::IN_PLACE => {
- *status_kind = FIGHTER_STATUS_KIND_PASSIVE_WALL.as_lua_int();
- *unk = LUA_TRUE;
- }
- TechFlags::ROLL_F => {
- *status_kind = FIGHTER_STATUS_KIND_PASSIVE_WALL_JUMP.as_lua_int();
- *unk = LUA_TRUE;
- }
- _ => (),
- }
-
- true
-}
-
-fn handle_ceil_tech(
- module_accessor: &mut app::BattleObjectModuleAccessor,
- status_kind: &mut L2CValue,
- unk: &mut L2CValue,
- status_kind_int: i32,
- state: TechFlags,
-) -> bool {
- if status_kind_int != *FIGHTER_STATUS_KIND_STOP_CEIL
- && status_kind_int != *FIGHTER_STATUS_KIND_DAMAGE_FLY_REFLECT_U
- {
- return false;
- }
-
- if state == TechFlags::NO_TECH {
- return false;
- }
-
- unsafe {
- let can_tech = WorkModule::is_enable_transition_term(
- module_accessor,
- *FIGHTER_STATUS_TRANSITION_TERM_ID_PASSIVE_CEIL,
- );
-
- if !can_tech {
- return false;
- }
- }
-
- *status_kind = FIGHTER_STATUS_KIND_PASSIVE_CEIL.as_lua_int();
- *unk = LUA_TRUE;
- true
-}
-
-pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccessor) {
- if !is_operation_cpu(module_accessor) {
- return;
- }
-
- if MENU.tech_state == TechFlags::empty() {
- return;
- }
-
- let status = StatusModule::status_kind(module_accessor) as i32;
-
- if [
- *FIGHTER_STATUS_KIND_DOWN_WAIT, // Mistech
- *FIGHTER_STATUS_KIND_DOWN_WAIT_CONTINUE, // Mistech
- *FIGHTER_STATUS_KIND_LAY_DOWN, // Snake down throw
- ]
- .contains(&status)
- {
- let status: i32 = match MENU.miss_tech_state.get_random() {
- MissTechFlags::GETUP => *FIGHTER_STATUS_KIND_DOWN_STAND,
- MissTechFlags::ATTACK => *FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK,
- MissTechFlags::ROLL_F => {
- MISS_TECH_ROLL_DIRECTION = Direction::IN; // = In
- *FIGHTER_STATUS_KIND_DOWN_STAND_FB
- }
- MissTechFlags::ROLL_B => {
- MISS_TECH_ROLL_DIRECTION = Direction::OUT; // = Away
- *FIGHTER_STATUS_KIND_DOWN_STAND_FB
- }
- _ => return,
- };
- StatusModule::change_status_request_from_script(module_accessor, status, false);
-
- mash::perform_defensive_option();
- } else if [
- // Handle slips (like Diddy banana)
- *FIGHTER_STATUS_KIND_SLIP_WAIT,
- ]
- .contains(&status)
- {
- let status: i32 = match MENU.miss_tech_state.get_random() {
- MissTechFlags::GETUP => *FIGHTER_STATUS_KIND_SLIP_STAND,
- MissTechFlags::ATTACK => *FIGHTER_STATUS_KIND_SLIP_STAND_ATTACK,
- MissTechFlags::ROLL_F => *FIGHTER_STATUS_KIND_SLIP_STAND_F,
- MissTechFlags::ROLL_B => *FIGHTER_STATUS_KIND_SLIP_STAND_B,
- _ => return,
- };
- StatusModule::change_status_request_from_script(module_accessor, status, false);
-
- mash::perform_defensive_option();
- };
-}
-
-pub unsafe fn change_motion(
- module_accessor: &mut app::BattleObjectModuleAccessor,
- motion_kind: u64,
-) -> Option {
- if !is_operation_cpu(module_accessor) {
- return None;
- }
-
- if MENU.tech_state == TechFlags::empty() {
- return None;
- }
-
- if [hash40("passive_stand_f"), hash40("passive_stand_b")].contains(&motion_kind) {
- if TECH_ROLL_DIRECTION == Direction::IN {
- return Some(hash40("passive_stand_f"));
- } else {
- return Some(hash40("passive_stand_b"));
- }
- } else if [hash40("down_forward_u"), hash40("down_back_u")].contains(&motion_kind) {
- if MISS_TECH_ROLL_DIRECTION == Direction::IN {
- return Some(hash40("down_forward_u"));
- } else {
- return Some(hash40("down_back_u"));
- }
- } else if [hash40("down_forward_d"), hash40("down_back_d")].contains(&motion_kind) {
- if MISS_TECH_ROLL_DIRECTION == Direction::IN {
- return Some(hash40("down_forward_d"));
- } else {
- return Some(hash40("down_back_d"));
- }
- }
-
- None
-}
+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;
+use smash::lib::lua_const::*;
+use smash::lib::L2CValue;
+use smash::lua2cpp::L2CFighterBase;
+
+static mut TECH_ROLL_DIRECTION: Direction = Direction::empty();
+static mut MISS_TECH_ROLL_DIRECTION: Direction = Direction::empty();
+
+#[skyline::hook(replace = smash::lua2cpp::L2CFighterBase_change_status)]
+pub unsafe fn handle_change_status(
+ fighter: &mut L2CFighterBase,
+ status_kind: L2CValue,
+ unk: L2CValue,
+) -> L2CValue {
+ let mut status_kind = status_kind;
+ let mut unk = unk;
+
+ if is_training_mode() {
+ mod_handle_change_status(fighter, &mut status_kind, &mut unk);
+ }
+
+ original!()(fighter, status_kind, unk)
+}
+
+unsafe fn mod_handle_change_status(
+ fighter: &mut L2CFighterBase,
+ status_kind: &mut L2CValue,
+ unk: &mut L2CValue,
+) {
+ let module_accessor = sv_system::battle_object_module_accessor(fighter.lua_state_agent);
+ if !is_operation_cpu(module_accessor) {
+ return;
+ }
+
+ let status_kind_int = status_kind
+ .try_get_int()
+ .unwrap_or(*FIGHTER_STATUS_KIND_WAIT as u64) as i32;
+
+ let state: TechFlags = MENU.tech_state.get_random();
+
+ if handle_grnd_tech(module_accessor, status_kind, unk, status_kind_int, state) {
+ return;
+ }
+
+ if handle_wall_tech(module_accessor, status_kind, unk, status_kind_int, state) {
+ return;
+ }
+
+ handle_ceil_tech(module_accessor, status_kind, unk, status_kind_int, state);
+}
+
+unsafe fn handle_grnd_tech(
+ module_accessor: &mut app::BattleObjectModuleAccessor,
+ status_kind: &mut L2CValue,
+ unk: &mut L2CValue,
+ status_kind_int: i32,
+ state: TechFlags,
+) -> bool {
+ if status_kind_int != *FIGHTER_STATUS_KIND_DOWN
+ && status_kind_int != *FIGHTER_STATUS_KIND_DAMAGE_FLY_REFLECT_D
+ {
+ return false;
+ }
+
+ // prev_status_kind(module_accessor, 0) gets the 1st previous status,
+ // which is FIGHTER_STATUS_KIND_CATCHED_AIR_END_GANON for both aerial/grounded sideb
+ // prev_status_kind(module_accessor, 1) gets the 2nd previous status,
+ // which is FIGHTER_STATUS_KIND_CATCHED_GANON for grounded sideb
+ // and FIGHTER_STATUS_KIND_CATCHED_AIR_GANON for aerial sideb
+ let second_prev_status = StatusModule::prev_status_kind(module_accessor, 1);
+ let can_tech = WorkModule::is_enable_transition_term(
+ module_accessor,
+ *FIGHTER_STATUS_TRANSITION_TERM_ID_PASSIVE,
+ ) && (second_prev_status != FIGHTER_STATUS_KIND_CATCHED_AIR_FALL_GANON);
+
+ if !can_tech {
+ return false;
+ }
+
+ let do_tech: bool = match state {
+ TechFlags::IN_PLACE => {
+ *status_kind = FIGHTER_STATUS_KIND_PASSIVE.as_lua_int();
+ *unk = LUA_TRUE;
+ true
+ }
+ TechFlags::ROLL_F => {
+ *status_kind = FIGHTER_STATUS_KIND_PASSIVE_FB.as_lua_int();
+ *unk = LUA_TRUE;
+ TECH_ROLL_DIRECTION = Direction::IN; // = In
+ true
+ }
+ TechFlags::ROLL_B => {
+ *status_kind = FIGHTER_STATUS_KIND_PASSIVE_FB.as_lua_int();
+ *unk = LUA_TRUE;
+ TECH_ROLL_DIRECTION = Direction::OUT; // = Away
+ true
+ }
+ _ => false,
+ };
+ if do_tech && MENU.mash_triggers.contains(MashTrigger::TECH) {
+ mash::buffer_menu_mash();
+ }
+
+ true
+}
+
+unsafe fn handle_wall_tech(
+ module_accessor: &mut app::BattleObjectModuleAccessor,
+ status_kind: &mut L2CValue,
+ unk: &mut L2CValue,
+ status_kind_int: i32,
+ state: TechFlags,
+) -> bool {
+ let can_tech = WorkModule::is_enable_transition_term(
+ module_accessor,
+ *FIGHTER_STATUS_TRANSITION_TERM_ID_PASSIVE_WALL,
+ );
+
+ if ![
+ *FIGHTER_STATUS_KIND_STOP_WALL,
+ *FIGHTER_STATUS_KIND_DAMAGE_FLY_REFLECT_LR,
+ ]
+ .contains(&status_kind_int)
+ || state == TechFlags::NO_TECH
+ || !can_tech
+ {
+ return false;
+ }
+
+ let do_tech: bool = match state {
+ TechFlags::IN_PLACE => {
+ *status_kind = FIGHTER_STATUS_KIND_PASSIVE_WALL.as_lua_int();
+ *unk = LUA_TRUE;
+ true
+ }
+ TechFlags::ROLL_F => {
+ *status_kind = FIGHTER_STATUS_KIND_PASSIVE_WALL_JUMP.as_lua_int();
+ *unk = LUA_TRUE;
+ true
+ }
+ _ => false,
+ };
+ if do_tech && MENU.mash_triggers.contains(MashTrigger::TECH) {
+ mash::buffer_menu_mash();
+ }
+ true
+}
+
+unsafe fn handle_ceil_tech(
+ module_accessor: &mut app::BattleObjectModuleAccessor,
+ status_kind: &mut L2CValue,
+ unk: &mut L2CValue,
+ status_kind_int: i32,
+ state: TechFlags,
+) -> bool {
+ let can_tech = WorkModule::is_enable_transition_term(
+ module_accessor,
+ *FIGHTER_STATUS_TRANSITION_TERM_ID_PASSIVE_CEIL,
+ );
+
+ if ![
+ *FIGHTER_STATUS_KIND_STOP_CEIL,
+ *FIGHTER_STATUS_KIND_DAMAGE_FLY_REFLECT_U,
+ ]
+ .contains(&status_kind_int)
+ || state == TechFlags::NO_TECH
+ || !can_tech
+ {
+ return false;
+ }
+
+ *status_kind = FIGHTER_STATUS_KIND_PASSIVE_CEIL.as_lua_int();
+ *unk = LUA_TRUE;
+ if MENU.mash_triggers.contains(MashTrigger::TECH) {
+ mash::buffer_menu_mash();
+ }
+ true
+}
+
+pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccessor) {
+ if !is_operation_cpu(module_accessor) || MENU.tech_state == TechFlags::empty() {
+ return;
+ }
+
+ let status = StatusModule::status_kind(module_accessor) as i32;
+
+ if [
+ *FIGHTER_STATUS_KIND_DOWN_WAIT, // Mistech
+ *FIGHTER_STATUS_KIND_DOWN_WAIT_CONTINUE, // Mistech
+ *FIGHTER_STATUS_KIND_LAY_DOWN, // Snake down throw
+ ]
+ .contains(&status)
+ {
+ let status: i32 = match MENU.miss_tech_state.get_random() {
+ MissTechFlags::GETUP => *FIGHTER_STATUS_KIND_DOWN_STAND,
+ MissTechFlags::ATTACK => *FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK,
+ MissTechFlags::ROLL_F => {
+ MISS_TECH_ROLL_DIRECTION = Direction::IN; // = In
+ *FIGHTER_STATUS_KIND_DOWN_STAND_FB
+ }
+ MissTechFlags::ROLL_B => {
+ MISS_TECH_ROLL_DIRECTION = Direction::OUT; // = Away
+ *FIGHTER_STATUS_KIND_DOWN_STAND_FB
+ }
+ _ => return,
+ };
+ StatusModule::change_status_request_from_script(module_accessor, status, false);
+ if MENU.mash_triggers.contains(MashTrigger::MISTECH) {
+ mash::buffer_menu_mash();
+ }
+ } else if [
+ // Handle slips (like Diddy banana)
+ *FIGHTER_STATUS_KIND_SLIP_WAIT,
+ ]
+ .contains(&status)
+ {
+ let status: i32 = match MENU.miss_tech_state.get_random() {
+ MissTechFlags::GETUP => *FIGHTER_STATUS_KIND_SLIP_STAND,
+ MissTechFlags::ATTACK => *FIGHTER_STATUS_KIND_SLIP_STAND_ATTACK,
+ MissTechFlags::ROLL_F => *FIGHTER_STATUS_KIND_SLIP_STAND_F,
+ MissTechFlags::ROLL_B => *FIGHTER_STATUS_KIND_SLIP_STAND_B,
+ _ => return,
+ };
+ StatusModule::change_status_request_from_script(module_accessor, status, false);
+ if MENU.mash_triggers.contains(MashTrigger::MISTECH) {
+ mash::buffer_menu_mash();
+ }
+ };
+}
+
+pub unsafe fn change_motion(
+ module_accessor: &mut app::BattleObjectModuleAccessor,
+ motion_kind: u64,
+) -> Option {
+ if !is_operation_cpu(module_accessor) {
+ return None;
+ }
+
+ if MENU.tech_state == TechFlags::empty() {
+ return None;
+ }
+
+ if [hash40("passive_stand_f"), hash40("passive_stand_b")].contains(&motion_kind) {
+ if TECH_ROLL_DIRECTION == Direction::IN {
+ return Some(hash40("passive_stand_f"));
+ } else {
+ return Some(hash40("passive_stand_b"));
+ }
+ } else if [hash40("down_forward_u"), hash40("down_back_u")].contains(&motion_kind) {
+ if MISS_TECH_ROLL_DIRECTION == Direction::IN {
+ return Some(hash40("down_forward_u"));
+ } else {
+ return Some(hash40("down_back_u"));
+ }
+ } else if [hash40("down_forward_d"), hash40("down_back_d")].contains(&motion_kind) {
+ if MISS_TECH_ROLL_DIRECTION == Direction::IN {
+ return Some(hash40("down_forward_d"));
+ } else {
+ return Some(hash40("down_back_d"));
+ }
+ }
+
+ None
+}
diff --git a/training_mod_consts/src/lib.rs b/training_mod_consts/src/lib.rs
index 5e46348..43fd9f1 100644
--- a/training_mod_consts/src/lib.rs
+++ b/training_mod_consts/src/lib.rs
@@ -1,3 +1,4 @@
+#![feature(const_option)]
#[macro_use]
extern crate bitflags;
@@ -13,9 +14,9 @@ use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
#[cfg(feature = "smash")]
use smash::lib::lua_const::*;
+use std::collections::HashMap;
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
-use std::collections::HashMap;
pub trait ToggleTrait {
fn to_toggle_strs() -> Vec<&'static str>;
@@ -326,33 +327,6 @@ impl ToggleTrait for SaveStateMirroring {
}
}
-// Defensive States
-bitflags! {
- pub struct Defensive : u32 {
- const SPOT_DODGE = 0x1;
- const ROLL_F = 0x2;
- const ROLL_B = 0x4;
- const JAB = 0x8;
- const SHIELD = 0x10;
- }
-}
-
-impl Defensive {
- fn as_str(self) -> Option<&'static str> {
- Some(match self {
- Defensive::SPOT_DODGE => "Spotdodge",
- Defensive::ROLL_F => "Roll Forwards",
- Defensive::ROLL_B => "Roll Backwards",
- Defensive::JAB => "Jab",
- Defensive::SHIELD => "Shield",
- _ => return None,
- })
- }
-}
-
-extra_bitflag_impls! {Defensive}
-impl_serde_for_bitflags!(Defensive);
-
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)]
pub enum OnOff {
@@ -971,49 +945,103 @@ impl ToggleTrait for CharacterItem {
}
}
-#[repr(C)]
-#[derive(Clone, Copy, Serialize, Deserialize, Debug, )]
-pub struct TrainingModpackMenu {
- pub hitbox_vis: OnOff,
- pub stage_hazards: OnOff,
- pub di_state: Direction,
- pub sdi_state: Direction,
- pub sdi_strength: InputFrequency,
- pub clatter_strength: InputFrequency,
- pub air_dodge_dir: Direction,
- pub mash_state: Action,
- pub follow_up: Action,
- pub attack_angle: AttackAngle,
- pub ledge_state: LedgeOption,
- pub ledge_delay: LongDelay,
- pub tech_state: TechFlags,
- pub miss_tech_state: MissTechFlags,
- pub shield_state: Shield,
- pub defensive_state: Defensive,
- pub oos_offset: Delay,
- pub reaction_time: Delay,
- pub shield_tilt: Direction,
- pub mash_in_neutral: OnOff,
- pub fast_fall: BoolFlag,
- pub fast_fall_delay: Delay,
- pub falling_aerials: BoolFlag,
- pub aerial_delay: Delay,
- pub full_hop: BoolFlag,
- pub crouch: OnOff,
- pub input_delay: i32,
- pub save_damage: OnOff,
- pub save_state_mirroring: SaveStateMirroring,
- pub frame_advantage: OnOff,
- pub save_state_enable: OnOff,
- pub save_state_autoload: OnOff,
- pub throw_state: ThrowOption,
- pub throw_delay: MedDelay,
- pub pummel_delay: MedDelay,
- pub buff_state: BuffOption,
- pub character_item: CharacterItem,
- pub quick_menu: OnOff,
+bitflags! {
+ pub struct MashTrigger : u32 {
+ const HIT = 0b0000_0000_0000_0000_0001;
+ const BLOCK = 0b0000_0000_0000_0000_0010;
+ const PARRY = 0b0000_0000_0000_0000_0100;
+ const TUMBLE = 0b0000_0000_0000_0000_1000;
+ const LANDING = 0b0000_0000_0000_0001_0000;
+ const TRUMP = 0b0000_0000_0000_0010_0000;
+ const FOOTSTOOL = 0b0000_0000_0000_0100_0000;
+ const CLATTER = 0b0000_0000_0000_1000_0000;
+ const LEDGE = 0b0000_0000_0001_0000_0000;
+ const TECH = 0b0000_0000_0010_0000_0000;
+ const MISTECH = 0b0000_0000_0100_0000_0000;
+ const GROUNDED = 0b0000_0000_1000_0000_0000;
+ const AIRBORNE = 0b0000_0001_0000_0000_0000;
+ const DISTANCE_CLOSE = 0b0000_0010_0000_0000_0000;
+ const DISTANCE_MID = 0b0000_0100_0000_0000_0000;
+ const DISTANCE_FAR = 0b0000_1000_0000_0000_0000;
+ const ALWAYS = 0b0001_0000_0000_0000_0000;
+ }
}
+impl MashTrigger {
+ pub fn as_str(self) -> Option<&'static str> {
+ Some(match self {
+ MashTrigger::HIT => "Hitstun",
+ MashTrigger::BLOCK => "Shieldstun",
+ MashTrigger::PARRY => "Parry",
+ MashTrigger::TUMBLE => "Tumble",
+ MashTrigger::LANDING => "Landing",
+ MashTrigger::TRUMP => "Ledge Trump",
+ MashTrigger::FOOTSTOOL => "Footstool",
+ MashTrigger::CLATTER => "Clatter",
+ MashTrigger::LEDGE => "Ledge Option",
+ MashTrigger::TECH => "Tech Option",
+ MashTrigger::MISTECH => "Mistech Option",
+ MashTrigger::GROUNDED => "Grounded",
+ MashTrigger::AIRBORNE => "Airborne",
+ MashTrigger::DISTANCE_CLOSE => "Distance: Close",
+ MashTrigger::DISTANCE_MID => "Distance: Mid",
+ MashTrigger::DISTANCE_FAR => "Distance: Far",
+ MashTrigger::ALWAYS => "Always",
+ _ => return None,
+ })
+ }
+
+ const fn default() -> MashTrigger {
+ // Hit, block, clatter
+ MashTrigger::HIT.union(MashTrigger::BLOCK).union(MashTrigger::CLATTER)
+ }
+}
+
+extra_bitflag_impls! {MashTrigger}
+impl_serde_for_bitflags!(MashTrigger);
+
+#[repr(C)]
+#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
+pub struct TrainingModpackMenu {
+ // Mash Tab
+ pub aerial_delay: Delay,
+ pub air_dodge_dir: Direction,
+ pub attack_angle: AttackAngle,
+ pub buff_state: BuffOption,
+ pub character_item: CharacterItem,
+ pub clatter_strength: InputFrequency,
+ pub crouch: OnOff,
+ pub di_state: Direction,
+ pub falling_aerials: BoolFlag,
+ pub fast_fall_delay: Delay,
+ pub fast_fall: BoolFlag,
+ pub follow_up: Action,
+ pub frame_advantage: OnOff,
+ pub full_hop: BoolFlag,
+ pub hitbox_vis: OnOff,
+ pub input_delay: i32,
+ pub ledge_delay: LongDelay,
+ pub ledge_state: LedgeOption,
+ pub mash_state: Action,
+ pub mash_triggers: MashTrigger,
+ pub miss_tech_state: MissTechFlags,
+ pub oos_offset: Delay,
+ pub pummel_delay: MedDelay,
+ pub quick_menu: OnOff,
+ pub reaction_time: Delay,
+ pub save_damage: OnOff,
+ pub save_state_autoload: OnOff,
+ pub save_state_enable: OnOff,
+ pub save_state_mirroring: SaveStateMirroring,
+ pub sdi_state: Direction,
+ pub sdi_strength: InputFrequency,
+ pub shield_state: Shield,
+ pub shield_tilt: Direction,
+ pub stage_hazards: OnOff,
+ pub tech_state: TechFlags,
+ pub throw_delay: MedDelay,
+ pub throw_state: ThrowOption,
+}
macro_rules! set_by_str {
($obj:ident, $s:ident, $($field:ident = $rhs:expr,)*) => {
@@ -1047,7 +1075,6 @@ impl TrainingModpackMenu {
attack_angle = AttackAngle::from_bits(val),
clatter_strength = num::FromPrimitive::from_u32(val),
crouch = OnOff::from_val(val),
- defensive_state = Defensive::from_bits(val),
di_state = Direction::from_bits(val),
falling_aerials = BoolFlag::from_bits(val),
fast_fall_delay = Delay::from_bits(val),
@@ -1058,8 +1085,8 @@ impl TrainingModpackMenu {
input_delay = Some(log_2(val) as i32),
ledge_delay = LongDelay::from_bits(val),
ledge_state = LedgeOption::from_bits(val),
- mash_in_neutral = OnOff::from_val(val),
mash_state = Action::from_bits(val),
+ mash_triggers = MashTrigger::from_bits(val),
miss_tech_state = MissTechFlags::from_bits(val),
oos_offset = Delay::from_bits(val),
reaction_time = Delay::from_bits(val),
@@ -1089,7 +1116,7 @@ impl TrainingModpackMenu {
pub struct MenuJsonStruct {
pub menu: TrainingModpackMenu,
pub defaults_menu: TrainingModpackMenu,
- // pub last_focused_submenu: &str
+ // pub last_focused_submenu: &str
}
// Fighter Ids
@@ -1117,44 +1144,43 @@ impl SubMenuType {
}
pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu {
- hitbox_vis: OnOff::On,
- stage_hazards: OnOff::Off,
- di_state: Direction::empty(),
- sdi_state: Direction::empty(),
- sdi_strength: InputFrequency::None,
- clatter_strength: InputFrequency::None,
- air_dodge_dir: Direction::empty(),
- mash_state: Action::empty(),
- follow_up: Action::empty(),
- attack_angle: AttackAngle::empty(),
- ledge_state: LedgeOption::all(),
- ledge_delay: LongDelay::empty(),
- tech_state: TechFlags::all(),
- miss_tech_state: MissTechFlags::all(),
- shield_state: Shield::None,
- defensive_state: Defensive::all(),
- oos_offset: Delay::empty(),
- shield_tilt: Direction::empty(),
- reaction_time: Delay::empty(),
- mash_in_neutral: OnOff::Off,
- fast_fall: BoolFlag::empty(),
- fast_fall_delay: Delay::empty(),
- falling_aerials: BoolFlag::empty(),
aerial_delay: Delay::empty(),
- full_hop: BoolFlag::empty(),
- crouch: OnOff::Off,
- input_delay: 0,
- save_damage: OnOff::On,
- save_state_mirroring: SaveStateMirroring::None,
- frame_advantage: OnOff::Off,
- save_state_enable: OnOff::On,
- save_state_autoload: OnOff::Off,
- throw_state: ThrowOption::NONE,
- throw_delay: MedDelay::empty(),
- pummel_delay: MedDelay::empty(),
+ air_dodge_dir: Direction::empty(),
+ attack_angle: AttackAngle::empty(),
buff_state: BuffOption::empty(),
character_item: CharacterItem::None,
+ clatter_strength: InputFrequency::None,
+ crouch: OnOff::Off,
+ di_state: Direction::empty(),
+ falling_aerials: BoolFlag::empty(),
+ fast_fall_delay: Delay::empty(),
+ fast_fall: BoolFlag::empty(),
+ follow_up: Action::empty(),
+ frame_advantage: OnOff::Off,
+ full_hop: BoolFlag::empty(),
+ hitbox_vis: OnOff::On,
+ input_delay: 0,
+ ledge_delay: LongDelay::empty(),
+ ledge_state: LedgeOption::all(),
+ mash_state: Action::empty(),
+ mash_triggers: MashTrigger::default(),
+ miss_tech_state: MissTechFlags::all(),
+ oos_offset: Delay::empty(),
+ pummel_delay: MedDelay::empty(),
quick_menu: OnOff::Off,
+ reaction_time: Delay::empty(),
+ save_damage: OnOff::On,
+ save_state_autoload: OnOff::Off,
+ save_state_enable: OnOff::On,
+ save_state_mirroring: SaveStateMirroring::None,
+ sdi_state: Direction::empty(),
+ sdi_strength: InputFrequency::None,
+ shield_state: Shield::None,
+ shield_tilt: Direction::empty(),
+ stage_hazards: OnOff::Off,
+ tech_state: TechFlags::all(),
+ throw_delay: MedDelay::empty(),
+ throw_state: ThrowOption::NONE,
};
pub static mut MENU: TrainingModpackMenu = DEFAULTS_MENU;
@@ -1265,6 +1291,12 @@ pub unsafe fn get_menu() -> UiMenu<'static> {
"Followup Toggles: Actions to be performed after the Mash option",
false,
);
+ mash_tab.add_submenu_with_toggles::(
+ "Mash Triggers",
+ "mash_triggers",
+ "Mash triggers: When the Mash Option will be performed",
+ false,
+ );
mash_tab.add_submenu_with_toggles::(
"Attack Angle",
"attack_angle",
@@ -1331,12 +1363,6 @@ pub unsafe fn get_menu() -> UiMenu<'static> {
"Reaction Time: How many frames to delay before performing a mash option",
false,
);
- mash_tab.add_submenu_with_toggles::(
- "Mash in Neutral",
- "mash_in_neutral",
- "Mash In Neutral: Should Mash options be performed repeatedly or only when the CPU is hit",
- true,
- );
overall_menu.tabs.push(mash_tab);
let mut defensive_tab = Tab {
@@ -1410,12 +1436,6 @@ pub unsafe fn get_menu() -> UiMenu<'static> {
"Shield Tilt: Direction to tilt the shield",
false, // TODO: Should this be true?
);
- defensive_tab.add_submenu_with_toggles::(
- "Escape Toggles",
- "defensive_state",
- "Escape Options: Actions to take after a ledge option, tech option, or mistech option",
- false,
- );
defensive_tab.add_submenu_with_toggles::(
"Buff Options",
"buff_state",
@@ -1497,7 +1517,8 @@ pub unsafe fn get_menu() -> UiMenu<'static> {
);
overall_menu.tabs.push(misc_tab);
- let non_ui_menu = serde_json::to_string(&MENU).unwrap()
+ let non_ui_menu = serde_json::to_string(&MENU)
+ .unwrap()
.replace("\"", "")
.replace("{", "")
.replace("}", "");