1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2024-11-20 00:46:34 +00:00

Mash Triggers (#385)

* Create mash triggers; remove mash in neutral and escape options

* Add landing condition

* Make default more readable
This commit is contained in:
asimon-1 2022-10-06 12:15:36 -07:00 committed by GitHub
parent c868fac2c3
commit 945ef21f60
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 567 additions and 594 deletions

View file

@ -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

View file

@ -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
)
}

View file

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="80.0px"
height="80.0px"
viewBox="0 0 80.0 80.0"
version="1.1"
id="SVGRoot"
sodipodi:docname="defensive_state.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<defs
id="defs5503" />
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="56.066346"
inkscape:cy="47.542419"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="true"
inkscape:window-width="1431"
inkscape:window-height="1150"
inkscape:window-x="256"
inkscape:window-y="0"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid6073" />
</sodipodi:namedview>
<metadata
id="metadata5506">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:#000000;fill-opacity:1;stroke-width:0.0763833"
d="M 38.816057,74.605714 C 29.334444,69.285944 21.721463,62.501161 16.396726,54.625324 12.680655,49.128873 10.507915,43.664275 9.6966552,37.774178 L 9.523071,36.513858 V 23.912615 11.311371 l 3.47544,-1.042804 C 14.909999,9.6950232 19.344052,8.3583968 22.851952,7.2982802 26.359855,6.2381628 31.257932,4.7597146 33.73657,4.0128262 36.215206,3.2659437 38.650419,2.5310366 39.148153,2.3796957 L 40.053125,2.10453 41.401461,2.5189583 c 0.741584,0.2279389 2.396695,0.727831 3.678025,1.1108785 2.124241,0.6350325 5.125149,1.5406034 15.467614,4.6676201 1.974506,0.5969825 5.033656,1.5193815 6.798111,2.0497691 l 3.208097,0.964332 v 12.524769 c 0,13.750626 0.01825,13.133525 -0.466202,15.771048 -1.469368,7.999907 -6.208433,16.280925 -13.435554,23.47723 -4.554305,4.534886 -9.53794,8.25966 -15.480083,11.569834 -0.616013,0.343161 -1.1316,0.622041 -1.145748,0.619733 -0.01415,-0.0023 -0.558497,-0.303113 -1.209664,-0.668458 z M 40.017434,6.9455021 c -0.01151,-0.011503 -1.154442,0.3221589 -2.539835,0.7414927 -1.385394,0.4193395 -4.804667,1.4508031 -7.598385,2.2921444 -2.793719,0.8413418 -6.248152,1.8853668 -7.67652,2.3200618 -1.42837,0.434688 -3.765692,1.137541 -5.194065,1.56189 -1.428365,0.424355 -2.676426,0.80554 -2.77347,0.847086 l -0.17644,0.07553 0.0285,10.635925 c 0.03141,11.709218 0.01623,11.306873 0.521534,13.844017 0.545678,2.739906 1.330584,4.981114 2.782065,7.943865 1.742197,3.556168 4.084322,6.961065 7.14568,10.388121 1.12907,1.263951 3.935989,4.012837 5.240776,5.132427 2.870291,2.462894 5.713524,4.524858 9.000587,6.527393 L 40,70 40.019187,38.483223 c 0.01055,-17.33423 0.0098,-31.5262046 -0.0018,-31.5377209 z"
id="path6100" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -1,83 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="80.0px"
height="80.0px"
viewBox="0 0 80.0 80.0"
version="1.1"
id="SVGRoot"
sodipodi:docname="mash_in_neutral.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<defs
id="defs1437" />
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="7.9195959"
inkscape:cx="42.95834"
inkscape:cy="46.564903"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="true"
inkscape:window-width="1431"
inkscape:window-height="1150"
inkscape:window-x="128"
inkscape:window-y="0"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid2007" />
</sodipodi:namedview>
<metadata
id="metadata1440">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:round"
id="rect2014"
width="35"
height="25"
x="-28.25321"
y="20.259903"
transform="matrix(-0.87578413,0.48270296,0.48270296,0.87578413,0,0)" />
<path
style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 13.870784,6 40,65"
id="path2016" />
<rect
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:round"
id="rect2014-3"
width="35"
height="25"
x="41.69635"
y="-18.293955"
transform="rotate(28.862086)" />
<path
style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 66,6.000001 26,71"
id="path2016-0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="80.0px"
height="80.0px"
viewBox="0 0 80.0 80.0"
version="1.1"
id="SVGRoot"
sodipodi:docname="mash_triggers.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview12"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
showgrid="false"
inkscape:zoom="6.6556426"
inkscape:cx="36.735747"
inkscape:cy="23.664131"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="SVGRoot" />
<defs
id="defs1437" />
<metadata
id="metadata1440">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<path
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 30,20 H 70"
id="path1277" />
<path
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 30,40 H 70"
id="path1279" />
<path
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 30,60 H 70"
id="path1281" />
<path
style="fill:none;stroke:#000000;stroke-width:2.57788;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 10.288939,33.555304 H 23.178333 V 46.444697 H 10.288939 V 33.555304"
id="path1287" />
<path
style="fill:none;stroke:#000000;stroke-width:2.57788;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 10.288939,13.035213 H 23.178333 V 25.924606 H 10.288939 V 13.035213 L 23.178333,25.924606 V 13.035213 L 10.288939,25.924606"
id="path2007" />
<path
style="fill:none;stroke:#000000;stroke-width:2.57788;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 10.288939,53.4744 H 23.178333 V 66.363794 H 10.288939 V 53.4744 L 23.178333,66.363794 V 53.4744 L 10.288939,66.363794"
id="path2009" />
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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<Action> = 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);
}

View file

@ -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;

View file

@ -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) {

View file

@ -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<u64> {
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<u64> {
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
}

View file

@ -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::<MashTrigger>(
"Mash Triggers",
"mash_triggers",
"Mash triggers: When the Mash Option will be performed",
false,
);
mash_tab.add_submenu_with_toggles::<AttackAngle>(
"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::<OnOff>(
"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::<Defensive>(
"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::<BuffOption>(
"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("}", "");