mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-24 02:44:17 +00:00
Pikmin Save States and Skyline Smash update (#613)
* 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 feature print methods * Pikmin debug assertions * clippy print fix * appease clippy
This commit is contained in:
parent
68a16f66fe
commit
9e94ef72a9
9 changed files with 405 additions and 18 deletions
|
@ -9,7 +9,7 @@ crate-type = ["cdylib"]
|
|||
|
||||
[dependencies]
|
||||
skyline = { git = "https://github.com/ultimate-research/skyline-rs.git" }
|
||||
skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git", branch = "no-cache" }
|
||||
skyline_smash = { git = "https://github.com/GradualSyrup/skyline-smash.git", branch = "training-modpack-updates" }
|
||||
skyline-web = { git = "https://github.com/skyline-rs/skyline-web.git" }
|
||||
bitflags = "1.2.1"
|
||||
parking_lot = { version = "0.12.0", features = ["nightly"] }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use smash::app::{self, lua_bind::*};
|
||||
use smash::app::{self, lua_bind::*, utility};
|
||||
use smash::hash40;
|
||||
use smash::lib::lua_const::*;
|
||||
use smash::lua2cpp::L2CFighterCommon;
|
||||
|
@ -34,7 +34,7 @@ pub fn is_training_mode() -> bool {
|
|||
}
|
||||
|
||||
pub fn get_category(module_accessor: &app::BattleObjectModuleAccessor) -> i32 {
|
||||
(module_accessor.info >> 28) as u8 as i32
|
||||
(module_accessor.battle_object_id >> 28) as u8 as i32
|
||||
}
|
||||
|
||||
pub fn is_emulator() -> bool {
|
||||
|
@ -266,6 +266,88 @@ pub unsafe fn get_fighter_distance() -> f32 {
|
|||
)
|
||||
}
|
||||
|
||||
// Example Call:
|
||||
|
||||
// print_fighter_info(
|
||||
// module_accessor,
|
||||
// "DebugTest",
|
||||
// true,
|
||||
// false,
|
||||
// true,
|
||||
// true,
|
||||
// vec![
|
||||
// ("FIGHTER_INSTANCE_WORK_ID_INT_CLIFF_COUNT", FIGHTER_INSTANCE_WORK_ID_INT_CLIFF_COUNT),
|
||||
// ],
|
||||
// Vec::new(),
|
||||
// vec![
|
||||
// ("FIGHTER_STATUS_CLIFF_FLAG_TO_FALL", FIGHTER_STATUS_CLIFF_FLAG_TO_FALL),
|
||||
// ],
|
||||
// );
|
||||
#[allow(dead_code)] // We won't be using this function in builds, but we don't want to be warned about it
|
||||
#[allow(clippy::too_many_arguments)] // This function has so many arguments so it's easy to quickly fill them in when debugging with the analyzer
|
||||
pub fn print_fighter_info(
|
||||
module_accessor: &mut app::BattleObjectModuleAccessor,
|
||||
title: &str,
|
||||
player_only: bool,
|
||||
cpu_only: bool,
|
||||
print_fighter_kind: bool,
|
||||
print_status: bool,
|
||||
work_int_pairs: Vec<(&str, i32)>,
|
||||
work_float_pairs: Vec<(&str, i32)>,
|
||||
work_flag_pairs: Vec<(&str, i32)>,
|
||||
) {
|
||||
unsafe {
|
||||
// Don't print for fighters we don't want to
|
||||
let is_cpu = is_operation_cpu(module_accessor);
|
||||
if (player_only && is_cpu) || (cpu_only && !is_cpu) {
|
||||
return;
|
||||
}
|
||||
// Print Title
|
||||
print!("{}: ", title);
|
||||
// Print Fighter Kind:
|
||||
if print_fighter_kind {
|
||||
print!("FIGHTER_KIND: {}, ", utility::get_kind(module_accessor));
|
||||
}
|
||||
// Print Status:
|
||||
if print_status {
|
||||
print!(
|
||||
"FIGHTER_STATUS: {}, ",
|
||||
StatusModule::status_kind(module_accessor)
|
||||
);
|
||||
}
|
||||
|
||||
// Print Work Ints:
|
||||
for work_int_pair in work_int_pairs {
|
||||
print!(
|
||||
"{}: {}, ",
|
||||
work_int_pair.0,
|
||||
WorkModule::get_int(module_accessor, work_int_pair.1)
|
||||
);
|
||||
}
|
||||
|
||||
// Print Work Floats:
|
||||
for work_float_pair in work_float_pairs {
|
||||
print!(
|
||||
"{}: {}, ",
|
||||
work_float_pair.0,
|
||||
WorkModule::get_float(module_accessor, work_float_pair.1)
|
||||
);
|
||||
}
|
||||
|
||||
// Print Work Flags:
|
||||
for work_flag_pair in work_flag_pairs {
|
||||
print!(
|
||||
"{}: {}, ",
|
||||
work_flag_pair.0,
|
||||
WorkModule::is_flag(module_accessor, work_flag_pair.1)
|
||||
);
|
||||
}
|
||||
|
||||
// End Line
|
||||
println!("|");
|
||||
}
|
||||
}
|
||||
|
||||
// From https://github.com/chrispo-git/ult-s/blob/cc1c3060ed83f6d33f39964e84f9c32c07a17bae/src/controls/util.rs#L106
|
||||
pub unsafe fn get_fighter_common_from_accessor(
|
||||
module_accessor: &mut app::BattleObjectModuleAccessor,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(clippy::unnecessary_unwrap)]
|
||||
use crate::common::dialog;
|
||||
use crate::consts::*;
|
||||
use crate::dialog;
|
||||
use crate::logging::*;
|
||||
use crate::MENU;
|
||||
use anyhow::{anyhow, Result};
|
||||
|
|
|
@ -2,6 +2,7 @@ use smash::app::{self};
|
|||
|
||||
mod bowser;
|
||||
pub mod items;
|
||||
pub mod pikmin;
|
||||
pub mod steve;
|
||||
|
||||
/**
|
||||
|
|
214
src/training/character_specific/pikmin.rs
Normal file
214
src/training/character_specific/pikmin.rs
Normal file
|
@ -0,0 +1,214 @@
|
|||
use smash::app::{self, lua_bind::*, smashball::is_training_mode};
|
||||
use smash::lib::lua_const::*;
|
||||
|
||||
#[repr(C)]
|
||||
struct TroopsManager {
|
||||
_x0: u64,
|
||||
max_pikmin_count: usize, // always 3
|
||||
current_pikmin_count: usize,
|
||||
pikmin_objects: *mut *mut app::BattleObject,
|
||||
pikmin: [*mut app::BattleObject; 3],
|
||||
padding_0: u64,
|
||||
padding_1: u64,
|
||||
padding_2: u64,
|
||||
padding_3: u64,
|
||||
padding_4: u64,
|
||||
padding_5: u64,
|
||||
padding_6: u64,
|
||||
padding_7: u64,
|
||||
padding_8: u64,
|
||||
held_pikmin_count: usize,
|
||||
maybe_more_pikmin_objects: *mut *mut app::BattleObject,
|
||||
held_pikmin: [*mut app::BattleObject; 3], // @ 0x90
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct WeaponWorkModule {
|
||||
vtable: u64,
|
||||
owner: *mut app::BattleObjectModuleAccessor,
|
||||
}
|
||||
|
||||
// Prevent Order Loss
|
||||
static ACTIVATE_AUTONOMY_OFFSET: usize = 0x034b5cf0;
|
||||
#[skyline::hook(offset = ACTIVATE_AUTONOMY_OFFSET)]
|
||||
pub unsafe fn autonomy_handle(weapon: *mut app::Weapon, work_module: *mut WeaponWorkModule) {
|
||||
if !is_training_mode() {
|
||||
return original!()(weapon, work_module);
|
||||
}
|
||||
let pikmin_boma = (*work_module).owner;
|
||||
// If the Pikmin is in a status where we want this behavior, execute the original process
|
||||
let pikmin_status = StatusModule::status_kind(pikmin_boma);
|
||||
let is_pikmin_thrown = (*WEAPON_PIKMIN_PIKMIN_STATUS_KIND_ATTACK_AIR
|
||||
..=*WEAPON_PIKMIN_PIKMIN_STATUS_KIND_ATTACK_HI4_LANDING)
|
||||
.contains(&pikmin_status);
|
||||
if is_pikmin_thrown {
|
||||
original!()(weapon, work_module)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
skyline::install_hooks!(autonomy_handle,);
|
||||
}
|
||||
|
||||
fn get_pikmin_prev(variation: i32) -> i32 {
|
||||
if variation > 0 {
|
||||
return variation - 1;
|
||||
}
|
||||
4
|
||||
}
|
||||
|
||||
pub unsafe fn follow(module_accessor: &mut app::BattleObjectModuleAccessor) {
|
||||
let troops_manager = WorkModule::get_int64(module_accessor, 0x100000C0) as *mut TroopsManager;
|
||||
let following_count = (*troops_manager).current_pikmin_count;
|
||||
let held_count = (*troops_manager).held_pikmin_count;
|
||||
|
||||
let mut pikmin_boid_following_vec = Vec::new();
|
||||
let mut pikmin_boid_held_vec = Vec::new();
|
||||
|
||||
// First, we get the order of held pikmin, since they'll be in front if we save state during a move or grab
|
||||
for held_index in 0..held_count {
|
||||
let held_boid = (*((*troops_manager).held_pikmin[held_index])).battle_object_id;
|
||||
pikmin_boid_held_vec.push(held_boid);
|
||||
}
|
||||
// Next, we get the order of the following pikmin
|
||||
for following_index in 0..following_count {
|
||||
let following_boid = (*((*troops_manager).pikmin[following_index])).battle_object_id;
|
||||
pikmin_boid_following_vec.push(following_boid);
|
||||
}
|
||||
|
||||
for pikmin_boid in pikmin_boid_following_vec {
|
||||
let pikmin_boma = app::sv_battle_object::module_accessor(pikmin_boid);
|
||||
StatusModule::change_status_request(
|
||||
pikmin_boma,
|
||||
*WEAPON_PIKMIN_PIKMIN_STATUS_KIND_AIR_FOLLOW,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn spawn_pikmin(module_accessor: &mut app::BattleObjectModuleAccessor, variation: i32) {
|
||||
WorkModule::set_int(
|
||||
module_accessor,
|
||||
get_pikmin_prev(variation),
|
||||
*FIGHTER_PIKMIN_INSTANCE_WORK_INT_PRE_PIKMIN_VARIATION,
|
||||
);
|
||||
WorkModule::set_int(
|
||||
module_accessor,
|
||||
get_pikmin_prev(get_pikmin_prev(variation)),
|
||||
*FIGHTER_PIKMIN_INSTANCE_WORK_INT_BEFORE_PRE_PIKMIN_VARIATION,
|
||||
);
|
||||
ArticleModule::generate_article(
|
||||
module_accessor as *mut app::BattleObjectModuleAccessor,
|
||||
0,
|
||||
false,
|
||||
-1,
|
||||
);
|
||||
}
|
||||
|
||||
pub unsafe fn get_current_pikmin(
|
||||
module_accessor: &mut app::BattleObjectModuleAccessor,
|
||||
) -> [Option<i32>; 3] {
|
||||
let troops_manager = WorkModule::get_int64(module_accessor, 0x100000C0) as *mut TroopsManager;
|
||||
|
||||
let following_count = (*troops_manager).current_pikmin_count;
|
||||
let held_count = (*troops_manager).held_pikmin_count;
|
||||
|
||||
let mut pikmin_boid_vec = Vec::new();
|
||||
//let mut pikmin_boma_vec: [*mut app::BattleObjectModuleAccessor; 3] = [0 as *mut app::BattleObjectModuleAccessor; 3];
|
||||
let mut ordered_pikmin_variation: [Option<i32>; 3] = [None; 3];
|
||||
|
||||
// First, we get the order of held pikmin, since they'll be in front if we save state during a move or grab
|
||||
for held_index in 0..held_count {
|
||||
let held_work_var = match held_index {
|
||||
0 => *FIGHTER_PIKMIN_INSTANCE_WORK_INT_PIKMIN_HOLD_PIKMIN_OBJECT_ID_0,
|
||||
1 => *FIGHTER_PIKMIN_INSTANCE_WORK_INT_PIKMIN_HOLD_PIKMIN_OBJECT_ID_1,
|
||||
2 => *FIGHTER_PIKMIN_INSTANCE_WORK_INT_PIKMIN_HOLD_PIKMIN_OBJECT_ID_2,
|
||||
_ => {
|
||||
panic!("Pikmin Held Out of Bounds!");
|
||||
}
|
||||
};
|
||||
let held_boid = WorkModule::get_int(module_accessor, held_work_var) as u32;
|
||||
println!(", boid: {}", held_boid);
|
||||
pikmin_boid_vec.push(held_boid);
|
||||
}
|
||||
// Next, we get the order of the following pikmin
|
||||
for following_index in 0..following_count {
|
||||
let following_boid = (*((*troops_manager).pikmin[following_index])).battle_object_id;
|
||||
pikmin_boid_vec.push(following_boid);
|
||||
}
|
||||
// Now, we have all pikmin boids, and want to get their bomas (if they exist) so we can check their color
|
||||
for (idx, pikmin_boid) in pikmin_boid_vec.iter().enumerate() {
|
||||
if *pikmin_boid != *BATTLE_OBJECT_ID_INVALID as u32
|
||||
&& app::sv_battle_object::is_active(*pikmin_boid)
|
||||
{
|
||||
let pikmin_boma = app::sv_battle_object::module_accessor(*pikmin_boid);
|
||||
let pikmin_variation = WorkModule::get_int(
|
||||
pikmin_boma,
|
||||
*WEAPON_PIKMIN_PIKMIN_INSTANCE_WORK_ID_INT_VARIATION,
|
||||
);
|
||||
ordered_pikmin_variation[idx] = Some(pikmin_variation);
|
||||
}
|
||||
}
|
||||
|
||||
ordered_pikmin_variation
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn pretty_print(module_accessor: &mut app::BattleObjectModuleAccessor) {
|
||||
let troops_manager = WorkModule::get_int64(module_accessor, 0x100000C0) as *mut TroopsManager;
|
||||
|
||||
let following_count = (*troops_manager).current_pikmin_count;
|
||||
let held_count = (*troops_manager).held_pikmin_count;
|
||||
|
||||
let mut pikmin_following_boid_vec = Vec::new();
|
||||
let mut pikmin_held_boid_vec = Vec::new();
|
||||
|
||||
// First, we get the order of held pikmin, since they'll be in front if we save state during a move or grab
|
||||
for held_index in 0..held_count {
|
||||
let held_boid = (*((*troops_manager).held_pikmin[held_index])).battle_object_id;
|
||||
pikmin_held_boid_vec.push(held_boid);
|
||||
print(held_boid, true);
|
||||
}
|
||||
// Next, we get the order of the following pikmin
|
||||
for following_index in 0..following_count {
|
||||
let following_boid = (*((*troops_manager).pikmin[following_index])).battle_object_id;
|
||||
pikmin_following_boid_vec.push(following_boid);
|
||||
print(following_boid, false);
|
||||
}
|
||||
println!("----------------------------------------")
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
#[allow(dead_code)]
|
||||
unsafe fn print(boid: u32, held: bool) {
|
||||
if boid != *BATTLE_OBJECT_ID_INVALID as u32 && app::sv_battle_object::is_active(boid) {
|
||||
let pikmin_boma = app::sv_battle_object::module_accessor(boid);
|
||||
let pikmin_variation = WorkModule::get_int(
|
||||
pikmin_boma,
|
||||
*WEAPON_PIKMIN_PIKMIN_INSTANCE_WORK_ID_INT_VARIATION,
|
||||
);
|
||||
let pikmin_status = StatusModule::status_kind(pikmin_boma);
|
||||
let pikmin_autonomy: bool = WorkModule::is_flag(
|
||||
pikmin_boma,
|
||||
*WEAPON_PIKMIN_PIKMIN_INSTANCE_WORK_ID_FLAG_AUTONOMY,
|
||||
);
|
||||
// solution:
|
||||
//WorkModule::off_flag(pikmin_boma, *WEAPON_PIKMIN_PIKMIN_INSTANCE_WORK_ID_FLAG_AUTONOMY);
|
||||
let owner_cond = WorkModule::get_int(
|
||||
pikmin_boma,
|
||||
*WEAPON_PIKMIN_PIKMIN_INSTANCE_WORK_ID_INT_OWNER_CONDITION_CURRENT,
|
||||
);
|
||||
let owner_cond_follow = WorkModule::get_int(
|
||||
pikmin_boma,
|
||||
*WEAPON_PIKMIN_PIKMIN_INSTANCE_WORK_ID_INT_OWNER_CONDITION_FOLLOW,
|
||||
);
|
||||
let owner_opt_flag_follow = WorkModule::get_int(
|
||||
pikmin_boma,
|
||||
*WEAPON_PIKMIN_PIKMIN_INSTANCE_WORK_ID_INT_OWNER_OPTION_FLAG_FOLLOW,
|
||||
);
|
||||
println!("Color: {}, Status: {}, Held {}, Autonomy: {}, owner_cond: {}, owner_cond_follow: {}, owner_opt_flag_follow: {}",
|
||||
pikmin_variation, pikmin_status, held, pikmin_autonomy, owner_cond, owner_cond_follow, owner_opt_flag_follow
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
use crate::training::character_specific::pikmin;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smash::app::{self, lua_bind::*, ArticleOperationTarget, FighterFacial, FighterUtil};
|
||||
use smash::lib::lua_const::*;
|
||||
|
@ -7,6 +8,7 @@ use smash::phx::{Hash40, Vector3f};
|
|||
pub struct ChargeState {
|
||||
pub int_x: Option<i32>,
|
||||
pub int_y: Option<i32>,
|
||||
pub int_z: Option<i32>,
|
||||
pub float_x: Option<f32>,
|
||||
pub float_y: Option<f32>,
|
||||
pub float_z: Option<f32>,
|
||||
|
@ -39,6 +41,18 @@ impl ChargeState {
|
|||
self
|
||||
}
|
||||
|
||||
fn set_pikmin(
|
||||
mut self,
|
||||
pikmin_1: Option<i32>,
|
||||
pikmin_2: Option<i32>,
|
||||
pikmin_3: Option<i32>,
|
||||
) -> Self {
|
||||
self.int_x = pikmin_1;
|
||||
self.int_y = pikmin_2;
|
||||
self.int_z = pikmin_3;
|
||||
self
|
||||
}
|
||||
|
||||
fn has_charge(mut self, has_charge: bool) -> Self {
|
||||
self.has_charge = Some(has_charge);
|
||||
self
|
||||
|
@ -115,7 +129,10 @@ pub unsafe fn get_charge(
|
|||
}
|
||||
// Wario Waft
|
||||
else if fighter_kind == FIGHTER_KIND_WARIO {
|
||||
let my_charge = WorkModule::get_int(module_accessor, 0x100000BF); // FIGHTER_WARIO_INSTANCE_WORK_ID_INT_GASS_COUNT
|
||||
let my_charge = WorkModule::get_int(
|
||||
module_accessor,
|
||||
*FIGHTER_WARIO_INSTANCE_WORK_ID_INT_GASS_COUNT,
|
||||
);
|
||||
charge_state.int_x(my_charge)
|
||||
}
|
||||
// Squirtle Water Gun
|
||||
|
@ -126,6 +143,11 @@ pub unsafe fn get_charge(
|
|||
);
|
||||
charge_state.int_x(my_charge)
|
||||
}
|
||||
// Olimar Pikmin
|
||||
else if fighter_kind == FIGHTER_KIND_PIKMIN {
|
||||
let pikmin_array = pikmin::get_current_pikmin(module_accessor);
|
||||
return charge_state.set_pikmin(pikmin_array[0], pikmin_array[1], pikmin_array[2]);
|
||||
}
|
||||
// Lucario Aura Sphere
|
||||
else if fighter_kind == FIGHTER_KIND_LUCARIO {
|
||||
let my_charge = WorkModule::get_int(
|
||||
|
@ -174,7 +196,10 @@ pub unsafe fn get_charge(
|
|||
}
|
||||
// Pac-Man Bonus Fruit
|
||||
else if fighter_kind == FIGHTER_KIND_PACMAN {
|
||||
let my_charge = WorkModule::get_int(module_accessor, 0x100000C1); // FIGHTER_PACMAN_INSTANCE_WORK_ID_INT_SPECIAL_N_CHARGE_RANK
|
||||
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,
|
||||
|
@ -501,7 +526,11 @@ pub unsafe fn handle_charge(
|
|||
// Wario Waft - 0 to 6000
|
||||
else if fighter_kind == FIGHTER_KIND_WARIO {
|
||||
charge.int_x.map(|waft_count| {
|
||||
WorkModule::set_int(module_accessor, waft_count, 0x100000BF); // FIGHTER_WARIO_INSTANCE_WORK_ID_INT_GASS_COUNT
|
||||
WorkModule::set_int(
|
||||
module_accessor,
|
||||
waft_count,
|
||||
*FIGHTER_WARIO_INSTANCE_WORK_ID_INT_GASS_COUNT,
|
||||
);
|
||||
});
|
||||
}
|
||||
// Squirtle Water Gun - 0 to 45
|
||||
|
@ -517,6 +546,36 @@ pub unsafe fn handle_charge(
|
|||
}
|
||||
});
|
||||
}
|
||||
// Olimar Pikmin - 0 to 4
|
||||
else if fighter_kind == FIGHTER_KIND_PIKMIN {
|
||||
ArticleModule::remove_exist(
|
||||
module_accessor,
|
||||
*FIGHTER_PIKMIN_GENERATE_ARTICLE_PIKMIN,
|
||||
app::ArticleOperationTarget(*ARTICLE_OPE_TARGET_ALL),
|
||||
);
|
||||
if ArticleModule::get_active_num(module_accessor, *FIGHTER_PIKMIN_GENERATE_ARTICLE_PIKMIN)
|
||||
== 0
|
||||
{
|
||||
charge.int_x.map(|pikmin_1| {
|
||||
pikmin::spawn_pikmin(module_accessor, pikmin_1);
|
||||
});
|
||||
}
|
||||
if ArticleModule::get_active_num(module_accessor, *FIGHTER_PIKMIN_GENERATE_ARTICLE_PIKMIN)
|
||||
== 1
|
||||
{
|
||||
charge.int_y.map(|pikmin_2| {
|
||||
pikmin::spawn_pikmin(module_accessor, pikmin_2);
|
||||
});
|
||||
}
|
||||
if ArticleModule::get_active_num(module_accessor, *FIGHTER_PIKMIN_GENERATE_ARTICLE_PIKMIN)
|
||||
== 2
|
||||
{
|
||||
charge.int_z.map(|pikmin_3| {
|
||||
pikmin::spawn_pikmin(module_accessor, pikmin_3);
|
||||
});
|
||||
}
|
||||
pikmin::follow(module_accessor);
|
||||
}
|
||||
// Lucario Aura Sphere - 0 to 90, Boolean
|
||||
else if fighter_kind == FIGHTER_KIND_LUCARIO {
|
||||
charge.int_x.map(|charge_frame| {
|
||||
|
@ -641,7 +700,11 @@ pub unsafe fn handle_charge(
|
|||
else if fighter_kind == FIGHTER_KIND_PACMAN {
|
||||
let mut has_key = false;
|
||||
charge.int_x.map(|charge_rank| {
|
||||
WorkModule::set_int(module_accessor, charge_rank, 0x100000C1); // FIGHTER_PACMAN_INSTANCE_WORK_ID_INT_SPECIAL_N_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);
|
||||
|
@ -799,7 +862,10 @@ pub unsafe fn handle_charge(
|
|||
// Hero (Ka)frizz(le) - 0 to 81
|
||||
else if fighter_kind == FIGHTER_KIND_BRAVE {
|
||||
EffectModule::remove_common(module_accessor, Hash40::new("charge_max"));
|
||||
WorkModule::off_flag(module_accessor, 0x200000E8); // FIGHTER_BRAVE_INSTANCE_WORK_ID_FLAG_SPECIAL_N_MAX_EFFECT
|
||||
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,
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::common::{
|
|||
use crate::hitbox_visualizer;
|
||||
use crate::input::*;
|
||||
use crate::logging::*;
|
||||
use crate::training::character_specific::items;
|
||||
use crate::training::character_specific::{items, pikmin};
|
||||
use skyline::hooks::{getRegionAddress, InlineCtx, Region};
|
||||
use skyline::nn::ro::LookupSymbol;
|
||||
use smash::app::{self, enSEType, lua_bind::*, utility};
|
||||
|
@ -680,6 +680,17 @@ pub unsafe fn handle_reused_ui(
|
|||
original!()(fighter_data, param_2)
|
||||
}
|
||||
|
||||
static ARTICLE_GET_INT_OFFSET: usize = 0x3d5920;
|
||||
|
||||
#[skyline::hook(offset = ARTICLE_GET_INT_OFFSET)]
|
||||
pub unsafe fn handle_article_get_int(
|
||||
article_module: *mut app::BattleObjectModuleAccessor, // *mut ArticleModule
|
||||
generate_article: i32,
|
||||
address: i32,
|
||||
) -> i32 {
|
||||
original!()(article_module, generate_article, address)
|
||||
}
|
||||
|
||||
// Instruction run on the completion of the CPU Control function
|
||||
static OPCF_OFFSET: usize = 0x06b7fdc;
|
||||
|
||||
|
@ -735,6 +746,15 @@ unsafe fn handle_final_input_mapping(
|
|||
input_record::handle_final_input_mapping(player_idx, out);
|
||||
}
|
||||
|
||||
static BOMA_OFFSET: usize = 0x15cf1b0;
|
||||
|
||||
#[skyline::hook(offset = BOMA_OFFSET)]
|
||||
pub unsafe fn handle_get_module_accessor(
|
||||
battle_object_id: u32,
|
||||
) -> *mut app::BattleObjectModuleAccessor {
|
||||
original!()(battle_object_id)
|
||||
}
|
||||
|
||||
pub fn training_mods() {
|
||||
info!("Applying training mods.");
|
||||
|
||||
|
@ -813,10 +833,14 @@ pub fn training_mods() {
|
|||
// Notifications
|
||||
handle_once_per_cpu_frame,
|
||||
// Input
|
||||
handle_final_input_mapping
|
||||
handle_final_input_mapping,
|
||||
// Charge
|
||||
handle_article_get_int,
|
||||
handle_get_module_accessor,
|
||||
);
|
||||
|
||||
items::init();
|
||||
input_record::init();
|
||||
ui::init();
|
||||
pikmin::init();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ use crate::training::reset;
|
|||
use crate::training::ui::notifications;
|
||||
use crate::{is_ptrainer, ITEM_MANAGER_ADDR};
|
||||
|
||||
// Don't remove Mii hats, or Luma, or crafting table
|
||||
// Don't remove Mii hats, Pikmin, Luma, or crafting table
|
||||
const ARTICLE_ALLOWLIST: [(LuaConst, LuaConst); 8] = [
|
||||
(
|
||||
FIGHTER_KIND_MIIFIGHTER,
|
||||
|
@ -98,6 +98,7 @@ macro_rules! default_save_state {
|
|||
charge: ChargeState {
|
||||
int_x: None,
|
||||
int_y: None,
|
||||
int_z: None,
|
||||
float_x: None,
|
||||
float_y: None,
|
||||
float_z: None,
|
||||
|
@ -308,12 +309,11 @@ unsafe fn on_ptrainer_death(module_accessor: &mut app::BattleObjectModuleAccesso
|
|||
ptrainer_module_accessor,
|
||||
*WEAPON_PTRAINER_PTRAINER_GENERATE_ARTICLE_MBALL,
|
||||
) {
|
||||
let ptrainer_masterball: u64 = ArticleModule::get_article(
|
||||
let ptrainer_masterball: *mut app::Article = ArticleModule::get_article(
|
||||
ptrainer_module_accessor,
|
||||
*WEAPON_PTRAINER_PTRAINER_GENERATE_ARTICLE_MBALL,
|
||||
);
|
||||
let ptrainer_masterball_id =
|
||||
Article::get_battle_object_id(ptrainer_masterball as *mut app::Article);
|
||||
let ptrainer_masterball_id = Article::get_battle_object_id(ptrainer_masterball);
|
||||
let ptrainer_masterball_module_accessor =
|
||||
&mut *app::sv_battle_object::module_accessor(ptrainer_masterball_id as u32);
|
||||
MotionModule::set_rate(ptrainer_masterball_module_accessor, 1000.0);
|
||||
|
@ -339,8 +339,9 @@ unsafe fn on_death(fighter_kind: i32, module_accessor: &mut app::BattleObjectMod
|
|||
})
|
||||
.for_each(|article_idx| {
|
||||
if ArticleModule::is_exist(module_accessor, article_idx) {
|
||||
let article: u64 = ArticleModule::get_article(module_accessor, article_idx);
|
||||
let article_object_id = Article::get_battle_object_id(article as *mut app::Article);
|
||||
let article: *mut app::Article =
|
||||
ArticleModule::get_article(module_accessor, article_idx);
|
||||
let article_object_id = Article::get_battle_object_id(article);
|
||||
ArticleModule::remove_exist_object_id(module_accessor, article_object_id as u32);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -496,7 +496,6 @@ bitflags! {
|
|||
const U_TILT = 0x0010_0000;
|
||||
const D_TILT = 0x0020_0000;
|
||||
const GRAB = 0x0040_0000;
|
||||
// TODO: Make work
|
||||
const DASH = 0x0080_0000;
|
||||
const DASH_ATTACK = 0x0100_0000;
|
||||
const PLAYBACK_1 = 0x0200_0000;
|
||||
|
|
Loading…
Reference in a new issue