mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2025-07-08 04:01:32 +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:
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;
|
mod bowser;
|
||||||
pub mod items;
|
pub mod items;
|
||||||
|
pub mod kirby;
|
||||||
pub mod pikmin;
|
pub mod pikmin;
|
||||||
pub mod ptrainer;
|
pub mod ptrainer;
|
||||||
pub mod steve;
|
pub mod steve;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::common::consts::FighterId;
|
use crate::common::consts::FighterId;
|
||||||
use crate::common::get_module_accessor;
|
use crate::common::get_module_accessor;
|
||||||
use crate::training::character_specific::pikmin;
|
use crate::training::character_specific::{kirby, pikmin};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smash::app::{self, lua_bind::*, ArticleOperationTarget, FighterFacial, FighterUtil};
|
use smash::app::{self, lua_bind::*, ArticleOperationTarget, FighterFacial, FighterUtil};
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
@ -28,27 +28,32 @@ pub struct ChargeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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.int_x = Some(int_x);
|
||||||
self
|
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.int_y = Some(int_y);
|
||||||
self
|
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.float_x = Some(float_x);
|
||||||
self
|
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.float_y = Some(float_y);
|
||||||
self
|
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.float_z = Some(float_z);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -65,7 +70,7 @@ impl ChargeState {
|
|||||||
self
|
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.has_charge = Some(has_charge);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -108,7 +113,9 @@ pub unsafe fn get_charge(
|
|||||||
module_accessor,
|
module_accessor,
|
||||||
*FIGHTER_KIRBY_INSTANCE_WORK_ID_INT_COPY_CHARA,
|
*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
|
// Sheik Needles
|
||||||
else if fighter_kind == FIGHTER_KIND_SHEIK {
|
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
|
// Only try to set up Copy Ability when the current opponent matches the type of fighter from the save state
|
||||||
let opponent_matches_fighter =
|
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) {
|
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() {
|
if !is_training_mode() {
|
||||||
original!()(work_module, value, address);
|
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);
|
original!()(work_module, value, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +91,7 @@ pub fn init() {
|
|||||||
//handle_on_flag,
|
//handle_on_flag,
|
||||||
//handle_set_int,
|
//handle_set_int,
|
||||||
// handle_set_int_64,
|
// handle_set_int_64,
|
||||||
// handle_set_float,
|
handle_set_float,
|
||||||
// handle_get_int,
|
// handle_get_int,
|
||||||
//handle_is_flag,
|
//handle_is_flag,
|
||||||
);
|
);
|
||||||
|
@ -7,7 +7,7 @@ use crate::common::{
|
|||||||
use crate::hitbox_visualizer;
|
use crate::hitbox_visualizer;
|
||||||
use crate::input::*;
|
use crate::input::*;
|
||||||
use crate::logging::*;
|
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::hooks::{getRegionAddress, InlineCtx, Region};
|
||||||
use skyline::nn::ro::LookupSymbol;
|
use skyline::nn::ro::LookupSymbol;
|
||||||
use smash::app::{self, enSEType, lua_bind::*, utility};
|
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)
|
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;
|
static FOLLOW_REQ_OFFSET: usize = 0x044f860;
|
||||||
#[skyline::hook(offset = FOLLOW_REQ_OFFSET)] // hooked to prevent score gfx from playing when loading save states
|
#[skyline::hook(offset = FOLLOW_REQ_OFFSET)] // hooked to prevent score gfx from playing when loading save states
|
||||||
pub unsafe fn handle_effect_follow(
|
pub unsafe fn handle_effect_follow(
|
||||||
effect_module: *mut FighterEffectModule,
|
effect_module: &mut FighterEffectModule,
|
||||||
eff_hash: Hash40,
|
eff_hash: Hash40,
|
||||||
eff_hash2: Hash40,
|
joint_hash: Hash40,
|
||||||
pos: *const Vector3f,
|
pos: *const Vector3f,
|
||||||
rot: *const Vector3f,
|
rot: *const Vector3f,
|
||||||
mut size: f32,
|
mut size: f32,
|
||||||
@ -549,7 +554,7 @@ pub unsafe fn handle_effect_follow(
|
|||||||
return original!()(
|
return original!()(
|
||||||
effect_module,
|
effect_module,
|
||||||
eff_hash,
|
eff_hash,
|
||||||
eff_hash2,
|
joint_hash,
|
||||||
pos,
|
pos,
|
||||||
rot,
|
rot,
|
||||||
size,
|
size,
|
||||||
@ -570,7 +575,7 @@ pub unsafe fn handle_effect_follow(
|
|||||||
original!()(
|
original!()(
|
||||||
effect_module,
|
effect_module,
|
||||||
eff_hash,
|
eff_hash,
|
||||||
eff_hash2,
|
joint_hash,
|
||||||
pos,
|
pos,
|
||||||
rot,
|
rot,
|
||||||
size,
|
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;
|
static EFFECT_REQ_OFFSET: usize = 0x44de50;
|
||||||
#[skyline::hook(offset = EFFECT_REQ_OFFSET)] // hooked to prevent death gfx from playing when loading save states
|
#[skyline::hook(offset = EFFECT_REQ_OFFSET)] // hooked to prevent death gfx from playing when loading save states
|
||||||
pub unsafe fn handle_fighter_effect(
|
pub unsafe fn handle_fighter_effect(
|
||||||
@ -931,6 +931,7 @@ pub fn training_mods() {
|
|||||||
ui::init();
|
ui::init();
|
||||||
pikmin::init();
|
pikmin::init();
|
||||||
ptrainer::init();
|
ptrainer::init();
|
||||||
|
kirby::init();
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
debug::init();
|
debug::init();
|
||||||
|
@ -69,9 +69,10 @@ pub enum SaveState {
|
|||||||
KillPlayer,
|
KillPlayer,
|
||||||
WaitForAlive,
|
WaitForAlive,
|
||||||
PosMove,
|
PosMove,
|
||||||
NanaPosMove,
|
|
||||||
ApplyBuff,
|
ApplyBuff,
|
||||||
|
NanaPosMove,
|
||||||
WaitForPokemonSwitch,
|
WaitForPokemonSwitch,
|
||||||
|
WaitForCopyAbility,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
|
||||||
@ -191,6 +192,31 @@ pub unsafe fn get_state_pokemon(
|
|||||||
(fighter_kind - *FIGHTER_KIND_PZENIGAME) as u32
|
(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 not mirror
|
||||||
// MIRROR_STATE == -1 -> Do Mirror
|
// MIRROR_STATE == -1 -> Do Mirror
|
||||||
static mut MIRROR_STATE: f32 = 1.0;
|
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
|
// Set the charge of special moves if the fighter matches the kind in the save state
|
||||||
if save_state.fighter_kind == fighter_kind {
|
if save_state.fighter_kind == fighter_kind {
|
||||||
charge::handle_charge(module_accessor, fighter_kind, save_state.charge);
|
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
|
// Buff the fighter if they're one of the fighters who can be buffed
|
||||||
if fighter_is_buffable {
|
if fighter_is_buffable {
|
||||||
@ -642,6 +672,14 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||||||
save_state.state = NoAction;
|
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
|
// Save state
|
||||||
if button_config::combo_passes(button_config::ButtonCombo::SaveState) {
|
if button_config::combo_passes(button_config::ButtonCombo::SaveState) {
|
||||||
// Don't begin saving state if Nana's delayed input is captured
|
// 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(),
|
follow_up: Action::empty(),
|
||||||
frame_advantage: OnOff::Off,
|
frame_advantage: OnOff::Off,
|
||||||
full_hop: BoolFlag::TRUE,
|
full_hop: BoolFlag::TRUE,
|
||||||
hitbox_vis: OnOff::On,
|
hitbox_vis: OnOff::Off,
|
||||||
input_display: InputDisplay::Smash,
|
input_display: InputDisplay::Smash,
|
||||||
input_display_status: OnOff::Off,
|
input_display_status: OnOff::Off,
|
||||||
hud: OnOff::On,
|
hud: OnOff::On,
|
||||||
|
Reference in New Issue
Block a user