1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2024-11-19 16:36:35 +00:00

Kirby Hat Charges (#619)

* Add reusable print_fighter_info()

* rustfmt

* Clippy

* starting charge

* Working Pikmin Save States, motion not working, order can be messed up by loading during an aerial, if you save too quickly you lose pikmin in the state

* often failing boid read

* notes

* Prevent Pikmin from being cleaned up by the regular cleanup process

* migration progress

* skyline-smash branch, more pikmin work

* Using buff to spawn pikmin, character specific file for cleanliness

* failed reordering attempt

* more failed ordering

* almost kind of works but out of order

* failed all, need to try individual hold and status change

* hard reorder crash

* battleobject not boma

* comment clarification

* messing around with printing

* printing, about to try to find where autonomy is being set

* solution found, going to hook backshield to find where autonomy is being set to true

* found where to hook, will start hooking

* switched to charge, issues with inline hook

* need to only have autonomy ignored on save state load

* distance and status controls (doesn't work perfectly)

* Christmas Miracle

* Working w/ Cleanup

* training mode check, improved owner check

* Debug for hooking, Working Implementation (No Transform, No Charge)

* Working for Aegis, PT having issues (LRA into state load works, but not regular state load)

* Working ptrainer hats

* fmt fmt fmt

* Working Samus Charge, debug

* Sheik, improved debug

* No Lucario, many broken

* Try to match main better

* Working Compile

* sun salutation debug

* disable debug assert while debug build is broken

* All charges working, copy ability tracking for save states broken, debug needs cleanup

* no copy state load not working

* Working build

* debug and formatting cleanup

* turn off hitbox vis for jugeeya
This commit is contained in:
GradualSyrup 2023-09-02 13:49:20 -05:00 committed by GitHub
parent 7fa0e933e9
commit d867616f4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 655 additions and 70 deletions

View file

@ -0,0 +1,579 @@
use crate::training::charge::ChargeState;
use crate::training::save_states;
use smash::app::{self, lua_bind::*, smashball::is_training_mode};
use smash::lib::lua_const::*;
use smash::phx::{Hash40, Vector3f};
#[repr(C)]
pub struct CopyModule {
_vtable: u64, // maybe, no clue
padding: [u8; 0x17390],
copied_fighter_kind: i32,
}
// Wait to set up copy ability variables until after CopyStart runs;
static KIRBY_OPFF_OFFSET: usize = 0xb971b0;
#[skyline::hook(offset = KIRBY_OPFF_OFFSET)]
pub unsafe fn handle_copy_start(param1: u64, kirby_fighter: *mut app::Fighter) -> u64 {
if !is_training_mode() || !save_states::is_loading() {
return original!()(param1, kirby_fighter);
}
// Need to check copy start before the function runs, since it will turn it off if it was on
let module_accessor = (*kirby_fighter).battle_object.module_accessor;
let on_copy_start = WorkModule::is_flag(module_accessor, 0x20000104); // *FIGHTER_KIRBY_INSTANCE_WORK_ID_FLAG_COPY_ON_START
// Run optional initial copy setup (it depends on fighter kind)
let ori = original!()(param1, kirby_fighter);
// Now try to set save state variables
if on_copy_start {
let copy_module =
WorkModule::get_int64(module_accessor, 0x10000106) as *const i64 as *const CopyModule; //*FIGHTER_KIRBY_INSTANCE_WORK_ID_INT_COPY_MODULE_ADDRESS
let opponent_fighter_kind = (*copy_module).copied_fighter_kind;
handle_kirby_hat_charge(
&mut *module_accessor,
opponent_fighter_kind,
save_states::get_charge_state(module_accessor),
);
save_states::end_copy_ability(module_accessor);
}
ori
}
pub unsafe fn is_kirby_hat_okay(
opponent_module_accessor: &mut app::BattleObjectModuleAccessor,
save_state_fighter_option: Option<i32>,
) -> Option<bool> {
let mut opponent_fighter_kind = app::utility::get_kind(opponent_module_accessor);
let save_state_fighter_kind = save_state_fighter_option?;
if opponent_fighter_kind == save_state_fighter_kind {
return Some(true);
}
// We have a fighter but they don't match - see if it's an accepted transformation
let trainer_kinds = [
*FIGHTER_KIND_PZENIGAME,
*FIGHTER_KIND_PFUSHIGISOU,
*FIGHTER_KIND_PLIZARDON,
-1, // Fighter Kind while switching pokemon
];
let element_kinds = [*FIGHTER_KIND_EFLAME, *FIGHTER_KIND_ELIGHT];
if opponent_fighter_kind == -1 {
let trainer_boid = LinkModule::get_parent_object_id(
opponent_module_accessor,
*FIGHTER_POKEMON_LINK_NO_PTRAINER,
) as u32;
if trainer_boid != *BATTLE_OBJECT_ID_INVALID as u32
&& app::sv_battle_object::is_active(trainer_boid)
{
opponent_fighter_kind = *FIGHTER_KIND_PZENIGAME; // ptrainer is in the match, so assume we have a ptrainer fighter
}
}
let both_trainer = trainer_kinds.contains(&opponent_fighter_kind)
&& trainer_kinds.contains(&save_state_fighter_kind);
let both_element = element_kinds.contains(&opponent_fighter_kind)
&& element_kinds.contains(&save_state_fighter_kind);
Some(both_trainer || both_element)
}
pub unsafe fn get_kirby_hat_charge(
module_accessor: &mut app::BattleObjectModuleAccessor,
opponent_fighter_kind: i32,
charge_state: ChargeState,
) -> ChargeState {
if opponent_fighter_kind == FIGHTER_KIND_SAMUS || opponent_fighter_kind == FIGHTER_KIND_SAMUSD {
let shot_charge = WorkModule::get_int(
module_accessor,
*FIGHTER_SAMUS_INSTANCE_WORK_ID_INT_SPECIAL_N_COUNT,
);
charge_state.int_x(shot_charge)
}
// Sheik Needles
else if opponent_fighter_kind == FIGHTER_KIND_SHEIK {
let my_charge = WorkModule::get_int(
module_accessor,
*FIGHTER_SHEIK_INSTANCE_WORK_ID_INT_NEEDLE_COUNT,
);
charge_state.int_x(my_charge)
}
// Mewtwo Shadowball
else if opponent_fighter_kind == FIGHTER_KIND_MEWTWO {
let my_charge = WorkModule::get_int(
module_accessor,
*FIGHTER_MEWTWO_INSTANCE_WORK_ID_INT_SHADOWBALL_CHARGE_FRAME,
);
let prev_frame = WorkModule::get_int(
module_accessor,
*FIGHTER_MEWTWO_INSTANCE_WORK_ID_INT_PREV_SHADOWBALL_CHARGE_FRAME,
);
let ball_had = WorkModule::is_flag(
module_accessor,
*FIGHTER_MEWTWO_INSTANCE_WORK_ID_FLAG_SHADOWBALL_HAD,
);
charge_state
.int_x(my_charge)
.int_y(prev_frame)
.has_charge(ball_had)
}
// Squirtle Water Gun
else if opponent_fighter_kind == FIGHTER_KIND_PZENIGAME {
let my_charge = WorkModule::get_int(
module_accessor,
*FIGHTER_PZENIGAME_INSTANCE_WORK_ID_INT_SPECIAL_N_CHARGE,
);
charge_state.int_x(my_charge)
}
// Olimar Pikmin
else if opponent_fighter_kind == FIGHTER_KIND_PIKMIN {
let pre_pikmin_variation = WorkModule::get_int(
module_accessor,
*FIGHTER_PIKMIN_INSTANCE_WORK_INT_PRE_PIKMIN_VARIATION,
);
let before_pre_pikmin_variation = WorkModule::get_int(
module_accessor,
*FIGHTER_PIKMIN_INSTANCE_WORK_INT_BEFORE_PRE_PIKMIN_VARIATION,
);
charge_state
.int_x(pre_pikmin_variation)
.int_y(before_pre_pikmin_variation)
}
// Lucario Aura Sphere
else if opponent_fighter_kind == FIGHTER_KIND_LUCARIO {
let my_charge = WorkModule::get_int(
module_accessor,
*FIGHTER_LUCARIO_INSTANCE_WORK_ID_INT_AURABALL_CHARGE_FRAME,
);
let prev_frame = WorkModule::get_int(
module_accessor,
*FIGHTER_LUCARIO_INSTANCE_WORK_ID_INT_PREV_AURABALL_CHARGE_FRAME,
);
let ball_had = WorkModule::is_flag(
module_accessor,
*FIGHTER_LUCARIO_INSTANCE_WORK_ID_FLAG_AURABALL_HAD,
);
charge_state
.int_x(my_charge)
.int_y(prev_frame)
.has_charge(ball_had)
}
// ROB Gyro/Laser/Fuel
else if opponent_fighter_kind == FIGHTER_KIND_ROBOT {
let laser_charge = WorkModule::get_float(
module_accessor,
*FIGHTER_ROBOT_INSTANCE_WORK_ID_FLOAT_BEAM_ENERGY_VALUE,
);
charge_state.float_x(laser_charge)
}
// Wii Fit Sun Salutation
else if opponent_fighter_kind == FIGHTER_KIND_WIIFIT {
let my_charge = WorkModule::get_float(
module_accessor,
*FIGHTER_WIIFIT_INSTANCE_WORK_ID_FLOAT_SPECIAL_N_CHARGE_LEVEL_RATIO,
);
charge_state.float_x(my_charge)
}
// Pac-Man Bonus Fruit
else if opponent_fighter_kind == FIGHTER_KIND_PACMAN {
let my_charge = WorkModule::get_int(
module_accessor,
*FIGHTER_PACMAN_INSTANCE_WORK_ID_INT_SPECIAL_N_CHARGE_RANK,
);
let fruit_have = WorkModule::is_flag(
module_accessor,
*FIGHTER_PACMAN_INSTANCE_WORK_ID_FLAG_SPECIAL_N_PULL_THROW,
);
charge_state.int_x(my_charge).has_charge(fruit_have)
}
// Robin Thunder Tome Spells
else if opponent_fighter_kind == FIGHTER_KIND_REFLET {
let my_charge = WorkModule::get_int(
module_accessor,
*FIGHTER_REFLET_INSTANCE_WORK_ID_INT_SPECIAL_N_THUNDER_KIND,
);
charge_state.int_x(my_charge)
}
// Hero (Ka)frizz(le)
else if opponent_fighter_kind == FIGHTER_KIND_BRAVE {
let my_charge = WorkModule::get_int(
module_accessor,
*FIGHTER_BRAVE_INSTANCE_WORK_ID_INT_SPECIAL_N_HOLD_FRAME,
);
charge_state.int_x(my_charge)
}
// No charge for this character's copy ability
else {
charge_state
}
}
pub unsafe fn handle_kirby_hat_charge(
module_accessor: &mut app::BattleObjectModuleAccessor,
opponent_fighter_kind: i32,
charge: ChargeState,
) {
// Samus/Dark Samus Charge Shot - 0 to 112
if opponent_fighter_kind == FIGHTER_KIND_SAMUS || opponent_fighter_kind == FIGHTER_KIND_SAMUSD {
charge.int_x.map(|shot_charge| {
WorkModule::set_int(
module_accessor,
shot_charge,
*FIGHTER_SAMUS_INSTANCE_WORK_ID_INT_SPECIAL_N_COUNT,
);
if shot_charge == 112 {
EffectModule::req_common(module_accessor, Hash40::new("charge_max"), 0.0);
let samus_cshot_hash = if opponent_fighter_kind == FIGHTER_KIND_SAMUS {
Hash40::new("samus_cshot_max")
} else {
Hash40::new("samusd_cshot_max")
};
let joint_hash = Hash40::new("handr");
let pos = Vector3f {
x: 0.0,
y: 0.0,
z: 0.0,
};
let rot = Vector3f {
x: 0.0,
y: 0.0,
z: 0.0,
};
let efh = EffectModule::req_follow(
module_accessor,
samus_cshot_hash,
joint_hash,
&pos,
&rot,
1.0,
false,
0,
0,
0,
0,
0,
false,
false,
);
WorkModule::set_int(
module_accessor,
efh as i32,
*FIGHTER_SAMUS_INSTANCE_WORK_ID_INT_EFH_CHARGE_MAX,
);
}
});
}
// Sheik Needles - 0 to 6
else if opponent_fighter_kind == FIGHTER_KIND_SHEIK {
charge.int_x.map(|needle_charge| {
WorkModule::set_int(
module_accessor,
needle_charge,
*FIGHTER_SHEIK_INSTANCE_WORK_ID_INT_NEEDLE_COUNT,
);
if needle_charge == 6 {
EffectModule::req_common(module_accessor, Hash40::new("charge_max"), 0.0);
}
});
}
// Mewtwo Shadowball - 0 to 120, Boolean
else if opponent_fighter_kind == FIGHTER_KIND_MEWTWO {
charge.int_x.map(|charge_frame| {
WorkModule::set_int(
module_accessor,
charge_frame,
*FIGHTER_MEWTWO_INSTANCE_WORK_ID_INT_SHADOWBALL_CHARGE_FRAME,
);
});
charge.int_y.map(|prev_frame| {
WorkModule::set_int(
module_accessor,
prev_frame,
*FIGHTER_MEWTWO_INSTANCE_WORK_ID_INT_PREV_SHADOWBALL_CHARGE_FRAME,
);
if prev_frame == 120 {
EffectModule::req_common(module_accessor, Hash40::new("charge_max"), 0.0);
let pos = Vector3f {
x: 0.0,
y: 0.0,
z: 0.0,
};
let rot = Vector3f {
x: 0.0,
y: 0.0,
z: 0.0,
};
let eff_hash = Hash40 { hash: 0x1ac6d446d8 };
let joint_hash_l = Hash40 { hash: 0x5e008fd84 };
let efh_l = EffectModule::req_follow(
module_accessor,
eff_hash,
joint_hash_l,
&pos,
&rot,
1.0,
false,
0,
0,
-1,
0,
0,
false,
false,
);
let joint_hash_r = Hash40 { hash: 0x51a07c0e7 };
let efh_r = EffectModule::req_follow(
module_accessor,
eff_hash,
joint_hash_r,
&pos,
&rot,
1.0,
false,
0,
0,
-1,
0,
0,
false,
false,
);
WorkModule::set_int(
module_accessor,
efh_l as i32,
*FIGHTER_MEWTWO_INSTANCE_WORK_ID_INT_EF_ID_SHADOWBALL_MAX_L,
);
WorkModule::set_int(
module_accessor,
efh_r as i32,
*FIGHTER_MEWTWO_INSTANCE_WORK_ID_INT_EF_ID_SHADOWBALL_MAX_R,
);
}
});
charge.has_charge.map(|has_shadowball| {
WorkModule::set_flag(
module_accessor,
has_shadowball,
*FIGHTER_MEWTWO_INSTANCE_WORK_ID_FLAG_SHADOWBALL_HAD,
);
});
}
// Squirtle Water Gun - 0 to 45
else if opponent_fighter_kind == FIGHTER_KIND_PZENIGAME {
charge.int_x.map(|water_charge| {
WorkModule::set_int(
module_accessor,
water_charge,
*FIGHTER_PZENIGAME_INSTANCE_WORK_ID_INT_SPECIAL_N_CHARGE,
);
if water_charge == 45 {
EffectModule::req_common(module_accessor, Hash40::new("charge_max"), 0.0);
}
});
}
// Olimar Pikmin - 0 to 4
else if opponent_fighter_kind == FIGHTER_KIND_PIKMIN {
charge.int_x.map(|pre| {
WorkModule::set_int(
module_accessor,
pre,
*FIGHTER_PIKMIN_INSTANCE_WORK_INT_PRE_PIKMIN_VARIATION,
);
});
charge.int_y.map(|before_pre| {
WorkModule::set_int(
module_accessor,
before_pre,
*FIGHTER_PIKMIN_INSTANCE_WORK_INT_BEFORE_PRE_PIKMIN_VARIATION,
);
});
}
// Lucario Aura Sphere - 0 to 90
else if opponent_fighter_kind == FIGHTER_KIND_LUCARIO {
charge.int_x.map(|charge_frame| {
WorkModule::set_int(
module_accessor,
charge_frame,
*FIGHTER_LUCARIO_INSTANCE_WORK_ID_INT_AURABALL_CHARGE_FRAME,
);
});
charge.int_y.map(|prev_frame| {
WorkModule::set_int(
module_accessor,
prev_frame,
*FIGHTER_LUCARIO_INSTANCE_WORK_ID_INT_PREV_AURABALL_CHARGE_FRAME,
);
if prev_frame == 90 {
EffectModule::req_common(module_accessor, Hash40::new("charge_max"), 0.0);
let pos = Vector3f {
x: 0.0,
y: 0.0,
z: 0.0,
};
let rot = Vector3f {
x: 0.0,
y: 0.0,
z: 0.0,
};
let eff_hash_l = Hash40 { hash: 0x164bf96ca1 };
let joint_hash_l = Hash40 { hash: 0x5e008fd84 };
let efh_l = EffectModule::req_follow(
module_accessor,
eff_hash_l,
joint_hash_l,
&pos,
&rot,
1.0,
false,
0,
0,
-1,
0,
0,
false,
false,
);
let eff_hash_r = Hash40 { hash: 0x16b1f651c2 };
let joint_hash_r = Hash40 { hash: 0x51a07c0e7 };
let efh_r = EffectModule::req_follow(
module_accessor,
eff_hash_r,
joint_hash_r,
&pos,
&rot,
1.0,
false,
0,
0,
-1,
0,
0,
false,
false,
);
WorkModule::set_int(
module_accessor,
efh_l as i32,
*FIGHTER_LUCARIO_INSTANCE_WORK_ID_INT_EF_ID_AURABALL_MAX_L,
);
WorkModule::set_int(
module_accessor,
efh_r as i32,
*FIGHTER_LUCARIO_INSTANCE_WORK_ID_INT_EF_ID_AURABALL_MAX_R,
);
}
});
charge.has_charge.map(|has_shadowball| {
WorkModule::set_flag(
module_accessor,
has_shadowball,
*FIGHTER_LUCARIO_INSTANCE_WORK_ID_FLAG_AURABALL_HAD,
);
});
}
// ROB Laser
else if opponent_fighter_kind == FIGHTER_KIND_ROBOT {
charge.float_x.map(|beam_energy| {
WorkModule::set_float(
module_accessor,
beam_energy,
*FIGHTER_ROBOT_INSTANCE_WORK_ID_FLOAT_BEAM_ENERGY_VALUE,
);
});
}
// Wii Fit Sun Salutation - 0 to 1
else if opponent_fighter_kind == FIGHTER_KIND_WIIFIT {
charge.float_x.map(|sun_ratio| {
WorkModule::set_float(
module_accessor,
sun_ratio,
*FIGHTER_WIIFIT_INSTANCE_WORK_ID_FLOAT_SPECIAL_N_CHARGE_LEVEL_RATIO,
)
});
}
// Pac-Man Bonus Fruit - 0 to 12
else if opponent_fighter_kind == FIGHTER_KIND_PACMAN {
let mut has_key = false;
charge.int_x.map(|charge_rank| {
WorkModule::set_int(
module_accessor,
charge_rank,
*FIGHTER_PACMAN_INSTANCE_WORK_ID_INT_SPECIAL_N_CHARGE_RANK,
);
if charge_rank == 12 {
EffectModule::req_common(module_accessor, Hash40::new("charge_max"), 0.0);
has_key = true;
}
});
charge.has_charge.map(|has_fruit| {
WorkModule::set_flag(
module_accessor,
has_fruit,
*FIGHTER_PACMAN_INSTANCE_WORK_ID_FLAG_SPECIAL_N_PULL_THROW,
);
if has_key {
WorkModule::set_flag(
module_accessor,
has_key,
*FIGHTER_PACMAN_INSTANCE_WORK_ID_FLAG_SPECIAL_N_MAX_HAVE_ITEM,
);
}
});
}
// Robin Thunder Tome Spells - 0 to 3
else if opponent_fighter_kind == FIGHTER_KIND_REFLET {
charge.int_x.map(|thunder_kind| {
WorkModule::set_int(
module_accessor,
thunder_kind,
*FIGHTER_REFLET_INSTANCE_WORK_ID_INT_SPECIAL_N_THUNDER_KIND,
);
if thunder_kind == 3 {
EffectModule::req_common(module_accessor, Hash40::new("charge_max"), 0.0);
let eff_hash = Hash40 { hash: 0x12db3e4172 };
let joint_hash = Hash40 { hash: 0x5eb263e0d };
let pos = Vector3f {
x: 0.0,
y: 0.0,
z: 0.0,
};
let rot = Vector3f {
x: 0.0,
y: 0.0,
z: 0.0,
};
EffectModule::req_follow(
module_accessor,
eff_hash,
joint_hash,
&pos,
&rot,
1.0,
false,
0,
0,
-1,
0,
0,
false,
false,
);
}
});
}
// Hero (Ka)frizz(le) - 0 to 81
else if opponent_fighter_kind == FIGHTER_KIND_BRAVE {
EffectModule::remove_common(module_accessor, Hash40::new("charge_max"));
WorkModule::off_flag(
module_accessor,
*FIGHTER_BRAVE_INSTANCE_WORK_ID_FLAG_SPECIAL_N_MAX_EFFECT,
);
charge.int_x.map(|frizz_charge| {
WorkModule::set_int(
module_accessor,
frizz_charge,
*FIGHTER_BRAVE_INSTANCE_WORK_ID_INT_SPECIAL_N_HOLD_FRAME,
);
});
}
}
pub fn init() {
skyline::install_hooks!(handle_copy_start,);
}

View file

@ -2,6 +2,7 @@ use smash::app::{self};
mod bowser;
pub mod items;
pub mod kirby;
pub mod pikmin;
pub mod ptrainer;
pub mod steve;

View file

@ -1,6 +1,6 @@
use crate::common::consts::FighterId;
use crate::common::get_module_accessor;
use crate::training::character_specific::pikmin;
use crate::training::character_specific::{kirby, pikmin};
use serde::{Deserialize, Serialize};
use smash::app::{self, lua_bind::*, ArticleOperationTarget, FighterFacial, FighterUtil};
use smash::lib::lua_const::*;
@ -28,27 +28,32 @@ pub struct ChargeState {
}
impl ChargeState {
fn int_x(mut self, int_x: i32) -> Self {
pub fn int_x(mut self, int_x: i32) -> Self {
self.int_x = Some(int_x);
self
}
fn int_y(mut self, int_y: i32) -> Self {
pub fn int_y(mut self, int_y: i32) -> Self {
self.int_y = Some(int_y);
self
}
fn float_x(mut self, float_x: f32) -> Self {
pub fn int_z(mut self, int_z: i32) -> Self {
self.int_z = Some(int_z);
self
}
pub fn float_x(mut self, float_x: f32) -> Self {
self.float_x = Some(float_x);
self
}
fn float_y(mut self, float_y: f32) -> Self {
pub fn float_y(mut self, float_y: f32) -> Self {
self.float_y = Some(float_y);
self
}
fn float_z(mut self, float_z: f32) -> Self {
pub fn float_z(mut self, float_z: f32) -> Self {
self.float_z = Some(float_z);
self
}
@ -65,7 +70,7 @@ impl ChargeState {
self
}
fn has_charge(mut self, has_charge: bool) -> Self {
pub fn has_charge(mut self, has_charge: bool) -> Self {
self.has_charge = Some(has_charge);
self
}
@ -108,7 +113,9 @@ pub unsafe fn get_charge(
module_accessor,
*FIGHTER_KIRBY_INSTANCE_WORK_ID_INT_COPY_CHARA,
);
charge_state.has_charge(hat_have).int_x(chara_kind)
let kirby_charge = charge_state.has_charge(hat_have).int_z(chara_kind);
// Get the charge of necessary abilities for kirby
kirby::get_kirby_hat_charge(module_accessor, chara_kind, kirby_charge)
}
// Sheik Needles
else if fighter_kind == FIGHTER_KIND_SHEIK {
@ -370,9 +377,10 @@ pub unsafe fn handle_charge(
};
// Only try to set up Copy Ability when the current opponent matches the type of fighter from the save state
let opponent_matches_fighter =
is_kirby_hat_okay(opponent_module_accessor, charge.int_x);
kirby::is_kirby_hat_okay(opponent_module_accessor, charge.int_z);
if opponent_matches_fighter == Some(true) {
copy_setup(module_accessor, 1, charge.int_x.unwrap(), true, false);
copy_setup(module_accessor, 1, charge.int_z.unwrap(), true, false);
//kirby::handle_kirby_hat_charge(module_accessor, charge.int_z.unwrap(), charge);
}
});
}
@ -926,50 +934,3 @@ pub unsafe fn handle_charge(
});
}
}
unsafe fn is_kirby_hat_okay(
opponent_module_accessor: &mut app::BattleObjectModuleAccessor,
save_state_fighter_option: Option<i32>,
) -> Option<bool> {
let mut opponent_fighter_kind = app::utility::get_kind(opponent_module_accessor);
let save_state_fighter_kind = save_state_fighter_option?;
if opponent_fighter_kind == save_state_fighter_kind {
return Some(true);
}
// We have a fighter but they don't match - see if it's an accepted transformation
let trainer_kinds = [
*FIGHTER_KIND_PZENIGAME,
*FIGHTER_KIND_PFUSHIGISOU,
*FIGHTER_KIND_PLIZARDON,
-1, // Fighter Kind while switching pokemon
];
let element_kinds = [*FIGHTER_KIND_EFLAME, *FIGHTER_KIND_ELIGHT];
if opponent_fighter_kind == -1 {
let trainer_boid = LinkModule::get_parent_object_id(
opponent_module_accessor,
*FIGHTER_POKEMON_LINK_NO_PTRAINER,
) as u32;
if trainer_boid != *BATTLE_OBJECT_ID_INVALID as u32
&& app::sv_battle_object::is_active(trainer_boid)
{
opponent_fighter_kind = *FIGHTER_KIND_PZENIGAME; // ptrainer is in the match, so assume we have a ptrainer fighter
}
}
let both_trainer = trainer_kinds.contains(&opponent_fighter_kind)
&& trainer_kinds.contains(&save_state_fighter_kind);
let both_element = element_kinds.contains(&opponent_fighter_kind)
&& element_kinds.contains(&save_state_fighter_kind);
Some(both_trainer || both_element)
}
pub unsafe fn _get_kirby_hat_charge(
_module_accessor: &mut app::BattleObjectModuleAccessor,
_opponent_fighter_kind: i32,
) {
}
pub unsafe fn _handle_kirby_hat_charge(
_module_accessor: &mut app::BattleObjectModuleAccessor,
_opponent_fighter_kind: i32,
) {
}

View file

@ -54,6 +54,11 @@ pub unsafe fn handle_set_float(work_module: &mut WorkModule2, value: f32, addres
if !is_training_mode() {
original!()(work_module, value, address);
}
if address == *FIGHTER_WIIFIT_INSTANCE_WORK_ID_FLOAT_SPECIAL_N_CHARGE_LEVEL_RATIO //*FIGHTER_KIRBY_INSTANCE_WORK_ID_FLAG_COPY_ON_START
&& app::utility::get_kind(work_module.owner) == FIGHTER_KIND_KIRBY
{
is_visible_backshield(work_module.owner);
}
original!()(work_module, value, address);
}
@ -86,7 +91,7 @@ pub fn init() {
//handle_on_flag,
//handle_set_int,
// handle_set_int_64,
// handle_set_float,
handle_set_float,
// handle_get_int,
//handle_is_flag,
);

View file

@ -7,7 +7,7 @@ use crate::common::{
use crate::hitbox_visualizer;
use crate::input::*;
use crate::logging::*;
use crate::training::character_specific::{items, pikmin, ptrainer};
use crate::training::character_specific::{items, kirby, pikmin, ptrainer};
use skyline::hooks::{getRegionAddress, InlineCtx, Region};
use skyline::nn::ro::LookupSymbol;
use smash::app::{self, enSEType, lua_bind::*, utility};
@ -527,12 +527,17 @@ pub unsafe fn handle_fighter_play_se(
original!()(sound_module, my_hash, bool1, bool2, bool3, bool4, se_type)
}
pub struct FighterEffectModule {
_vtable: u64,
owner: *mut app::BattleObjectModuleAccessor,
}
static FOLLOW_REQ_OFFSET: usize = 0x044f860;
#[skyline::hook(offset = FOLLOW_REQ_OFFSET)] // hooked to prevent score gfx from playing when loading save states
pub unsafe fn handle_effect_follow(
effect_module: *mut FighterEffectModule,
effect_module: &mut FighterEffectModule,
eff_hash: Hash40,
eff_hash2: Hash40,
joint_hash: Hash40,
pos: *const Vector3f,
rot: *const Vector3f,
mut size: f32,
@ -549,7 +554,7 @@ pub unsafe fn handle_effect_follow(
return original!()(
effect_module,
eff_hash,
eff_hash2,
joint_hash,
pos,
rot,
size,
@ -570,7 +575,7 @@ pub unsafe fn handle_effect_follow(
original!()(
effect_module,
eff_hash,
eff_hash2,
joint_hash,
pos,
rot,
size,
@ -585,11 +590,6 @@ pub unsafe fn handle_effect_follow(
)
}
pub struct FighterEffectModule {
_table: u64,
owner: *mut app::BattleObjectModuleAccessor,
}
static EFFECT_REQ_OFFSET: usize = 0x44de50;
#[skyline::hook(offset = EFFECT_REQ_OFFSET)] // hooked to prevent death gfx from playing when loading save states
pub unsafe fn handle_fighter_effect(
@ -931,6 +931,7 @@ pub fn training_mods() {
ui::init();
pikmin::init();
ptrainer::init();
kirby::init();
#[cfg(debug_assertions)]
debug::init();

View file

@ -69,9 +69,10 @@ pub enum SaveState {
KillPlayer,
WaitForAlive,
PosMove,
NanaPosMove,
ApplyBuff,
NanaPosMove,
WaitForPokemonSwitch,
WaitForCopyAbility,
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
@ -191,6 +192,31 @@ pub unsafe fn get_state_pokemon(
(fighter_kind - *FIGHTER_KIND_PZENIGAME) as u32
}
pub unsafe fn get_charge_state(
module_accessor: *mut app::BattleObjectModuleAccessor,
) -> ChargeState {
let selected_slot = get_slot();
let cpu_module_accessor = get_module_accessor(FighterId::CPU);
if !ptr::eq(module_accessor, cpu_module_accessor) {
save_state_player(selected_slot).charge
} else {
save_state_cpu(selected_slot).charge
}
}
pub unsafe fn end_copy_ability(module_accessor: *mut app::BattleObjectModuleAccessor) {
let selected_slot = get_slot();
let cpu_module_accessor = get_module_accessor(FighterId::CPU);
let save_state = if !ptr::eq(module_accessor, cpu_module_accessor) {
save_state_player(selected_slot)
} else {
save_state_cpu(selected_slot)
};
if save_state.state == WaitForCopyAbility {
save_state.state = NoAction;
}
}
// MIRROR_STATE == 1 -> Do not mirror
// MIRROR_STATE == -1 -> Do Mirror
static mut MIRROR_STATE: f32 = 1.0;
@ -571,6 +597,10 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
// Set the charge of special moves if the fighter matches the kind in the save state
if save_state.fighter_kind == fighter_kind {
charge::handle_charge(module_accessor, fighter_kind, save_state.charge);
// If we ever want to buff kirby, we have to move this to after apply buff
if fighter_kind == FIGHTER_KIND_KIRBY {
save_state.state = WaitForCopyAbility;
}
}
// Buff the fighter if they're one of the fighters who can be buffed
if fighter_is_buffable {
@ -642,6 +672,14 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
save_state.state = NoAction;
}
// Wait for Copy Ability to be applied if needed, exit otherwise
if save_state.state == WaitForCopyAbility {
let is_copy_start = WorkModule::is_flag(module_accessor, 0x20000104); // *FIGHTER_KIRBY_INSTANCE_WORK_ID_FLAG_COPY_ON_START
if !is_copy_start {
save_state.state = NoAction;
}
}
// Save state
if button_config::combo_passes(button_config::ButtonCombo::SaveState) {
// Don't begin saving state if Nana's delayed input is captured

View file

@ -142,7 +142,7 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu {
follow_up: Action::empty(),
frame_advantage: OnOff::Off,
full_hop: BoolFlag::TRUE,
hitbox_vis: OnOff::On,
hitbox_vis: OnOff::Off,
input_display: InputDisplay::Smash,
input_display_status: OnOff::Off,
hud: OnOff::On,