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

Mash Overrides (#533)

* Merge from CookieScythe branch

* Rename block to shieldstun, add icons to layout.arc, add new options to ui_menu

* Address clippy warnings and reformat

* Add fn_null_check back to whitelist

* Pray to clippy gods
This commit is contained in:
asimon-1 2023-07-12 11:36:32 -07:00 committed by GitHub
parent e0ef313297
commit 7eec409086
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 322 additions and 60 deletions

View file

@ -116,12 +116,20 @@ pub fn is_in_shieldstun(module_accessor: &mut app::BattleObjectModuleAccessor) -
let status_kind = unsafe { StatusModule::status_kind(module_accessor) };
let prev_status = unsafe { StatusModule::prev_status_kind(module_accessor, 0) };
// If we are taking shield damage or we are droping shield from taking shield damage we are in hitstun
// If we are taking shield damage or we are dropping shield from taking shield damage we are in hitstun
// check if we're in first frames of guard off; don't try to mash in parryable frames - is this a problem for jump/grab OoS?
status_kind == FIGHTER_STATUS_KIND_GUARD_DAMAGE
|| (prev_status == FIGHTER_STATUS_KIND_GUARD_DAMAGE
&& status_kind == FIGHTER_STATUS_KIND_GUARD_OFF)
}
pub unsafe fn is_in_tech(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
let status_kind = StatusModule::status_kind(module_accessor);
(*FIGHTER_STATUS_KIND_DOWN_STAND..=*FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK)
.contains(&status_kind)
|| (*FIGHTER_STATUS_KIND_PASSIVE..=*FIGHTER_STATUS_KIND_PASSIVE_CEIL).contains(&status_kind)
}
pub unsafe fn is_ptrainer(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
[
*FIGHTER_KIND_PZENIGAME,
@ -216,7 +224,8 @@ pub unsafe fn is_in_tumble(module_accessor: &mut app::BattleObjectModuleAccessor
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)
(*FIGHTER_STATUS_KIND_LANDING..=*FIGHTER_STATUS_KIND_LANDING_DAMAGE_LIGHT)
.contains(&status_kind)
}
// Returns true if a match is currently active
@ -225,7 +234,6 @@ pub unsafe fn is_ready_go() -> bool {
FighterManager::is_ready_go(fighter_manager)
}
// Returns true if a match is currently active
pub unsafe fn entry_count() -> i32 {
let fighter_manager = *(FIGHTER_MANAGER_ADDR as *mut *mut app::FighterManager);
FighterManager::entry_count(fighter_manager)

View file

@ -22,7 +22,7 @@ fn is_current_version(fpath: &str) -> VersionCheck {
return VersionCheck::NoFile;
}
if fs::read_to_string(fpath).unwrap_or("".to_string()) == CURRENT_VERSION {
if fs::read_to_string(fpath).unwrap_or_else(|_| "".to_string()) == CURRENT_VERSION {
VersionCheck::Current
} else {
VersionCheck::Update

View file

@ -75,11 +75,7 @@ pub unsafe fn generate_hitbox_effects(
let dist_sq: f32 = x_dist * x_dist + y_dist * y_dist + z_dist * z_dist;
let dist = dist_sq.sqrt();
n_effects = ((dist / (size * 1.75)) + 1.0).ceil() as i32; // just enough effects to form a continuous line
if n_effects < 2 {
n_effects = 2;
} else if n_effects > MAX_EFFECTS_PER_HITBOX {
n_effects = MAX_EFFECTS_PER_HITBOX;
}
n_effects = n_effects.clamp(2, MAX_EFFECTS_PER_HITBOX);
} else {
x_dist = 0.0;
y_dist = 0.0;

View file

@ -9,7 +9,7 @@
clippy::missing_safety_doc,
clippy::wrong_self_convention,
clippy::option_map_unit_fn,
clippy::fn_null_check,
clippy::incorrect_fn_null_checks,
clippy::transmute_num_to_bytes
)]

Binary file not shown.

View file

@ -3,7 +3,7 @@ use smash::app::{self};
use crate::common::consts::*;
use crate::common::*;
static mut DIRECTION: AttackAngle = AttackAngle::UP;
static mut DIRECTION: AttackAngle = AttackAngle::NEUTRAL;
pub fn roll_direction() {
unsafe {

View file

@ -5,10 +5,8 @@ use smash::phx::{Hash40, Vector3f};
use crate::common::consts::*;
use crate::common::*;
use crate::training::mash;
static mut COUNTER: u32 = 0;
static mut WAS_IN_CLATTER_FLAG: bool = false;
static mut CLATTER_STEP: f32 = 8.0;
unsafe fn do_clatter_input(module_accessor: &mut BattleObjectModuleAccessor) {
@ -44,13 +42,9 @@ pub unsafe fn handle_clatter(module_accessor: &mut BattleObjectModuleAccessor) {
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;
// Don't do clatter inputs if we're not in clatter
return;
}
WAS_IN_CLATTER_FLAG = true;
let repeat = MENU.clatter_strength.into_u32();
COUNTER = (COUNTER + 1) % repeat;

View file

@ -102,7 +102,18 @@ pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor
StatusModule::change_status_request_from_script(module_accessor, status, true);
if MENU.mash_triggers.contains(MashTrigger::LEDGE) {
mash::buffer_menu_mash();
if LEDGE_CASE == LedgeOption::NEUTRAL && MENU.ledge_neutral_override != Action::empty() {
mash::external_buffer_menu_mash(MENU.ledge_neutral_override.get_random());
} else if LEDGE_CASE == LedgeOption::ROLL && MENU.ledge_roll_override != Action::empty() {
mash::external_buffer_menu_mash(MENU.ledge_roll_override.get_random());
} else if LEDGE_CASE == LedgeOption::JUMP && MENU.ledge_jump_override != Action::empty() {
mash::external_buffer_menu_mash(MENU.ledge_jump_override.get_random());
} else if LEDGE_CASE == LedgeOption::ATTACK && MENU.ledge_attack_override != Action::empty()
{
mash::external_buffer_menu_mash(MENU.ledge_attack_override.get_random());
} else {
mash::external_buffer_menu_mash(MENU.mash_state.get_random());
}
}
}

View file

@ -131,46 +131,127 @@ pub unsafe fn get_command_flag_cat(
}
unsafe fn check_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) {
if !QUEUE.is_empty() {
return;
// Different situations mean we want to change our buffered option, so we check what to buffer every frame
let buffered_action = get_buffered_action(module_accessor);
if let Some(action) = buffered_action {
full_reset();
// we need to clear the queue when adding a mash to the queue, but not necessarily a follow-up.
// We need to clear the queue since it'll be trying to buffer that action until it's completed, but now we want
// different things to happen.
buffer_menu_mash(action);
}
if !should_buffer(module_accessor) {
return;
}
buffer_menu_mash();
}
unsafe fn should_buffer(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
unsafe fn get_buffered_action(
module_accessor: &mut app::BattleObjectModuleAccessor,
) -> Option<Action> {
// TODO: refactor this so it is less repetitive. Maybe a macro is the right tool for this
if save_states::is_loading() {
return false;
return None;
}
let fighter_distance = get_fighter_distance();
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))
if is_in_tech(module_accessor) {
let action = MENU.tech_action_override.get_random();
if action != Action::empty() {
Some(action)
} else if MENU.mash_triggers.contains(MashTrigger::TECH) {
Some(MENU.mash_state.get_random())
} else {
None
}
} else if is_in_clatter(module_accessor) {
let action = MENU.clatter_override.get_random();
if action != Action::empty() {
Some(action)
} else if MENU.mash_triggers.contains(MashTrigger::CLATTER) {
Some(MENU.mash_state.get_random())
} else {
None
}
} else if is_in_tumble(module_accessor) {
// Note that the tumble check needs to come before hitstun,
// otherwise the hitstun check will always return first
let action = MENU.tumble_override.get_random();
if action != Action::empty() {
Some(action)
} else if MENU.mash_triggers.contains(MashTrigger::TUMBLE) {
Some(MENU.mash_state.get_random())
} else {
None
}
} else if is_in_hitstun(module_accessor) {
let action = MENU.hitstun_override.get_random();
if action != Action::empty() {
Some(action)
} else if MENU.mash_triggers.contains(MashTrigger::HIT) {
Some(MENU.mash_state.get_random())
} else {
None
}
} else if is_in_parry(module_accessor) {
let action = MENU.parry_override.get_random();
if action != Action::empty() {
Some(action)
} else if MENU.mash_triggers.contains(MashTrigger::PARRY) {
Some(MENU.mash_state.get_random())
} else {
None
}
} else if is_in_shieldstun(module_accessor) {
let action = MENU.shieldstun_override.get_random();
if action != Action::empty() {
Some(action)
} else if MENU.mash_triggers.contains(MashTrigger::SHIELDSTUN) {
Some(MENU.mash_state.get_random())
} else {
None
}
} else if is_in_footstool(module_accessor) {
let action = MENU.footstool_override.get_random();
if action != Action::empty() {
Some(action)
} else if MENU.mash_triggers.contains(MashTrigger::FOOTSTOOL) {
Some(MENU.mash_state.get_random())
} else {
None
}
} else if is_in_ledgetrump(module_accessor) {
let action = MENU.trump_override.get_random();
if action != Action::empty() {
Some(action)
} else if MENU.mash_triggers.contains(MashTrigger::TRUMP) {
Some(MENU.mash_state.get_random())
} else {
None
}
} else if is_in_landing(module_accessor) {
let action = MENU.landing_override.get_random();
if action != Action::empty() {
Some(action)
} else if MENU.mash_triggers.contains(MashTrigger::LANDING) {
Some(MENU.mash_state.get_random())
} else {
None
}
} else if (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)
|| (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)
|| MENU.mash_triggers.contains(MashTrigger::ALWAYS)
{
Some(MENU.mash_state.get_random())
} else {
// LEDGE handled in ledge.rs
None
}
}
// Temp Translation
pub fn buffer_menu_mash() {
fn buffer_menu_mash(action: Action) {
unsafe {
let action = MENU.mash_state.get_random();
buffer_action(action);
full_hop::roll_full_hop();
fast_fall::roll_fast_fall();
@ -178,6 +259,11 @@ pub fn buffer_menu_mash() {
}
}
pub fn external_buffer_menu_mash(action: Action) {
full_reset();
buffer_menu_mash(action);
}
unsafe fn perform_action(module_accessor: &mut app::BattleObjectModuleAccessor) -> i32 {
let action = get_current_buffer();
match action {

View file

@ -238,8 +238,12 @@ unsafe fn mod_handle_sub_guard_cont(fighter: &mut L2CFighterCommon) {
return;
}
if MENU.mash_triggers.contains(MashTrigger::BLOCK) {
mash::buffer_menu_mash();
if MENU.mash_triggers.contains(MashTrigger::SHIELDSTUN) {
if MENU.shieldstun_override == Action::empty() {
mash::external_buffer_menu_mash(MENU.mash_state.get_random())
} else {
mash::external_buffer_menu_mash(MENU.shieldstun_override.get_random())
}
}
let action = mash::get_current_buffer();
@ -341,7 +345,30 @@ fn needs_oos_handling_drop_shield() -> bool {
if action == Action::U_SMASH {
return true;
}
// Make sure we only flicker shield when Airdodge and Shield mash options are selected
if action == Action::AIR_DODGE {
let shield_state;
unsafe {
shield_state = &MENU.shield_state;
}
// If we're supposed to be holding shield, let airdodge make us drop shield
if [Shield::Hold, Shield::Infinite, Shield::Constant].contains(shield_state) {
suspend_shield(Action::AIR_DODGE);
}
return true;
}
if action == Action::SHIELD {
let shield_state;
unsafe {
shield_state = &MENU.shield_state;
}
// Don't drop shield on shield hit if we're supposed to be holding shield
if [Shield::Hold, Shield::Infinite, Shield::Constant].contains(shield_state) {
return false;
}
return true;
}
false
}

View file

@ -116,7 +116,11 @@ unsafe fn handle_grnd_tech(
_ => false,
};
if do_tech && MENU.mash_triggers.contains(MashTrigger::TECH) {
mash::buffer_menu_mash();
if MENU.tech_action_override == Action::empty() {
mash::external_buffer_menu_mash(MENU.mash_state.get_random())
} else {
mash::external_buffer_menu_mash(MENU.tech_action_override.get_random())
}
}
true
@ -159,7 +163,11 @@ unsafe fn handle_wall_tech(
_ => false,
};
if do_tech && MENU.mash_triggers.contains(MashTrigger::TECH) {
mash::buffer_menu_mash();
if MENU.tech_action_override == Action::empty() {
mash::external_buffer_menu_mash(MENU.mash_state.get_random())
} else {
mash::external_buffer_menu_mash(MENU.tech_action_override.get_random())
}
}
true
}
@ -190,7 +198,11 @@ unsafe fn handle_ceil_tech(
*status_kind = FIGHTER_STATUS_KIND_PASSIVE_CEIL.as_lua_int();
*unk = LUA_TRUE;
if MENU.mash_triggers.contains(MashTrigger::TECH) {
mash::buffer_menu_mash();
if MENU.tech_action_override == Action::empty() {
mash::external_buffer_menu_mash(MENU.mash_state.get_random())
} else {
mash::external_buffer_menu_mash(MENU.tech_action_override.get_random())
}
}
true
}
@ -258,7 +270,11 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces
if requested_status != 0 {
StatusModule::change_status_request_from_script(module_accessor, requested_status, false);
if MENU.mash_triggers.contains(MashTrigger::MISTECH) {
mash::buffer_menu_mash();
if MENU.tech_action_override == Action::empty() {
mash::external_buffer_menu_mash(MENU.mash_state.get_random())
} else {
mash::external_buffer_menu_mash(MENU.tech_action_override.get_random())
}
}
}
}

View file

@ -147,7 +147,7 @@ pub unsafe fn get_command_flag_throw_direction(
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_THROW_HI,
) {
let cmd = THROW_CASE.into_cmd().unwrap_or(0);
mash::buffer_menu_mash();
mash::external_buffer_menu_mash(MENU.mash_state.get_random());
return cmd;
}

View file

@ -38,7 +38,7 @@ pub unsafe fn parse_anim_transform(anim_transform: &mut AnimTransform, layout_na
as *const ResAnimationContent;
let name = skyline::try_from_c_str((*res_animation_cont).name.as_ptr())
.unwrap_or("UNKNOWN".to_string());
.unwrap_or_else(|_| "UNKNOWN".to_string());
let anim_type = (*res_animation_cont).anim_content_type;
// AnimContentType 1 == MATERIAL

View file

@ -59,6 +59,19 @@ pub struct TrainingModpackMenu {
pub tech_state: TechFlags,
pub throw_delay: MedDelay,
pub throw_state: ThrowOption,
pub ledge_neutral_override: Action,
pub ledge_roll_override: Action,
pub ledge_jump_override: Action,
pub ledge_attack_override: Action,
pub tech_action_override: Action,
pub clatter_override: Action,
pub tumble_override: Action,
pub hitstun_override: Action,
pub parry_override: Action,
pub shieldstun_override: Action,
pub footstool_override: Action,
pub landing_override: Action,
pub trump_override: Action,
}
#[repr(C)]
@ -136,6 +149,19 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu {
tech_state: TechFlags::all(),
throw_delay: MedDelay::empty(),
throw_state: ThrowOption::NONE,
ledge_neutral_override: Action::empty(),
ledge_roll_override: Action::empty(),
ledge_jump_override: Action::empty(),
ledge_attack_override: Action::empty(),
tech_action_override: Action::empty(),
clatter_override: Action::empty(),
tumble_override: Action::empty(),
hitstun_override: Action::empty(),
parry_override: Action::empty(),
shieldstun_override: Action::empty(),
footstool_override: Action::empty(),
landing_override: Action::empty(),
trump_override: Action::empty(),
};
pub static mut MENU: TrainingModpackMenu = DEFAULTS_MENU;
@ -385,6 +411,104 @@ pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu<'static> {
);
overall_menu.tabs.push(mash_tab);
let mut override_tab = Tab {
tab_id: "override",
tab_title: "Override Settings",
tab_submenus: Vec::new(),
};
override_tab.add_submenu_with_toggles::<Action>(
"Ledge Neutral Getup",
"ledge_neutral_override",
"Neutral Getup Override: Mash Actions to be performed after a Neutral Getup from ledge",
false,
&(menu.ledge_neutral_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Ledge Roll",
"ledge_roll_override",
"Ledge Roll Override: Mash Actions to be performed after a Roll Getup from ledge",
false,
&(menu.ledge_roll_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Ledge Jump",
"ledge_jump_override",
"Ledge Jump Override: Mash Actions to be performed after a Jump Getup from ledge",
false,
&(menu.ledge_jump_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Ledge Attack",
"ledge_attack_override",
"Ledge Attack Override: Mash Actions to be performed after a Getup Attack from ledge",
false,
&(menu.ledge_attack_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Tech Action",
"tech_action_override",
"Tech Action Override: Mash Actions to be performed after any tech action",
false,
&(menu.tech_action_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Clatter",
"clatter_override",
"Clatter Override: Mash Actions to be performed after leaving a clatter situation (grab, bury, etc)",
false,
&(menu.clatter_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Tumble",
"tumble_override",
"Tumble Override: Mash Actions to be performed after exiting a tumble state",
false,
&(menu.tumble_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Hitstun",
"hitstun_override",
"Hitstun Override: Mash Actions to be performed after exiting a hitstun state",
false,
&(menu.hitstun_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Parry",
"parry_override",
"Parry Override: Mash Actions to be performed after a parry",
false,
&(menu.parry_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Shieldstun",
"shieldstun_override",
"Shieldstun Override: Mash Actions to be performed after exiting a shieldstun state",
false,
&(menu.shieldstun_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Footstool",
"footstool_override",
"Footstool Override: Mash Actions to be performed after exiting a footstool state",
false,
&(menu.footstool_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Landing",
"landing_override",
"Landing Override: Mash Actions to be performed after landing on the ground",
false,
&(menu.landing_override.bits()),
);
override_tab.add_submenu_with_toggles::<Action>(
"Ledge Trump",
"trump_override",
"Ledge Trump Override: Mash Actions to be performed after leaving a ledgetrump state",
false,
&(menu.trump_override.bits()),
);
overall_menu.tabs.push(override_tab);
let mut defensive_tab = Tab {
tab_id: "defensive",
tab_title: "Defensive Settings",

View file

@ -1014,7 +1014,7 @@ impl ToggleTrait for CharacterItem {
bitflags! {
pub struct MashTrigger : u32 {
const HIT = 0b0000_0000_0000_0000_0001;
const BLOCK = 0b0000_0000_0000_0000_0010;
const SHIELDSTUN = 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;
@ -1037,7 +1037,7 @@ impl MashTrigger {
pub fn as_str(self) -> Option<&'static str> {
Some(match self {
MashTrigger::HIT => "Hitstun",
MashTrigger::BLOCK => "Shieldstun",
MashTrigger::SHIELDSTUN => "Shieldstun",
MashTrigger::PARRY => "Parry",
MashTrigger::TUMBLE => "Tumble",
MashTrigger::LANDING => "Landing",
@ -1060,7 +1060,7 @@ impl MashTrigger {
pub const fn default() -> MashTrigger {
// Hit, block, clatter
MashTrigger::HIT
.union(MashTrigger::BLOCK)
.union(MashTrigger::SHIELDSTUN)
.union(MashTrigger::CLATTER)
}
}