mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-20 00:46:34 +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:
parent
7fa0e933e9
commit
d867616f4f
7 changed files with 655 additions and 70 deletions
579
src/training/character_specific/kirby.rs
Normal file
579
src/training/character_specific/kirby.rs
Normal 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,);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
) {
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue