Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions dynamic/src/attack_log.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use crate::{consts::vars, VarModule};
use smash::app::BattleObject;

pub type StaleMoveQueue = AttackLog<4>;

#[inline]
pub const fn pack_player_seed(player_id: u32, seed: u32) -> i32 {
let raw: u32 = ((player_id) << 16) | (seed);
raw as i32
}

#[inline]
pub const fn unpack_player_id(packed: i32) -> u16 {
((packed as u32) >> 16) as u16
}

#[inline]
pub const fn unpack_seed(packed: i32) -> u16 {
(packed as u32 & 0xFFFF) as u16
}

#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct AttackPatternLogEntry {
/// packed: hi16 = player_id, lo16 = per-player seed
pub status_seed: i32,
pub frame_entry: u32,
pub attack_kind: u64,
}

impl AttackPatternLogEntry {
#[inline]
pub const fn new(status_seed: i32, frame_entry: u32, attack_kind: u64) -> Self {
Self {
status_seed,
frame_entry,
attack_kind,
}
}

#[inline]
pub const fn new_entry(player_id: u32, seed: u32, frame_entry: u32, attack_kind: u64) -> Self {
Self {
status_seed: pack_player_seed(player_id, seed),
frame_entry,
attack_kind,
}
}

#[inline]
pub const fn zero() -> Self {
Self {
status_seed: 0,
frame_entry: 0,
attack_kind: 0,
}
}

#[inline]
pub const fn player_id(self) -> u16 {
unpack_player_id(self.status_seed)
}

#[inline]
pub const fn seed(self) -> u16 {
unpack_seed(self.status_seed)
}

#[inline]
pub const fn pack_slot0(self) -> u64 {
// same-width cast
let hi = self.status_seed as u32 as u64;
let lo = self.frame_entry as u32 as u64;
(hi << 32) | lo
}

#[inline]
pub const fn unpack_slot0(slot0: u64) -> (i32, u32) {
let hi = (slot0 >> 32) as u32 as i32;
let lo = (slot0 & 0xFFFF_FFFF) as u32;
(hi, lo)
}
}

pub struct AttackLog<const N: usize>;

impl<const N: usize> AttackLog<N> {
pub const FIRST_ENTRY: i32 = vars::common::instance::ATTACK_LOG_ENTRIES;
pub const STRIDE: i32 = 2; // two u64 slots per entry

#[inline]
pub const fn base(i: usize) -> i32 {
Self::FIRST_ENTRY + (i as i32) * Self::STRIDE
}
#[inline]
pub const fn slot0(i: usize) -> i32 {
Self::base(i)
}
#[inline]
pub const fn slot1(i: usize) -> i32 {
Self::base(i) + 1
}

#[inline]
pub unsafe fn clear(object: *mut BattleObject) {
for i in 0..N {
VarModule::set_int64(object, Self::slot0(i), 0);
VarModule::set_int64(object, Self::slot1(i), 0);
}
}

#[inline]
pub unsafe fn set(object: *mut BattleObject, i: usize, e: AttackPatternLogEntry) {
VarModule::set_int64(object, Self::slot0(i), e.pack_slot0());
VarModule::set_int64(object, Self::slot1(i), e.attack_kind);
}

#[inline]
pub unsafe fn get(object: *mut BattleObject, i: usize) -> AttackPatternLogEntry {
let s0 = VarModule::get_int64(object, Self::slot0(i));
let attack_kind = VarModule::get_int64(object, Self::slot1(i));
let (status_seed, frame_entry) = AttackPatternLogEntry::unpack_slot0(s0);
AttackPatternLogEntry {
status_seed,
frame_entry,
attack_kind,
}
}

pub unsafe fn check_stale(object: *mut BattleObject, entry: AttackPatternLogEntry) -> bool {
let entry_player = entry.player_id();
let entry_seed = entry.seed();
let entry_attack = entry.attack_kind;

let mut oldest_index: usize = 0;
let mut oldest_frame: u32 = u32::MAX;

for i in 0..N {
let e = Self::get(object, i);

// Take first empty slot
if e.frame_entry == 0 {
Self::set(object, i, entry);
return false;
}

// Track oldest entry
if e.frame_entry < oldest_frame {
oldest_frame = e.frame_entry;
oldest_index = i;
}

// Check player
if e.player_id() != entry_player {
//println!("Skipping!");
continue;
}

// Same attack seed, refresh frame counter
if e.seed() == entry_seed {
// refresh with new frame
Self::set(object, i, entry);
return false;
}

// New attack seed, check attack staleness
if e.attack_kind == entry_attack {
Self::set(object, i, entry);
return true;
}
}
// Seed and attack are new. Overwrite oldest.
Self::set(object, oldest_index, entry);
false
}
}
8 changes: 8 additions & 0 deletions dynamic/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ pub mod vars {

pub const ATTACK_LR_CHECK: i32 = 0x0014;

// pub const DI_STALE_LEVEL: i32 = 0x0015;
pub const ATTACK_LOG_SEED: i32 = 0x0016;
pub const POWER_UP_BIT_LAST: i32 = 0x0017;

// floats

pub const LAST_ATTACK_DAMAGE_DEALT: i32 = 0x0000;
Expand Down Expand Up @@ -282,6 +286,10 @@ pub mod vars {
pub const LAST_RECEIVED_ATTACK_HIT_LOCATION_Y: i32 = 0x0024;
pub const LAST_RECEIVED_ATTACK_HIT_LOCATION_Z: i32 = 0x0025;
pub const LAND_CANCEL_LAG: i32 = 0x0026;

// int64
pub const ATTACK_LOG_ENTRIES: i32 = 0x0050; // Length(4) * int64
// Padding until 60
}
pub mod status {
// flags
Expand Down
14 changes: 14 additions & 0 deletions dynamic/src/ext.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::consts::{globals::*, vars};
use crate::attack_log::{AttackPatternLogEntry, StaleMoveQueue};
use bitflags::bitflags;
use modular_bitfield::specifiers::*;
use smash::app::{
Expand Down Expand Up @@ -550,6 +551,9 @@ pub trait BomaExt {
unsafe fn sub_check_command_parry(&mut self) -> L2CValue;
// Checks for situation kind and transitions to heavy landing
unsafe fn check_land_cancel(&mut self, landing_lag: Option<f32>) -> bool;
// Checks for stale move queue
unsafe fn check_stale_move_entry(&mut self, entry: AttackPatternLogEntry) -> bool;
unsafe fn reset_stale_move_log(&mut self);

/// check for hitfall (should be called once per frame)
unsafe fn check_hitfall(&mut self) -> bool;
Expand Down Expand Up @@ -1284,6 +1288,16 @@ impl BomaExt for BattleObjectModuleAccessor {
false
}

// Check if move is stale, adds entry if needed.
unsafe fn check_stale_move_entry(&mut self, entry: AttackPatternLogEntry) -> bool {
StaleMoveQueue::check_stale(self.object(), entry)
}

unsafe fn reset_stale_move_log(&mut self) {
StaleMoveQueue::clear(self.object());
}


/// Sets the position of the front/red ledge-grab box (see [`set_center_cliff_hangdata`](BomaExt::set_center_cliff_hangdata) for more information)
///
/// # Arguments
Expand Down
2 changes: 2 additions & 0 deletions dynamic/src/game_modes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub enum CustomMode {
Smash64Mode = 4,
MagicSeriesMode = 5,
ElementMode = 6,
//RainbowDI =
}

impl fmt::Display for CustomMode {
Expand All @@ -23,6 +24,7 @@ impl fmt::Display for CustomMode {
CustomMode::Smash64Mode => write!(f, "Smash64"),
CustomMode::MagicSeriesMode => write!(f, "MagicSeries"),
CustomMode::ElementMode => write!(f, "Element"),
//CustomMode::ElementMode => write!(f, "RainbowDI"),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions dynamic/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod frame_info;
pub mod game_modes;
pub mod ui;
pub mod se;
pub mod attack_log;

#[macro_use]
extern crate modular_bitfield;
Expand Down
28 changes: 27 additions & 1 deletion fighters/common/src/function_hooks/attack.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use crate::attack_log::AttackPatternLogEntry;
use smash_rs::app::CollisionSoundAttr;
use utils::ext::*;
use utils::game_modes::CustomMode;
Expand Down Expand Up @@ -305,13 +306,38 @@ unsafe fn x03df93c(ctx: &mut skyline::hooks::InlineCtx) {
unsafe fn notify_log_event_collision_hit(fighter_manager: u64, attacker_object_id: u32, receiver_object_id: u32, move_type: u64, arg5: u64, move_type_again: u64) -> u64 {
let attacker_boma = &mut *smash::app::sv_battle_object::module_accessor(attacker_object_id);
let receiver_boma = &mut *smash::app::sv_battle_object::module_accessor(receiver_object_id);
let atk_has_var = VarModule::has_var_module(attacker_boma.object());
let rcv_has_var = VarModule::has_var_module(receiver_boma.object());

if VarModule::has_var_module(attacker_boma.object())
if atk_has_var
&& VarModule::is_flag(attacker_boma.object(), vars::common::status::HIT_EFFECT_DROP_ITEM)
&& ItemModule::is_have_item(receiver_boma, 0) {
ItemModule::drop_item(receiver_boma, 90.0, 0.0, 0);
}

// Add Attack to Stale Move Log
// TODO: Projectile Compatibility
if (rcv_has_var && atk_has_var && attacker_boma.is_fighter() && receiver_boma.is_fighter()) {
let attack_seed = VarModule::get_int(attacker_boma.object(), vars::common::instance::ATTACK_LOG_SEED);
let attack_kind = smash::app::sv_battle_object::log_attack_kind(attacker_object_id);
let frame = util::get_global_frame_count() as u32;
let log = AttackPatternLogEntry::new_entry(
attacker_boma.get_player_idx_from_boma() as u32,
attack_seed as u32,
frame,
attack_kind,
);

// Rainbow DI Staling
// if receiver_boma.check_stale_move_entry(log) {
// let mut new_stale_level =
// VarModule::get_int(receiver_boma.object(), vars::common::instance::DI_STALE_LEVEL) + 1;
// new_stale_level = std::cmp::min(new_stale_level, 2);
// VarModule::set_int(receiver_boma.object(), vars::common::instance::DI_STALE_LEVEL, new_stale_level);
// }

}

original!()(fighter_manager, attacker_object_id, receiver_object_id, move_type, arg5, move_type_again)
}

Expand Down
15 changes: 15 additions & 0 deletions fighters/common/src/function_hooks/get_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,20 @@ pub unsafe fn get_param_float_hook(x0 /*boma*/: u64, x1 /*param_type*/: u64, x2
return 4.0;
}
}
// if modes.contains(&CustomMode::RainbowDI) {
// // Correction based on Max DI Level
// if x2 == hash40("damage_fly_correction_max") {
// let bo = boma_reference.object();
// let di_level = VarModule::get_int(bo, vars::common::instance::DI_STALE_LEVEL);
// //println!("Real DI Correction: {} \n", di_level);
// match di_level {
// 1 => return 17.0,
// 2 => return 19.0,
// _ => return original!()(x0, x1, x2),
// };
// return original!()(x0, x1, x2);
// }
// }
},
_ => {}
}
Expand All @@ -207,6 +221,7 @@ pub unsafe fn get_param_float_hook(x0 /*boma*/: u64, x1 /*param_type*/: u64, x2
}
*/


// handle reduction of the tumble threshold for DK when in barrel carry
if x2 == hash40("damage_level3")
&& boma_reference.kind() == *FIGHTER_KIND_DONKEY
Expand Down
2 changes: 1 addition & 1 deletion fighters/common/src/function_hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,7 @@ pub fn install() {
jumps::install();
knockback::install();
stage_hazards::install();
//set_fighter_status_data::install();
set_fighter_status_data::install();
attack::install();
collision::install();
camera::install();
Expand Down
27 changes: 19 additions & 8 deletions fighters/common/src/function_hooks/set_fighter_status_data.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
use super::*;
use globals::*;

const MAX_SEED: u32 = 12_000;

//=================================================================
//== FighterStatusModuleImpl::set_fighter_status_data
//=================================================================
// #[skyline::hook(replace=FighterStatusModuleImpl::set_fighter_status_data)]
// unsafe fn set_fighter_status_data_hook(boma: &mut BattleObjectModuleAccessor, arg2: bool, treaded_kind: i32, arg4: bool, arg5: bool, arg6: bool, log_mask_flag: u64, status_attr: u32, power_up_attack_bit: u32, arg10: u32) {
// original!()(boma, arg2, treaded_kind, arg4, arg5, arg6, log_mask_flag, new_status_attr, power_up_attack_bit, arg10)
// }
#[skyline::hook(replace=FighterStatusModuleImpl::set_fighter_status_data)]
unsafe fn set_fighter_status_data_hook(boma: &mut BattleObjectModuleAccessor, arg2: bool, treaded_kind: i32, arg4: bool, arg5: bool, arg6: bool, log_mask_flag: u64, status_attr: u32, power_up_attack_bit: u32, arg10: u32) {
let bo = boma.object();
if (VarModule::has_var_module(bo)) {
let bit_last = VarModule::get_int(bo, vars::common::instance::POWER_UP_BIT_LAST) as u32;
if (power_up_attack_bit != bit_last) {
GLOBAL_SEED += 1;
let new_seed = GLOBAL_SEED % MAX_SEED;
VarModule::set_int(boma.object(), vars::common::instance::ATTACK_LOG_SEED, new_seed as i32);
//println!("Seed Update {} | BIT: {} \n", new_seed, power_up_attack_bit);
}
VarModule::set_int(boma.object(), vars::common::instance::POWER_UP_BIT_LAST, power_up_attack_bit as i32);
}
return original!()(boma, arg2, treaded_kind, arg4, arg5, arg6, log_mask_flag, status_attr, power_up_attack_bit, arg10);
}

pub fn install() {
// skyline::install_hooks!(
// set_fighter_status_data_hook,
// );
}
skyline::install_hooks!(set_fighter_status_data_hook);
}
Loading
Loading