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

Shulk Monado Art Buffs, SFX and Visual Buff Fixes (#564)

* Monado Buffs, Shulk Dial on Input Recording, Silent Buffs

* All Buffs Silent

* Shulk Flash removed, working on KO UI update

* Little Mac Meter Update

* Remove a few debug functions

* More cleanup

* merge with main

* Paren

* Paren

* rustfmt

* Clippy Fixes

* Fix further Shulk effect issues, improve buff functions
This commit is contained in:
GradualSyrup 2023-08-04 12:23:22 -05:00 committed by GitHub
parent c2f5bd5bb1
commit dcb1e831dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 777 additions and 582 deletions

View file

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

View file

@ -58,31 +58,18 @@ pub unsafe fn get_buff_rem(module_accessor: &mut app::BattleObjectModuleAccessor
BUFF_REMAINING_PLAYER
}
fn get_spell_vec() -> Vec<BuffOption> {
unsafe {
let menu_buff = MENU.buff_state.to_vec();
let menu_iter = menu_buff.iter();
let mut spell_buff: Vec<BuffOption> = Vec::new();
for buff in menu_iter {
if buff.into_int().unwrap_or(1) != 1 {
// all non-spells into_int as 1
spell_buff.push(*buff);
}
}
spell_buff
}
}
pub unsafe fn handle_buffs(
module_accessor: &mut app::BattleObjectModuleAccessor,
fighter_kind: i32,
status: i32,
percent: f32,
) -> bool {
// Future Enhancement - Remove startup effects on buffs (Flash of Limit, Wii Fit's flash, Shulk's occasional Jump Art smoke, etc.)
SoundModule::stop_all_sound(module_accessor); // silences buff sfx other than KO Punch
ControlModule::stop_rumble(module_accessor, false);
MotionAnimcmdModule::set_sleep(module_accessor, false);
CameraModule::stop_quake(module_accessor, *CAMERA_QUAKE_KIND_M); // stops Psyche-Up quake
CameraModule::stop_quake(module_accessor, *CAMERA_QUAKE_KIND_S); // stops Monado Art quake
let menu_vec = MENU.buff_state.to_vec();
@ -98,13 +85,14 @@ pub unsafe fn handle_buffs(
return buff_mac(module_accessor);
} else if fighter_kind == *FIGHTER_KIND_EDGE && menu_vec.contains(&BuffOption::WING) {
return buff_sepiroth(module_accessor, percent);
} else if fighter_kind == *FIGHTER_KIND_SHULK {
return buff_shulk(module_accessor, status);
}
true
}
unsafe fn buff_hero(module_accessor: &mut app::BattleObjectModuleAccessor, status: i32) -> bool {
let buff_vec = get_spell_vec();
let buff_vec = MENU.buff_state.hero_buffs().to_vec();
if !is_buffing(module_accessor) {
// Initial set up for spells
start_buff(module_accessor);
@ -113,6 +101,10 @@ unsafe fn buff_hero(module_accessor: &mut app::BattleObjectModuleAccessor, statu
}
if get_buff_rem(module_accessor) <= 0 {
// If there are no buffs selected/left, we're done
if frame_counter::should_delay(3_u32, BUFF_DELAY_COUNTER) {
// Need to wait 3 frames to make sure we stop the spell SFX, since it's a bit delayed
return false;
}
return true;
}
buff_hero_single(module_accessor, status, buff_vec);
@ -185,14 +177,19 @@ unsafe fn buff_joker(module_accessor: &mut app::BattleObjectModuleAccessor) -> b
}
unsafe fn buff_mac(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
WorkModule::set_float(
module_accessor,
100.0,
*FIGHTER_LITTLEMAC_INSTANCE_WORK_ID_FLOAT_KO_GAGE,
);
// Trying to stop KO Punch from playing seems to make it play multiple times in rapid succession
// Look at 0x7100c44b60 for the func that handles this
// Need to figure out how to update the KO meter if this is fixed
if !is_buffing(module_accessor) {
// Only need to set KO gauge once
start_buff(module_accessor);
WorkModule::set_float(
module_accessor,
100.0,
*FIGHTER_LITTLEMAC_INSTANCE_WORK_ID_FLOAT_KO_GAGE,
);
}
if frame_counter::should_delay(2_u32, BUFF_DELAY_COUNTER) {
// Need to wait 2 frames to make sure we stop the KO sound, since it's a bit delayed
return false;
}
true
}
@ -221,6 +218,47 @@ unsafe fn buff_sepiroth(
false
}
unsafe fn buff_shulk(module_accessor: &mut app::BattleObjectModuleAccessor, status: i32) -> bool {
let current_art = MENU.buff_state.shulk_buffs().get_random();
if current_art == BuffOption::empty() {
// No Monado Arts selected in the buff menu, so we don't need to buff
return true;
}
start_buff(module_accessor);
let prev_status_kind = StatusModule::prev_status_kind(module_accessor, 0);
if prev_status_kind == FIGHTER_SHULK_STATUS_KIND_SPECIAL_N_ACTION {
if frame_counter::should_delay(3_u32, BUFF_DELAY_COUNTER) {
// Need to continue to be buffing to make sure we stop "JUMP!" voice line
return false;
}
return true;
}
if status != FIGHTER_SHULK_STATUS_KIND_SPECIAL_N_ACTION {
WorkModule::set_int(
module_accessor,
current_art.into_int().unwrap(),
*FIGHTER_SHULK_INSTANCE_WORK_ID_INT_SPECIAL_N_TYPE_SELECT,
);
WorkModule::set_int(
module_accessor,
29,
*FIGHTER_SHULK_INSTANCE_WORK_ID_INT_SPECIAL_N_SELECT_TIMER,
);
WorkModule::on_flag(
module_accessor,
*FIGHTER_SHULK_INSTANCE_WORK_ID_FLAG_SPECIAL_N_SELECT,
);
StatusModule::change_status_force(
module_accessor,
*FIGHTER_SHULK_STATUS_KIND_SPECIAL_N_ACTION,
true,
);
} else {
MotionModule::set_rate(module_accessor, 40.0);
}
false
}
unsafe fn buff_wiifit(
module_accessor: &mut app::BattleObjectModuleAccessor,
status: i32,

File diff suppressed because it is too large Load diff

View file

@ -79,12 +79,11 @@ pub fn buffer_action(action: Action) {
&& !is_playback_queued()
&& action != Action::PLAYBACK
{
println!("Stopping mash playback for menu option!");
input_record::stop_playback();
}
// if we don't want to leave playback on mash actions, then don't perform the mash
if input_record::is_playback() {
return;
//println!("Stopping mash playback for menu option!");
// if we don't want to leave playback on mash actions, then don't perform the mash
if input_record::is_playback() {
return;
}
}
}

View file

@ -1,13 +1,14 @@
use skyline::hooks::{getRegionAddress, InlineCtx, Region};
use skyline::nn::hid::*;
use skyline::nn::ro::LookupSymbol;
use smash::app::{self, enSEType, lua_bind::*};
use smash::app::{self, enSEType, lua_bind::*, utility};
use smash::lib::lua_const::*;
use smash::params::*;
use smash::phx::{Hash40, Vector3f};
use crate::common::{
dev_config, is_training_mode, menu, FIGHTER_MANAGER_ADDR, ITEM_MANAGER_ADDR, STAGE_MANAGER_ADDR,
consts::BuffOption, consts::FighterId, consts::MENU, dev_config, get_module_accessor,
is_training_mode, menu, FIGHTER_MANAGER_ADDR, ITEM_MANAGER_ADDR, STAGE_MANAGER_ADDR,
};
use crate::hitbox_visualizer;
use crate::logging::*;
@ -119,6 +120,26 @@ fn once_per_frame_per_fighter(
return;
}
/*unsafe {
let fighter_kind = app::utility::get_kind(module_accessor);
if fighter_kind == *FIGHTER_KIND_LITTLEMAC {
let status = StatusModule::status_kind(module_accessor);
let gage_max_keep = WorkModule::get_int(module_accessor, *FIGHTER_LITTLEMAC_INSTANCE_WORK_ID_INT_KO_GAGE_MAX_KEEP_FRAME);
let select_timer = WorkModule::get_int(module_accessor, *FIGHTER_LITTLEMAC_INSTANCE_WORK_ID_INT_SPECIAL_N2_HIT_FRAME);
let max_effect_flag = WorkModule::is_flag(module_accessor, *FIGHTER_LITTLEMAC_INSTANCE_WORK_ID_FLAG_REQUEST_KO_GAUGE_MAX_EFFECT);
let mesh_flag = WorkModule::is_flag(module_accessor, *FIGHTER_LITTLEMAC_INSTANCE_WORK_ID_FLAG_DAMAGE_MESH);
let gage_max_keep = WorkModule::get_float(module_accessor, *FIGHTER_LITTLEMAC_INSTANCE_WORK_ID_INT_KO_GAGE_MAX_KEEP_FRAME);
let select_timer = WorkModule::get_float(module_accessor, *FIGHTER_LITTLEMAC_INSTANCE_WORK_ID_INT_SPECIAL_N2_HIT_FRAME);
// may need to check out his status flags and not just work insts
println!("Status: {:x}, Counter: {}, Select_Timer: {}, Decide_Interval_Frame: {}, SNType: {}, SNTypeSelect: {}, Sel_F: {}, Active_F: {}, SelButton: {}, Circ Menu: {}",
status, counter, select_timer, decide_interval_frame, special_n_type, special_n_type_select, select_flag, active_flag, select_button_push_flag, circle_menu_flag
);
}
}*/
unsafe {
if menu::menu_condition(module_accessor) {
menu::spawn_menu();
@ -453,6 +474,54 @@ pub unsafe fn handle_se(
)
}
static PLAY_SE_OFFSET: usize = 0x04cf6a0;
// fighters don't use the symbol and go straight through their vtable to this function
#[skyline::hook(offset = PLAY_SE_OFFSET)]
pub unsafe fn handle_fighter_play_se(
module_accessor: &mut app::BattleObjectModuleAccessor,
my_hash: Hash40,
bool1: bool,
bool2: bool,
bool3: bool,
bool4: bool,
se_type: enSEType,
) -> u64 {
if !is_training_mode() {
return original!()(
module_accessor,
my_hash,
bool1,
bool2,
bool3,
bool4,
se_type,
);
}
// Supress Buff Sound Effects while buffing
if buff::is_buffing(module_accessor) {
let silent_hash = Hash40::new("se_silent");
return original!()(
module_accessor,
silent_hash,
bool1,
bool2,
bool3,
bool4,
se_type,
);
}
original!()(
module_accessor,
my_hash,
bool1,
bool2,
bool3,
bool4,
se_type,
)
}
#[skyline::hook(replace = EffectModule::req)] // hooked to prevent death gfx from playing when loading save states
pub unsafe fn handle_effect(
module_accessor: &mut app::BattleObjectModuleAccessor,
@ -518,6 +587,34 @@ pub unsafe fn handle_star_ko(my_long_ptr: &mut u64) -> bool {
}
}
static REUSED_UI_OFFSET: usize = 0x068cd80;
// A function reused by many functions to update UI. Called to update at least Little Mac's meter.
#[skyline::hook(offset = REUSED_UI_OFFSET)]
pub unsafe fn handle_reused_ui(
fighter_data: *mut u32, // a pointer to length 4 data in the Fighter's FighterEntry in the FighterManager
mut param_2: u32, // In Little Mac's case, the meter value as an integer
) {
if !is_training_mode() {
original!()(fighter_data, param_2);
}
if save_states::is_loading() {
let player_module_accessor = &mut *get_module_accessor(FighterId::Player);
let cpu_module_accessor = &mut *get_module_accessor(FighterId::CPU);
let player_fighter_kind = utility::get_kind(player_module_accessor);
let cpu_fighter_kind = utility::get_kind(cpu_module_accessor);
// If Little Mac is in the game and we're buffing him, set the meter to 100
if (player_fighter_kind == *FIGHTER_KIND_LITTLEMAC
|| cpu_fighter_kind == *FIGHTER_KIND_LITTLEMAC)
&& MENU.buff_state.to_vec().contains(&BuffOption::KO)
{
param_2 = 100;
}
}
original!()(fighter_data, param_2)
}
#[allow(improper_ctypes)]
extern "C" {
fn add_nn_hid_hook(callback: fn(*mut NpadGcState, *const u32));
@ -528,12 +625,13 @@ pub fn training_mods() {
// Input Mods
unsafe {
if (add_nn_hid_hook as *const ()).is_null() {
if let Some(_f) = (add_nn_hid_hook as *const ()).as_ref() {
add_nn_hid_hook(input_delay::handle_get_npad_state);
add_nn_hid_hook(menu::handle_get_npad_state);
add_nn_hid_hook(dev_config::handle_get_npad_state);
} else {
panic!("The NN-HID hook plugin could not be found and is required to add NRO hooks. Make sure libnn_hid_hook.nro is installed.");
}
add_nn_hid_hook(input_delay::handle_get_npad_state);
add_nn_hid_hook(menu::handle_get_npad_state);
add_nn_hid_hook(dev_config::handle_get_npad_state);
}
unsafe {
@ -591,6 +689,7 @@ pub fn training_mods() {
// Buffs
handle_add_limit,
handle_check_doyle_summon_dispatch,
handle_reused_ui,
handle_req_screen,
// Stale Moves
stale_handle,
@ -603,6 +702,8 @@ pub fn training_mods() {
handle_star_ko,
// Clatter
clatter::hook_start_clatter,
// Buff SFX
handle_fighter_play_se,
);
combo::init();

View file

@ -224,6 +224,14 @@ pub unsafe fn get_param_int(
*FIGHTER_INSTANCE_WORK_ID_INT_HIT_STOP_IGNORE_JOSTLE_FRAME,
);
}
// Remove Shulk Monado Art Damage Effects
WorkModule::set_int(
module_accessor,
0,
*FIGHTER_INSTANCE_WORK_ID_INT_SHULK_MONAD_ARTS_DAMAGE_FLASH_FRAME,
);
EffectModule::remove_common(module_accessor, Hash40::new("monad_arts_damage_buster"));
EffectModule::remove_common(module_accessor, Hash40::new("monad_arts_damage_smash"));
return Some(1);
}
if param_hash == hash40("rebirth_move_frame") {
@ -389,6 +397,7 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
*FIGHTER_KIND_LITTLEMAC,
*FIGHTER_KIND_EDGE,
*FIGHTER_KIND_WIIFIT,
*FIGHTER_KIND_SHULK,
]
.contains(&fighter_kind);

View file

@ -588,6 +588,11 @@ bitflags! {
const LIMIT = 0x40;
const KO = 0x80;
const WING = 0x100;
const MONAD_JUMP = 0x200;
const MONAD_SPEED = 0x400;
const MONAD_SHIELD = 0x800;
const MONAD_BUSTER = 0x1000;
const MONAD_SMASH = 0x2000;
}
}
@ -605,6 +610,11 @@ impl BuffOption {
BuffOption::LIMIT => 1,
BuffOption::KO => 1,
BuffOption::WING => 1,
BuffOption::MONAD_JUMP => *FIGHTER_SHULK_MONAD_TYPE_JUMP,
BuffOption::MONAD_SPEED => *FIGHTER_SHULK_MONAD_TYPE_SPEED,
BuffOption::MONAD_SHIELD => *FIGHTER_SHULK_MONAD_TYPE_SHIELD,
BuffOption::MONAD_BUSTER => *FIGHTER_SHULK_MONAD_TYPE_BUSTER,
BuffOption::MONAD_SMASH => *FIGHTER_SHULK_MONAD_TYPE_SMASH,
_ => return None,
})
}
@ -624,9 +634,33 @@ impl BuffOption {
BuffOption::LIMIT => "Limit Break",
BuffOption::KO => "KO Punch",
BuffOption::WING => "1-Winged Angel",
BuffOption::MONAD_JUMP => "Jump",
BuffOption::MONAD_SPEED => "Speed",
BuffOption::MONAD_SHIELD => "Shield",
BuffOption::MONAD_BUSTER => "Buster",
BuffOption::MONAD_SMASH => "Smash",
_ => return None,
})
}
pub fn hero_buffs(self) -> BuffOption {
// Return a struct with only Hero's selected buffs
let hero_buffs_bitflags = BuffOption::ACCELERATLE
.union(BuffOption::OOMPH)
.union(BuffOption::BOUNCE)
.union(BuffOption::PSYCHE);
self.intersection(hero_buffs_bitflags)
}
pub fn shulk_buffs(self) -> BuffOption {
// Return a struct with only Shulk's selected arts
let shulk_buffs_bitflags = BuffOption::MONAD_JUMP
.union(BuffOption::MONAD_SPEED)
.union(BuffOption::MONAD_SHIELD)
.union(BuffOption::MONAD_BUSTER)
.union(BuffOption::MONAD_SMASH);
self.intersection(shulk_buffs_bitflags)
}
}
extra_bitflag_impls! {BuffOption}