From 1b0f755c4b5d785b62780a8aa40a482b1c625ab4 Mon Sep 17 00:00:00 2001 From: Brian Allred Date: Mon, 5 Oct 2026 16:20:34 -0500 Subject: [PATCH 01/20] Fix controls SP under ozone --- fighters/common/src/function_hooks/controls.rs | 2 +- fighters/common/src/misc.rs | 2 +- src/lua.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fighters/common/src/function_hooks/controls.rs b/fighters/common/src/function_hooks/controls.rs index d8bec849fa..99e808e527 100644 --- a/fighters/common/src/function_hooks/controls.rs +++ b/fighters/common/src/function_hooks/controls.rs @@ -1093,7 +1093,7 @@ static mut GC_TRIGGERS: [f32; 2] = [0.0, 0.0]; #[skyline::hook(offset = 0x366745c, inline)] unsafe fn post_gamecube_process(ctx: &skyline::hooks::InlineCtx) { let state: *mut skyline::nn::hid::NpadGcState = - (ctx as *const _ as *mut u8).add(0x300) as *mut _; + (ctx.sp.x() as *const u8) as *mut _; let controller: *mut Controller = ctx.registers[19].x() as _; GC_TRIGGERS[0] = (*state).LTrigger as f32 / i16::MAX as f32; diff --git a/fighters/common/src/misc.rs b/fighters/common/src/misc.rs index ae8c659165..dc6ddc6b45 100644 --- a/fighters/common/src/misc.rs +++ b/fighters/common/src/misc.rs @@ -16,7 +16,7 @@ use globals::*; #[skyline::hook(offset = 0xf13ddc, inline)] unsafe fn steve_parry_stuff_fix(ctx: &mut skyline::hooks::InlineCtx) { if ctx.registers[0].x() == 0x1D { - *((ctx as *mut _ as *mut u8).add(0x300).add(0x98) as *mut u32) = 0x1; + *((ctx.sp.x() as *const u8).add(0x98) as *mut u32) = 0x1; } } diff --git a/src/lua.rs b/src/lua.rs index 1fb3a28cc8..bcb4b0609b 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -416,7 +416,7 @@ unsafe fn set_pane_text_values(ctx: &skyline::hooks::InlineCtx) { #[skyline::hook(offset = 0x1d33b60, inline)] unsafe fn set_parry_button_shield_text(ctx: &skyline::hooks::InlineCtx) { - let sp = (ctx as *const _ as *const u8).add(0x300); + let sp = ctx.sp.x() as *const u8; let ptr = *(sp.add(0xa8) as *const u64); if ctx.registers[22].x() == 4 { @@ -429,7 +429,7 @@ unsafe fn set_parry_button_shield_text(ctx: &skyline::hooks::InlineCtx) { #[skyline::hook(offset = 0x1d33ca0, inline)] unsafe fn set_parry_button_taunt_text(ctx: &skyline::hooks::InlineCtx) { - let sp = (ctx as *const _ as *const u8).add(0x300); + let sp = ctx.sp.x() as *const u8; let ptr = *(sp.add(0xa8) as *const u64); if ctx.registers[22].x() == 4 { From d04d7a7f932fbaa08fa1cc83ac58d2ec34fa85a5 Mon Sep 17 00:00:00 2001 From: SuddyN Date: Thu, 8 Oct 2026 22:01:26 -0400 Subject: [PATCH 02/20] link shield fixes --- fighters/link/src/acmd/ground.rs | 13 ++++++++++--- fighters/link/src/acmd/other.rs | 23 +++++++++++++++++++++++ fighters/link/src/opff.rs | 19 +++++++++++++++++-- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/fighters/link/src/acmd/ground.rs b/fighters/link/src/acmd/ground.rs index 16997bc547..26bc9a06d3 100644 --- a/fighters/link/src/acmd/ground.rs +++ b/fighters/link/src/acmd/ground.rs @@ -134,17 +134,24 @@ unsafe extern "C" fn expression_attack13(agent: &mut L2CAgentBase) { unsafe extern "C" fn game_attackdash(agent: &mut L2CAgentBase) { let lua_state = agent.lua_state_agent; let boma = agent.boma(); + frame(lua_state, 3.0); + if is_excute(agent) { + WorkModule::on_flag(boma, *FIGHTER_LINK_INSTANCE_WORK_ID_FLAG_WAIT_SHIELD); + HIT_NODE(agent, Hash40::new("head"), *HIT_STATUS_XLU); + HIT_NODE(agent, Hash40::new("shoulderl"), *HIT_STATUS_XLU); + HIT_NODE(agent, Hash40::new("arml"), *HIT_STATUS_XLU); + } frame(lua_state, 7.0); sv_kinetic_energy!(set_speed_mul, agent, FIGHTER_KINETIC_ENERGY_ID_MOTION, 0.93); if is_excute(agent) { - WorkModule::on_flag(boma, *FIGHTER_LINK_INSTANCE_WORK_ID_FLAG_WAIT_SHIELD); - ATTACK(agent, 0, 0, Hash40::new("top"), 12.0, 70, 93, 0, 40, 3.5, 0.0, 4.0, 6.0, Some(0.0), Some(10.0), Some(6.0), 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_F, false, 3, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_OBJECT); + HitModule::set_status_all(boma, HitStatus(*HIT_STATUS_NORMAL), 0); + ATTACK(agent, 0, 0, Hash40::new("top"), 12.0, 60, 93, 0, 40, 3.5, 0.0, 4.0, 6.0, Some(0.0), Some(10.0), Some(6.0), 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_F, false, 3, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_OBJECT); } frame(lua_state, 9.0); sv_kinetic_energy!(set_speed_mul, agent, FIGHTER_KINETIC_ENERGY_ID_MOTION, 1.0); frame(lua_state, 10.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("top"), 9.0, 62, 55, 0, 45, 5.5, 0.0, 8.5, 4.0, Some(0.0), Some(8.5), Some(4.75), 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_F, false, 3, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_PUNCH, *ATTACK_REGION_OBJECT); + ATTACK(agent, 0, 0, Hash40::new("top"), 9.0, 60, 55, 0, 45, 5.5, 0.0, 8.5, 4.0, Some(0.0), Some(8.5), Some(4.75), 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_PUNCH, *ATTACK_REGION_OBJECT); } frame(lua_state, 15.0); if is_excute(agent) { diff --git a/fighters/link/src/acmd/other.rs b/fighters/link/src/acmd/other.rs index a8001c2067..aab551ec70 100644 --- a/fighters/link/src/acmd/other.rs +++ b/fighters/link/src/acmd/other.rs @@ -226,6 +226,26 @@ unsafe extern "C" fn effect_win3(agent: &mut L2CAgentBase) { } } +unsafe extern "C" fn game_squat(agent: &mut L2CAgentBase) { + let lua_state = agent.lua_state_agent; + let boma = agent.boma(); + if is_excute(agent) { + WorkModule::on_flag(boma, *FIGHTER_LINK_INSTANCE_WORK_ID_FLAG_WAIT_SHIELD); + } + frame(lua_state, 7.0); + if is_excute(agent) { + WorkModule::on_flag(boma, *FIGHTER_STATUS_WORK_ID_FLAG_RESERVE_CHANGE_STATUS_DLAY_MOTION); + } +} + +unsafe extern "C" fn game_squatrv(agent: &mut L2CAgentBase) { + let lua_state = agent.lua_state_agent; + let boma = agent.boma(); + if is_excute(agent) { + WorkModule::on_flag(boma, *FIGHTER_LINK_INSTANCE_WORK_ID_FLAG_WAIT_SHIELD); + } +} + pub fn install(agent: &mut Agent) { agent.acmd("game_cliffescape", acmd_stub, Priority::Low); @@ -252,4 +272,7 @@ pub fn install(agent: &mut Agent) { agent.acmd("effect_win1", effect_win1, Priority::Low); agent.acmd("effect_win3", effect_win3, Priority::Low); + + agent.acmd("game_squat", game_squat, Priority::Low); + agent.acmd("game_squatrv", game_squatrv, Priority::Low); } diff --git a/fighters/link/src/opff.rs b/fighters/link/src/opff.rs index 5882f28d75..729ca378c0 100644 --- a/fighters/link/src/opff.rs +++ b/fighters/link/src/opff.rs @@ -18,21 +18,36 @@ unsafe fn fastfall_specials(fighter: &mut L2CFighterCommon) { } } -unsafe fn bomb_cancel(fighter: &mut smash::lua2cpp::L2CFighterCommon) { +unsafe fn bomb_cancel(fighter: &mut smash::lua2cpp::L2CFighterCommon) { if VarModule::is_flag(fighter.battle_object, vars::link::status::ENABLE_SPECIAL_LW_CANCEL) && AttackModule::is_infliction_status(fighter.module_accessor, *COLLISION_KIND_MASK_HIT) && ArticleModule::is_exist(fighter.module_accessor, *FIGHTER_LINK_GENERATE_ARTICLE_LINKBOMB) && fighter.is_cat_flag(Cat1::SpecialLw) { // let bomb_exists = ArticleModule::is_exist(fighter.module_accessor, *FIGHTER_LINK_GENERATE_ARTICLE_LINKBOMB); // println!("Bomb Exists: {}", bomb_exists); - fighter.change_status_req(*FIGHTER_STATUS_KIND_SPECIAL_LW, true); { + fighter.change_status_req(*FIGHTER_STATUS_KIND_SPECIAL_LW, true); } } + +unsafe fn shield_scale_fix(fighter: &mut smash::lua2cpp::L2CFighterCommon) { + if !fighter.is_status_one_of(&[ + *FIGHTER_STATUS_KIND_ATTACK_DASH, + *FIGHTER_STATUS_KIND_SQUAT, + *FIGHTER_STATUS_KIND_SQUAT_RV, + ]) { + return; + } + + if let Some(target) = smashline::api::get_target_function("lua2cpp_link.nrs", 0x6e40) { + let shield_set_scale: extern "C" fn(&mut L2CFighterCommon) = std::mem::transmute(target); + shield_set_scale(fighter); + } } pub unsafe fn moveset(fighter: &mut L2CFighterCommon, boma: &mut BattleObjectModuleAccessor, id: usize, cat: [i32 ; 4], status_kind: i32, situation_kind: i32, motion_kind: u64, stick_x: f32, stick_y: f32, facing: f32, frame: f32) { fastfall_specials(fighter); bomb_cancel(fighter); + shield_scale_fix(fighter); } pub extern "C" fn link_frame_wrapper(fighter: &mut smash::lua2cpp::L2CFighterCommon) { From 9f7b5e6d31170618a13c7abb6c0d8ca2eb20faaf Mon Sep 17 00:00:00 2001 From: SuddyN Date: Thu, 8 Oct 2026 22:01:44 -0400 Subject: [PATCH 03/20] link FAir buff --- fighters/link/src/acmd/aerials.rs | 16 ++++++++-------- .../fighter/common/param/fighter_param.prcxml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fighters/link/src/acmd/aerials.rs b/fighters/link/src/acmd/aerials.rs index 9b554a67cc..2a85df5698 100644 --- a/fighters/link/src/acmd/aerials.rs +++ b/fighters/link/src/acmd/aerials.rs @@ -47,10 +47,10 @@ unsafe extern "C" fn game_attackairf(agent: &mut L2CAgentBase) { frame(lua_state, 13.0); FT_MOTION_RATE(agent, 1.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 12.0, 361, 103, 0, 30, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 30, 3.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 30, 3.5, 4.25, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 30, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 12.0, 361, 103, 0, 30, 3.0, -1.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 12.0, 361, 100, 0, 30, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 30, 3.5, 4.2, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 30, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); } frame(lua_state, 16.0); FT_MOTION_RATE_RANGE(agent, 16.0, 20.0, 7.0); @@ -61,10 +61,10 @@ unsafe extern "C" fn game_attackairf(agent: &mut L2CAgentBase) { FT_MOTION_RATE(agent, 1.0); frame(lua_state, 21.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 9.0, 68, 65, 0, 43, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 2, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 10.0, 68, 65, 0, 43, 3.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 2, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 10.0, 68, 65, 0, 43, 3.5, 4.25, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 2, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 10.0, 68, 65, 0, 43, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 2, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 9.0, 68, 65, 0, 43, 3.0, -1.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 68, 65, 0, 43, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 10.0, 68, 65, 0, 43, 3.5, 4.2, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 10.0, 68, 65, 0, 43, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); } frame(lua_state, 24.0); if is_excute(agent) { diff --git a/romfs/source/fighter/common/param/fighter_param.prcxml b/romfs/source/fighter/common/param/fighter_param.prcxml index 1269fca8ba..8bc33ddab4 100644 --- a/romfs/source/fighter/common/param/fighter_param.prcxml +++ b/romfs/source/fighter/common/param/fighter_param.prcxml @@ -97,7 +97,7 @@ 2.13 104 8 - 10 + 8 7 14 18 From d864c4456a22474b5cddb7e27779a2b8942d42ec Mon Sep 17 00:00:00 2001 From: SuddyN Date: Thu, 8 Oct 2026 22:01:54 -0400 Subject: [PATCH 04/20] link NAir activity buff --- fighters/link/src/acmd/aerials.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fighters/link/src/acmd/aerials.rs b/fighters/link/src/acmd/aerials.rs index 2a85df5698..563a26e27f 100644 --- a/fighters/link/src/acmd/aerials.rs +++ b/fighters/link/src/acmd/aerials.rs @@ -22,12 +22,9 @@ unsafe extern "C" fn game_attackairn(agent: &mut L2CAgentBase) { ATTACK(agent, 1, 0, Hash40::new("kneer"), 8.0, 361, 100, 0, 10, 4.0, 3.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); ATTACK(agent, 2, 0, Hash40::new("kneel"), 8.0, 361, 100, 0, 10, 3.5, 1.75, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); } - frame(lua_state, 28.0); - if is_excute(agent) { - AttackModule::clear_all(boma); - } frame(lua_state, 34.0); if is_excute(agent) { + AttackModule::clear_all(boma); VarModule::on_flag(agent.battle_object, vars::link::status::ENABLE_SPECIAL_LW_CANCEL); } frame(lua_state, 36.0); From a24cd8f2920242b2eccf8fc9ceee907eac3c3533 Mon Sep 17 00:00:00 2001 From: SuddyN Date: Fri, 9 Oct 2026 15:40:26 -0400 Subject: [PATCH 05/20] fuse arrow initial reimplementation --- dynamic/src/consts.rs | 45 +++ fighters/common/src/opff/fuse.rs | 325 ++++++++++++++++++ fighters/common/src/opff/mod.rs | 1 + fighters/dedede/src/opff.rs | 8 +- fighters/kirby/src/opff.rs | 8 +- .../kirby/src/status/copy/link_special_n.rs | 18 + fighters/kirby/src/status/copy/mod.rs | 2 + fighters/link/src/bowarrow/mod.rs | 11 + fighters/link/src/bowarrow/opff.rs | 27 ++ fighters/link/src/bowarrow/status.rs | 153 +++++++++ fighters/link/src/lib.rs | 2 + fighters/link/src/status/special_n.rs | 12 + fighters/murabito/src/opff.rs | 6 + fighters/rosetta/src/opff.rs | 8 +- fighters/shizue/src/opff.rs | 6 + 15 files changed, 629 insertions(+), 3 deletions(-) create mode 100644 fighters/common/src/opff/fuse.rs create mode 100644 fighters/kirby/src/status/copy/link_special_n.rs create mode 100644 fighters/link/src/bowarrow/mod.rs create mode 100644 fighters/link/src/bowarrow/opff.rs create mode 100644 fighters/link/src/bowarrow/status.rs diff --git a/dynamic/src/consts.rs b/dynamic/src/consts.rs index d33b18baa9..2d8223d8c7 100644 --- a/dynamic/src/consts.rs +++ b/dynamic/src/consts.rs @@ -563,6 +563,14 @@ pub mod vars { //floats pub const SPECIAL_N_STICK_Y: i32 = 0x0105; pub const SPECIAL_S_TOSS_LR: i32 = 0x0106; + + // link arrow fuse + // flags + pub const FUSE_ITEM: i32 = 0x0107; + pub const FUSE_ITEM_CHECKED: i32 = 0x0109; + + // ints + pub const FUSED_ITEM_KIND: i32 = 0x0108; } pub mod status{ //flags @@ -919,6 +927,11 @@ pub mod vars { pub const SPECIAL_N_PTRAINER_PLEDGE_STATE: i32 = 0x01F6; // Unique var as it doesn't like borrowing from ptrainer pub const SPECIAL_N_PTRAINER_PLEDGE_EFFECT_HANDLE: i32 = 0x01F7; + // link arrow fuse + pub const IS_ARROW_FUSE: i32 = 0x01F9; // flag + pub const FUSED_ITEM_ID: i32 = 0x01F8; + pub const TEAM_NO: i32 = 0x01F9; + pub use super::super::bayonetta::instance::SPECIAL_N_CANCEL_TYPE; pub use super::super::ptrainer::instance::SPECIAL_N_PLEDGE_TIMER; @@ -1008,12 +1021,34 @@ pub mod vars { } pub mod link { + pub mod instance { + // flags + pub const IS_ARROW_FUSE: i32 = 0x0100; + + // ints + pub const FUSED_ITEM_ID: i32 = 0x0100; + pub const TEAM_NO: i32 = 0x0101; + } pub mod status { // flags pub const ENABLE_SPECIAL_LW_CANCEL: i32 = 0x1000; } } + pub mod link_bowarrow { + pub mod instance { + // flags + pub const IS_ARROW_FUSE: i32 = 0x0100; + pub const IS_REFLECT_FIX: i32 = 0x0101; + + // ints + pub const FUSED_ITEM_KIND: i32 = 0x0100; + pub const FUSED_ITEM_TYPE: i32 = 0x0101; + pub const FUSED_ITEM_POST_STATUS: i32 = 0x0102; + pub const FUSED_ITEM_ID: i32 = 0x0103; + } + } + pub mod littlemac { pub mod instance { // flags @@ -1372,6 +1407,11 @@ pub mod vars { // ints pub const ATTACK_AIR_HI_TURNIP_COUNT: i32 = 0x0104; pub const ATTACK_AIR_LW_TURNIP_COUNT: i32 = 0x0105; + + // link arrow fuse + pub const FUSED_ITEM_KIND: i32 = 0x0106; + pub const TEAM_NO: i32 = 0x0107; + pub const FUSE_POCKET_TARGET_ID: i32 = 0x0108; } } @@ -1881,6 +1921,11 @@ pub mod vars { // ints pub const SPECIAL_LW_LLOID_TIMER: i32 = 0x0100; + + // link arrow fuse + pub const FUSED_ITEM_KIND: i32 = 0x0101; + pub const TEAM_NO: i32 = 0x0102; + pub const FUSE_POCKET_TARGET_ID: i32 = 0x0103; } pub mod status { // flags diff --git a/fighters/common/src/opff/fuse.rs b/fighters/common/src/opff/fuse.rs new file mode 100644 index 0000000000..7546fcfa25 --- /dev/null +++ b/fighters/common/src/opff/fuse.rs @@ -0,0 +1,325 @@ +use super::*; +use globals::*; +use smash::app::utility; + +#[repr(C)] +pub struct CreateItemParam { + founder_pos: Vector4f, + item_pos: Vector4f, + item_kind: ItemKind, + another_battle_object_id: u32, + variation_kind: i32, + lr_dir: f32, + owner_id: u32, + unk_20: u32, + pokeball_or_assist_kind: i32, + unk_3c: f32, + unk_40: u32, + unk_44: u32, + unk_48: f32, + unk_4c: u32 +} + +#[skyline::from_offset(0x15db0b0)] +unsafe fn create_item(item_manager: *const smash_rs::app::ItemManager, create_item_param: *mut CreateItemParam, unk: bool, unk2: bool, unk3: bool) -> *mut BattleObject; + +unsafe fn get_owner(weapon_boma: *mut BattleObjectModuleAccessor) -> (*mut BattleObjectModuleAccessor, *mut BattleObject, i32) { + let owner_id = WorkModule::get_int(weapon_boma, *WEAPON_INSTANCE_WORK_ID_INT_LINK_OWNER) as u32; + let owner_boma = sv_battle_object::module_accessor(owner_id); + let owner_object = get_battle_object_from_id(owner_id); + let owner_kind = utility::get_kind(&mut *owner_boma); + (owner_boma, owner_object, owner_kind) +} + +unsafe fn owner_team_no_var(owner_kind: i32) -> i32 { + if owner_kind == *FIGHTER_KIND_MURABITO { + vars::murabito::instance::TEAM_NO + } + else if owner_kind == *FIGHTER_KIND_SHIZUE { + vars::shizue::instance::TEAM_NO + } + else if owner_kind == *FIGHTER_KIND_KIRBY { + vars::kirby::instance::TEAM_NO + } + else { + vars::link::instance::TEAM_NO + } +} + +// returns the boma and object of the given id if it is an active Link arrow +unsafe fn get_arrow(object_id: u32) -> Option<(*mut BattleObjectModuleAccessor, *mut BattleObject)> { + if object_id == *BATTLE_OBJECT_ID_INVALID as u32 || !sv_battle_object::is_active(object_id) { + return None; + } + let boma = sv_battle_object::module_accessor(object_id); + if utility::get_category(&mut *boma) != *BATTLE_OBJECT_CATEGORY_WEAPON + || utility::get_kind(&mut *boma) != *WEAPON_KIND_LINK_BOWARROW { + return None; + } + Some((boma, get_battle_object_from_id(object_id))) +} + +// returns the team the arrow's owner had when the arrow was fused +#[no_mangle] +pub unsafe extern "Rust" fn fuse_get_owner_team_no(weapon_boma: *mut BattleObjectModuleAccessor) -> i32 { + let (_, owner_object, owner_kind) = get_owner(weapon_boma); + VarModule::get_int(owner_object, owner_team_no_var(owner_kind)) +} + +// unlinks an item from whatever it is attached to, returning whether it was attached +#[no_mangle] +pub unsafe extern "Rust" fn fuse_detach_item(item_boma: *mut BattleObjectModuleAccessor) -> bool { + LinkModule::remove_model_constraint(item_boma, true); + if LinkModule::is_link(item_boma, *ITEM_LINK_NO_HAVE) { + LinkModule::unlink_all(item_boma); + return true; + } + false +} + +// attaches an item to the arrow's "top" bone, returning whether it was newly attached +#[no_mangle] +pub unsafe extern "Rust" fn fuse_attach_item(item_boma: *mut BattleObjectModuleAccessor, arrow_id: u32) -> bool { + if !LinkModule::is_link(item_boma, *ITEM_LINK_NO_HAVE) { + VisibilityModule::set_whole(item_boma, true); + LinkModule::link(item_boma, *ITEM_LINK_NO_HAVE, arrow_id); + LinkModule::set_model_constraint_pos_ort(item_boma, *ITEM_LINK_NO_HAVE, Hash40::new("top"), Hash40::new("top"), (*CONSTRAINT_FLAG_ORIENTATION | *CONSTRAINT_FLAG_POSITION) as u32, true); + return true; + } + false +} + +// deletes the item fused to an arrow, if any +#[no_mangle] +pub unsafe extern "Rust" fn fuse_remove_item(arrow_object: *mut BattleObject) { + if !VarModule::is_flag(arrow_object, vars::link_bowarrow::instance::IS_ARROW_FUSE) { + return; + } + let item_id = VarModule::get_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_ID) as u32; + if sv_battle_object::is_active(item_id) { + smash_rs::app::ItemManager::instance().unwrap().remove_item_from_id(item_id); + } + VarModule::off_flag(arrow_object, vars::link_bowarrow::instance::IS_ARROW_FUSE); +} + +// stores the fused item's info on the arrow/owner +// pass ITEM_KIND_NONE / BATTLE_OBJECT_ID_INVALID to use the item the owner is currently holding. +#[no_mangle] +pub unsafe extern "Rust" fn fuse_set_arrow_params(arrow_boma: *mut BattleObjectModuleAccessor, item: i32, id: u32) { + let (owner_boma, owner_object, owner_kind) = get_owner(arrow_boma); + let arrow_object = get_battle_object_from_id((*arrow_boma).battle_object_id); + + let kind = if item == *ITEM_KIND_NONE { + ItemModule::get_have_item_kind(owner_boma, 0) + } + else { + item + }; + let item_id = if id == *BATTLE_OBJECT_ID_INVALID as u32 { + ItemModule::get_have_item_id(owner_boma, 0) as u32 + } + else { + id + }; + + VarModule::set_int(owner_object, owner_team_no_var(owner_kind), TeamModule::team_no(owner_boma) as i32); + if owner_kind == *FIGHTER_KIND_LINK { + VarModule::set_int(owner_object, vars::link::instance::FUSED_ITEM_ID, item_id as i32); + } + else if owner_kind == *FIGHTER_KIND_KIRBY { + VarModule::set_int(owner_object, vars::kirby::instance::FUSED_ITEM_ID, item_id as i32); + } + + // 0: item travels with the arrow normally + // 1: arrow is fired straight and fast + let (item_type, post_status) = if kind == *ITEM_KIND_BOMBER { + (0, *ITEM_BOMBER_STATUS_KIND_BORN2) + } + else if [*ITEM_KIND_KILLER, *ITEM_KIND_BANANAGUN, *ITEM_KIND_DOLPHINBOMB].contains(&kind) { + (1, *ITEM_STATUS_KIND_THROW) + } + else if kind == *ITEM_KIND_LINKBOMB { + (0, *ITEM_STATUS_KIND_BORN) + } + else { + (0, *ITEM_STATUS_KIND_THROW) + }; + VarModule::set_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_KIND, kind); + VarModule::set_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_TYPE, item_type); + VarModule::set_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_POST_STATUS, post_status); + VarModule::set_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_ID, item_id as i32); +} + +// spawns a new item of the given kind and fuses it to the given arrow +#[no_mangle] +pub unsafe extern "Rust" fn fuse_create_item(arrow_boma: *mut BattleObjectModuleAccessor, item: i32, founder_boma: *mut BattleObjectModuleAccessor, owner_id: u32) { + let pos = Vector4f{x: PostureModule::pos_x(founder_boma), y: PostureModule::pos_y(founder_boma), z: PostureModule::pos_z(founder_boma), w: 0.0}; + let mut params = CreateItemParam { + founder_pos: pos, + item_pos: pos, + item_kind: ItemKind(item), + another_battle_object_id: *BATTLE_OBJECT_ID_INVALID as u32, + variation_kind: *ITEM_VARIATION_NONE, + lr_dir: PostureModule::lr(founder_boma), + owner_id: owner_id, + unk_20: 20, + pokeball_or_assist_kind: *ITEM_KIND_NONE, + unk_3c: 0.0, + unk_40: 0, + unk_44: 0, + unk_48: 1.0, + unk_4c: 0x63 + }; + let item_manager = smash_rs::app::ItemManager::instance().unwrap(); + let battle_object = create_item(item_manager, &mut params, false, false, false); + if battle_object.is_null() { + return; + } + let item_boma = (*battle_object).module_accessor; + if ![*ITEM_KIND_HEALBALL, *ITEM_KIND_CHEWING, *ITEM_KIND_BOOMERANG].contains(&item) { + StatusModule::change_status_request(item_boma, *ITEM_STATUS_KIND_HAVE, false); + } + if item == *ITEM_KIND_LINKBOMB { + PostureModule::set_scale(item_boma, 1.3, false); + } + LinkModule::remove_model_constraint(item_boma, true); + fuse_attach_item(item_boma, (*arrow_boma).battle_object_id); + let arrow_object = get_battle_object_from_id((*arrow_boma).battle_object_id); + VarModule::on_flag(arrow_object, vars::link_bowarrow::instance::IS_ARROW_FUSE); + fuse_set_arrow_params(arrow_boma, item, (*item_boma).battle_object_id); +} + +// ddd re-creates the fused item when spitting the arrow back out +#[no_mangle] +pub unsafe extern "Rust" fn fuse_dedede_common(fighter: &mut L2CFighterCommon) { + if !fighter.is_status(*FIGHTER_DEDEDE_STATUS_KIND_SPECIAL_N_SHOT_OBJECT_HIT) { + VarModule::off_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM); + VarModule::off_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM_CHECKED); + return; + } + let obj_id = WorkModule::get_int(fighter.module_accessor, *FIGHTER_DEDEDE_STATUS_SPECIAL_N_WORK_INT_SHOT_OBJECT_ID) as u32; + let (obj_boma, obj_object) = match get_arrow(obj_id) { + Some(arrow) => arrow, + None => return + }; + + if WorkModule::is_flag(fighter.module_accessor, *FIGHTER_DEDEDE_STATUS_SPECIAL_N_FLAG_SHOT_OBJECT_SHOOT) + && !VarModule::is_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM_CHECKED) { + VarModule::on_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM_CHECKED); + if VarModule::is_flag(obj_object, vars::link_bowarrow::instance::IS_ARROW_FUSE) { + // skip if the arrow still carries its item + let fused_item_id = VarModule::get_int(obj_object, vars::link_bowarrow::instance::FUSED_ITEM_ID) as u32; + let is_fused_item_attached = sv_battle_object::is_active(fused_item_id) + && LinkModule::is_link(sv_battle_object::module_accessor(fused_item_id), *ITEM_LINK_NO_HAVE); + if !is_fused_item_attached { + let fused_item = VarModule::get_int(obj_object, vars::link_bowarrow::instance::FUSED_ITEM_KIND); + VarModule::set_int(fighter.battle_object, vars::dedede::instance::FUSED_ITEM_KIND, fused_item); + VarModule::on_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM); + } + } + } + + if VarModule::is_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM) + && MotionModule::frame(fighter.module_accessor) >= 7.0 { + let item = VarModule::get_int(fighter.battle_object, vars::dedede::instance::FUSED_ITEM_KIND); + fuse_create_item(obj_boma, item, fighter.module_accessor, (*fighter.module_accessor).battle_object_id); + VarModule::set_int(fighter.battle_object, vars::dedede::instance::FUSED_ITEM_KIND, *ITEM_KIND_NONE); + VarModule::off_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM); + } +} + +// villager/isabelle store the fused item when pocketing the arrow, and delete the original +// the item is re-created when the arrow is pulled back out +#[no_mangle] +pub unsafe extern "Rust" fn fuse_pocket_common(fighter: &mut L2CFighterCommon) { + let (fused_item_kind_var, team_no_var, target_id_var) = if fighter.kind() == *FIGHTER_KIND_SHIZUE { + (vars::shizue::instance::FUSED_ITEM_KIND, vars::shizue::instance::TEAM_NO, vars::shizue::instance::FUSE_POCKET_TARGET_ID) + } + else { + (vars::murabito::instance::FUSED_ITEM_KIND, vars::murabito::instance::TEAM_NO, vars::murabito::instance::FUSE_POCKET_TARGET_ID) + }; + + // the pocket is lost on death + if fighter.is_status(*FIGHTER_STATUS_KIND_DEAD) { + VarModule::set_int(fighter.battle_object, fused_item_kind_var, *ITEM_KIND_NONE); + } + if !fighter.is_status(*FIGHTER_MURABITO_STATUS_KIND_SPECIAL_N_SEARCH) { + VarModule::set_int(fighter.battle_object, target_id_var, *BATTLE_OBJECT_ID_INVALID); + return; + } + + let obj_id = WorkModule::get_int(fighter.module_accessor, *FIGHTER_MURABITO_INSTANCE_WORK_ID_INT_TARGET_OBJECT_ID) as u32; + if obj_id == *BATTLE_OBJECT_ID_INVALID as u32 + || obj_id == VarModule::get_int(fighter.battle_object, target_id_var) as u32 { + return; + } + + // handle each pocketed object once, replacing whatever fused item was stored before + VarModule::set_int(fighter.battle_object, target_id_var, obj_id as i32); + VarModule::set_int(fighter.battle_object, fused_item_kind_var, *ITEM_KIND_NONE); + let obj_object = match get_arrow(obj_id) { + Some((_, obj_object)) => obj_object, + None => return + }; + + VarModule::set_int(fighter.battle_object, team_no_var, TeamModule::team_no(fighter.module_accessor) as i32); + if VarModule::is_flag(obj_object, vars::link_bowarrow::instance::IS_ARROW_FUSE) { + let fused_item = VarModule::get_int(obj_object, vars::link_bowarrow::instance::FUSED_ITEM_KIND); + VarModule::set_int(fighter.battle_object, fused_item_kind_var, fused_item); + fuse_remove_item(obj_object); + } +} + +// kirby's inhale deletes the fused item +#[no_mangle] +pub unsafe extern "Rust" fn fuse_kirby_common(fighter: &mut L2CFighterCommon) { + if !fighter.is_status(*FIGHTER_KIRBY_STATUS_KIND_SPECIAL_N_LOOP) { + return; + } + let obj_id = WorkModule::get_int(fighter.module_accessor, *FIGHTER_KIRBY_STATUS_SPECIAL_N_WORK_INT_INHALE_OBJECT_ID) as u32; + if let Some((_, obj_object)) = get_arrow(obj_id) { + fuse_remove_item(obj_object); + } +} + +// rosalina's gravitational pull deletes the fused item +#[no_mangle] +pub unsafe extern "Rust" fn fuse_rosetta_common(fighter: &mut L2CFighterCommon) { + if !fighter.is_status(*FIGHTER_STATUS_KIND_SPECIAL_LW) { + return; + } + let obj_id = WorkModule::get_int(fighter.module_accessor, *FIGHTER_ROSETTA_STATUS_SPECIAL_LW_INT_CAPTURE_OBJECT_ID) as u32; + if let Some((_, obj_object)) = get_arrow(obj_id) { + fuse_remove_item(obj_object); + } +} + +// drops the fused item if Link's (or Kirby's) NSpecial ends before the arrow is fired +#[no_mangle] +pub unsafe extern "Rust" fn fuse_special_n_exit(fighter: &mut L2CFighterCommon) { + let (is_arrow_fuse_var, fused_item_id_var) = if fighter.kind() == *FIGHTER_KIND_KIRBY { + (vars::kirby::instance::IS_ARROW_FUSE, vars::kirby::instance::FUSED_ITEM_ID) + } + else { + (vars::link::instance::IS_ARROW_FUSE, vars::link::instance::FUSED_ITEM_ID) + }; + + if VarModule::is_flag(fighter.battle_object, is_arrow_fuse_var) + && ArticleModule::is_exist(fighter.module_accessor, *FIGHTER_LINK_GENERATE_ARTICLE_BOWARROW) { + let article = ArticleModule::get_article(fighter.module_accessor, *FIGHTER_LINK_GENERATE_ARTICLE_BOWARROW); + if !article.is_null() { + let arrow_id = smash::app::lua_bind::Article::get_battle_object_id(article) as u32; + if sv_battle_object::is_active(arrow_id) { + VarModule::off_flag(get_battle_object_from_id(arrow_id), vars::link_bowarrow::instance::IS_ARROW_FUSE); + } + } + let item_id = VarModule::get_int(fighter.battle_object, fused_item_id_var) as u32; + if sv_battle_object::is_active(item_id) { + let item_boma = sv_battle_object::module_accessor(item_id); + if fuse_detach_item(item_boma) { + StatusModule::change_status_request(item_boma, *ITEM_STATUS_KIND_FALL, false); + } + } + } + VarModule::off_flag(fighter.battle_object, is_arrow_fuse_var); +} diff --git a/fighters/common/src/opff/mod.rs b/fighters/common/src/opff/mod.rs index 53ebdd5f34..068df49c55 100644 --- a/fighters/common/src/opff/mod.rs +++ b/fighters/common/src/opff/mod.rs @@ -18,6 +18,7 @@ pub mod floats; pub mod other; pub mod fe; pub mod pocket; +pub mod fuse; use other::*; diff --git a/fighters/dedede/src/opff.rs b/fighters/dedede/src/opff.rs index 67d3dd7e6b..73009ff432 100644 --- a/fighters/dedede/src/opff.rs +++ b/fighters/dedede/src/opff.rs @@ -313,10 +313,16 @@ pub unsafe fn moveset(fighter: &mut L2CFighterCommon, boma: &mut BattleObjectMod jet_hammer_charge(fighter, motion_kind); } +// symbol-based call for link's arrow fuse +extern "Rust" { + fn fuse_dedede_common(fighter: &mut smash::lua2cpp::L2CFighterCommon); +} + pub extern "C" fn dedede_frame_wrapper(fighter: &mut smash::lua2cpp::L2CFighterCommon) { unsafe { common::opff::fighter_common_opff(fighter); - dedede_frame(fighter) + dedede_frame(fighter); + fuse_dedede_common(fighter); } } diff --git a/fighters/kirby/src/opff.rs b/fighters/kirby/src/opff.rs index c99a671aee..f8e912c33f 100644 --- a/fighters/kirby/src/opff.rs +++ b/fighters/kirby/src/opff.rs @@ -10,6 +10,11 @@ extern "Rust" { fn gimmick_flash(boma: &mut BattleObjectModuleAccessor); } +// symbol-based call for link's arrow fuse +extern "Rust" { + fn fuse_kirby_common(fighter: &mut L2CFighterCommon); +} + unsafe fn final_cutter_landing_bugfix(fighter: &mut L2CFighterCommon) { if fighter.is_status(*FIGHTER_KIRBY_STATUS_KIND_SPECIAL_HI2) && MotionModule::frame(fighter.module_accessor) <= 2.0 { @@ -108,7 +113,8 @@ pub unsafe fn moveset(fighter: &mut L2CFighterCommon) { pub extern "C" fn kirby_frame_wrapper(fighter: &mut smash::lua2cpp::L2CFighterCommon) { unsafe { common::opff::fighter_common_opff(fighter); - kirby_frame(fighter) + kirby_frame(fighter); + fuse_kirby_common(fighter); } } diff --git a/fighters/kirby/src/status/copy/link_special_n.rs b/fighters/kirby/src/status/copy/link_special_n.rs new file mode 100644 index 0000000000..a6935f4f36 --- /dev/null +++ b/fighters/kirby/src/status/copy/link_special_n.rs @@ -0,0 +1,18 @@ +use super::*; + +// FIGHTER_KIRBY_STATUS_KIND_LINK_SPECIAL_N + +// symbol-based call for link's arrow fuse +extern "Rust" { + fn fuse_special_n_exit(fighter: &mut L2CFighterCommon); +} + +// drops the fused item if the arrow was never fired +unsafe extern "C" fn special_n_exit(fighter: &mut L2CFighterCommon) -> L2CValue { + fuse_special_n_exit(fighter); + smashline::original_status(Exit, fighter, *FIGHTER_KIRBY_STATUS_KIND_LINK_SPECIAL_N)(fighter) +} + +pub fn install(agent: &mut Agent) { + agent.status(Exit, *FIGHTER_KIRBY_STATUS_KIND_LINK_SPECIAL_N, special_n_exit); +} diff --git a/fighters/kirby/src/status/copy/mod.rs b/fighters/kirby/src/status/copy/mod.rs index a3a0705b18..ed282fac86 100644 --- a/fighters/kirby/src/status/copy/mod.rs +++ b/fighters/kirby/src/status/copy/mod.rs @@ -14,6 +14,7 @@ mod ganon_special_n_float; mod gaogaen_special_n; mod koopa_special_n; mod krool_special_n; +mod link_special_n; mod littlemac_special_n; mod lucario_special_n; mod lucas_special_n; @@ -52,6 +53,7 @@ pub fn install(agent: &mut Agent) { gaogaen_special_n::install(agent); koopa_special_n::install(agent); krool_special_n::install(agent); + link_special_n::install(agent); littlemac_special_n::install(agent); lucario_special_n::install(agent); lucas_special_n::install(agent); diff --git a/fighters/link/src/bowarrow/mod.rs b/fighters/link/src/bowarrow/mod.rs new file mode 100644 index 0000000000..e7204573ca --- /dev/null +++ b/fighters/link/src/bowarrow/mod.rs @@ -0,0 +1,11 @@ +use super::*; + +mod opff; +mod status; + +pub fn install() { + let agent = &mut Agent::new("link_bowarrow"); + opff::install(agent); + status::install(agent); + agent.install(); +} diff --git a/fighters/link/src/bowarrow/opff.rs b/fighters/link/src/bowarrow/opff.rs new file mode 100644 index 0000000000..05810b7a03 --- /dev/null +++ b/fighters/link/src/bowarrow/opff.rs @@ -0,0 +1,27 @@ +use super::*; + +// when a fused arrow is reflected, the fused item joins the reflector's team +// the arrow's team is restored to its owner once it sticks (see stick end) +unsafe fn fuse_reflect_fix(weapon: &mut L2CFighterBase) { + if !weapon.is_status(*WN_LINK_BOWARROW_STATUS_KIND_FLY) + || !AttackModule::is_infliction(weapon.module_accessor, *COLLISION_KIND_MASK_REFLECTOR) + || !VarModule::is_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_ARROW_FUSE) { + return; + } + VarModule::on_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_REFLECT_FIX); + let item_id = VarModule::get_int(weapon.battle_object, vars::link_bowarrow::instance::FUSED_ITEM_ID) as u32; + if !sv_battle_object::is_active(item_id) { + return; + } + let item_boma = sv_battle_object::module_accessor(item_id); + TeamModule::set_team(item_boma, TeamModule::team_no(weapon.module_accessor) as i32, true); + TeamModule::set_team_owner_id(item_boma, TeamModule::team_owner_id(weapon.module_accessor) as u32); +} + +pub unsafe extern "C" fn link_bowarrow_frame(weapon: &mut L2CFighterBase) { + fuse_reflect_fix(weapon); +} + +pub fn install(agent: &mut Agent) { + agent.on_line(Main, link_bowarrow_frame); +} diff --git a/fighters/link/src/bowarrow/status.rs b/fighters/link/src/bowarrow/status.rs new file mode 100644 index 0000000000..a3b67ced84 --- /dev/null +++ b/fighters/link/src/bowarrow/status.rs @@ -0,0 +1,153 @@ +use super::*; + +// symbol-based calls for link's arrow fuse +extern "Rust" { + fn fuse_set_arrow_params(arrow_boma: *mut BattleObjectModuleAccessor, item: i32, id: u32); + fn fuse_create_item(arrow_boma: *mut BattleObjectModuleAccessor, item: i32, founder_boma: *mut BattleObjectModuleAccessor, owner_id: u32); + fn fuse_detach_item(item_boma: *mut BattleObjectModuleAccessor) -> bool; + fn fuse_attach_item(item_boma: *mut BattleObjectModuleAccessor, arrow_id: u32) -> bool; + fn fuse_remove_item(arrow_object: *mut BattleObject); + fn fuse_get_owner_team_no(weapon_boma: *mut BattleObjectModuleAccessor) -> i32; +} + +unsafe fn get_owner(weapon_boma: *mut BattleObjectModuleAccessor) -> (*mut BattleObjectModuleAccessor, *mut BattleObject, i32) { + let owner_id = WorkModule::get_int(weapon_boma, *WEAPON_INSTANCE_WORK_ID_INT_LINK_OWNER) as u32; + let owner_boma = sv_battle_object::module_accessor(owner_id); + let owner_object = get_battle_object_from_id(owner_id); + let owner_kind = utility::get_kind(&mut *owner_boma); + (owner_boma, owner_object, owner_kind) +} + +// WN_LINK_BOWARROW_STATUS_KIND_HAVED // + +unsafe extern "C" fn haved_main(weapon: &mut L2CWeaponCommon) -> L2CValue { + let (owner_boma, owner_object, owner_kind) = get_owner(weapon.module_accessor); + let mut is_fused = false; + if ItemModule::is_have_item(owner_boma, 0) { + let kind = ItemModule::get_have_item_kind(owner_boma, 0); + let trait_flag = ItemModule::get_have_item_trait(owner_boma, 0); + // trait flags are bitmasks, so swing/shoot items can carry other bits as well + let is_swing_or_shoot = trait_flag & (*ITEM_TRAIT_FLAG_SWING | *ITEM_TRAIT_FLAG_SHOOT) as u64 != 0; + // projectile items that fire the arrow straight (see fuse_set_arrow_params) + let is_projectile = [*ITEM_KIND_KILLER, *ITEM_KIND_BANANAGUN, *ITEM_KIND_DOLPHINBOMB].contains(&kind); + is_fused = ![*ITEM_KIND_NONE, *ITEM_KIND_ASSIST, *ITEM_KIND_LINKARROW].contains(&kind) + && trait_flag != *ITEM_TRAIT_FLAG_NONE as u64 + && (is_projectile || !is_swing_or_shoot); + if is_fused { + fuse_set_arrow_params(weapon.module_accessor, *ITEM_KIND_NONE, *BATTLE_OBJECT_ID_INVALID as u32); + } + } + VarModule::set_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_ARROW_FUSE, is_fused); + if owner_kind == *FIGHTER_KIND_LINK { + VarModule::set_flag(owner_object, vars::link::instance::IS_ARROW_FUSE, is_fused); + } + else if owner_kind == *FIGHTER_KIND_KIRBY { + VarModule::set_flag(owner_object, vars::kirby::instance::IS_ARROW_FUSE, is_fused); + } + + if is_fused { + // move the held item from the owner's hand onto the arrow + let item_id = VarModule::get_int(weapon.battle_object, vars::link_bowarrow::instance::FUSED_ITEM_ID) as u32; + let item_boma = sv_battle_object::module_accessor(item_id); + fuse_detach_item(item_boma); + if fuse_attach_item(item_boma, (*weapon.module_accessor).battle_object_id) { + // TODO: PLAY_SE(weapon, Hash40::new("se_link_fuse")); + } + MotionModule::change_motion(weapon.module_accessor, Hash40::new("haved"), 0.0, 1.0, false, 0.0, false, false); + } + else { + MotionModule::change_motion(weapon.module_accessor, Hash40::new("haved_hide"), 0.0, 1.0, false, 0.0, false, false); + } + weapon.fastshift(L2CValue::Ptr(haved_main_loop as *const () as _)) +} + +unsafe extern "C" fn haved_main_loop(weapon: &mut L2CWeaponCommon) -> L2CValue { + 0.into() +} + +// re-creates the item stored by Villager/Isabelle when a pocketed fused arrow is pulled back out +unsafe extern "C" fn haved_end(weapon: &mut L2CWeaponCommon) -> L2CValue { + let (owner_boma, owner_object, owner_kind) = get_owner(weapon.module_accessor); + let fused_item_kind_var = if owner_kind == *FIGHTER_KIND_MURABITO { + vars::murabito::instance::FUSED_ITEM_KIND + } + else if owner_kind == *FIGHTER_KIND_SHIZUE { + vars::shizue::instance::FUSED_ITEM_KIND + } + else { + return 0.into(); + }; + let item = VarModule::get_int(owner_object, fused_item_kind_var); + if item != *ITEM_KIND_NONE && item > *ITEM_KIND_ASSIST { + fuse_create_item(weapon.module_accessor, item, weapon.module_accessor, (*owner_boma).battle_object_id); + VarModule::set_int(owner_object, fused_item_kind_var, *ITEM_KIND_NONE); + } + 0.into() +} + +// WN_LINK_BOWARROW_STATUS_KIND_FLY // + +unsafe extern "C" fn fly_init(weapon: &mut L2CWeaponCommon) -> L2CValue { + smashline::original_status(Init, weapon, *WN_LINK_BOWARROW_STATUS_KIND_FLY)(weapon); + if VarModule::is_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_ARROW_FUSE) + && VarModule::get_int(weapon.battle_object, vars::link_bowarrow::instance::FUSED_ITEM_TYPE) == 1 { + // projectile items fly straight and fast, and hit harder + let lr = PostureModule::lr(weapon.module_accessor); + weapon.clear_lua_stack(); + lua_args!(weapon, *WEAPON_KINETIC_ENERGY_RESERVE_ID_NORMAL, 12.0 * lr, 0.0); + sv_kinetic_energy::set_speed(weapon.lua_state_agent); + weapon.clear_lua_stack(); + lua_args!(weapon, *WEAPON_KINETIC_ENERGY_RESERVE_ID_NORMAL, 0.0, 0.0); + sv_kinetic_energy::set_accel(weapon.lua_state_agent); + KineticModule::enable_energy(weapon.module_accessor, *WEAPON_KINETIC_ENERGY_RESERVE_ID_NORMAL); + AttackModule::set_power_mul(weapon.module_accessor, 2.5); + } + 0.into() +} + +unsafe extern "C" fn fly_end(weapon: &mut L2CWeaponCommon) -> L2CValue { + if VarModule::is_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_ARROW_FUSE) { + let status_next = StatusModule::status_kind_next(weapon.module_accessor); + if status_next == *WN_LINK_BOWARROW_STATUS_KIND_STICK + || status_next == *WN_LINK_BOWARROW_STATUS_KIND_HIT_STICK + || AttackModule::is_infliction_status(weapon.module_accessor, *COLLISION_KIND_MASK_HIT) { + // the arrow landed or hit something, so release the item + let item_id = VarModule::get_int(weapon.battle_object, vars::link_bowarrow::instance::FUSED_ITEM_ID) as u32; + if sv_battle_object::is_active(item_id) { + let item_boma = sv_battle_object::module_accessor(item_id); + if fuse_detach_item(item_boma) { + let status = VarModule::get_int(weapon.battle_object, vars::link_bowarrow::instance::FUSED_ITEM_POST_STATUS); + StatusModule::change_status_request(item_boma, status, false); + } + } + } + else { + // the arrow vanished without hitting anything + fuse_remove_item(weapon.battle_object); + } + } + EffectModule::detach_all(weapon.module_accessor, 5); + 0.into() +} + +// WN_LINK_BOWARROW_STATUS_KIND_STICK / HIT_STICK // + +// restores the arrow's team after a reflected fused arrow sticks +unsafe extern "C" fn stick_end(weapon: &mut L2CWeaponCommon) -> L2CValue { + if VarModule::is_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_REFLECT_FIX) { + let (owner_boma, _, _) = get_owner(weapon.module_accessor); + TeamModule::set_team(weapon.module_accessor, fuse_get_owner_team_no(weapon.module_accessor), true); + TeamModule::set_team_owner_id(weapon.module_accessor, (*owner_boma).battle_object_id); + VarModule::off_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_REFLECT_FIX); + } + 0.into() +} + +pub fn install(agent: &mut Agent) { + agent.status(Main, *WN_LINK_BOWARROW_STATUS_KIND_HAVED, haved_main); + agent.status(End, *WN_LINK_BOWARROW_STATUS_KIND_HAVED, haved_end); + agent.status(Init, *WN_LINK_BOWARROW_STATUS_KIND_FLY, fly_init); + agent.status(End, *WN_LINK_BOWARROW_STATUS_KIND_FLY, fly_end); + agent.status(End, *WN_LINK_BOWARROW_STATUS_KIND_STICK, stick_end); + agent.status(End, *WN_LINK_BOWARROW_STATUS_KIND_HIT_STICK, stick_end); +} diff --git a/fighters/link/src/lib.rs b/fighters/link/src/lib.rs index 28bb571dad..a18386decd 100644 --- a/fighters/link/src/lib.rs +++ b/fighters/link/src/lib.rs @@ -10,6 +10,7 @@ pub mod status; // articles mod boomerang; +mod bowarrow; use smash::{ lib::{ @@ -52,4 +53,5 @@ pub fn install() { agent.install(); boomerang::install(); + bowarrow::install(); } \ No newline at end of file diff --git a/fighters/link/src/status/special_n.rs b/fighters/link/src/status/special_n.rs index d8142f1dba..f0fd9d4e3b 100644 --- a/fighters/link/src/status/special_n.rs +++ b/fighters/link/src/status/special_n.rs @@ -619,7 +619,19 @@ unsafe extern "C" fn special_n_helper(fighter: &mut L2CFighterCommon) { ArticleModule::shoot(fighter.module_accessor, *FIGHTER_LINK_GENERATE_ARTICLE_BOWARROW, app::ArticleOperationTarget(*ARTICLE_OPE_TARGET_FIRST), true); } +// symbol-based call for link's arrow fuse +extern "Rust" { + fn fuse_special_n_exit(fighter: &mut L2CFighterCommon); +} + +// drops the fused item if the arrow was never fired +pub unsafe extern "C" fn special_n_exit(fighter: &mut L2CFighterCommon) -> L2CValue { + fuse_special_n_exit(fighter); + smashline::original_status(Exit, fighter, *FIGHTER_STATUS_KIND_SPECIAL_N)(fighter) +} + pub fn install(agent: &mut Agent) { agent.status(Pre, *FIGHTER_STATUS_KIND_SPECIAL_N, special_n_pre); agent.status(Main, *FIGHTER_STATUS_KIND_SPECIAL_N, special_n_main); + agent.status(Exit, *FIGHTER_STATUS_KIND_SPECIAL_N, special_n_exit); } \ No newline at end of file diff --git a/fighters/murabito/src/opff.rs b/fighters/murabito/src/opff.rs index 4d9a22effb..1311fa14e6 100644 --- a/fighters/murabito/src/opff.rs +++ b/fighters/murabito/src/opff.rs @@ -77,11 +77,17 @@ extern "Rust" { fn ac_common(fighter: &mut smash::lua2cpp::L2CFighterCommon); } +// symbol-based call for link's arrow fuse +extern "Rust" { + fn fuse_pocket_common(fighter: &mut smash::lua2cpp::L2CFighterCommon); +} + pub extern "C" fn murabito_frame_wrapper(fighter: &mut smash::lua2cpp::L2CFighterCommon) { unsafe { common::opff::fighter_common_opff(fighter); murabito_frame(fighter); ac_common(fighter); + fuse_pocket_common(fighter); } } diff --git a/fighters/rosetta/src/opff.rs b/fighters/rosetta/src/opff.rs index 547c3894dc..af3e7e8cee 100644 --- a/fighters/rosetta/src/opff.rs +++ b/fighters/rosetta/src/opff.rs @@ -17,6 +17,11 @@ extern "Rust" { fn gimmick_flash(boma: &mut BattleObjectModuleAccessor); } +// symbol-based call for link's arrow fuse +extern "Rust" { + fn fuse_rosetta_common(fighter: &mut L2CFighterCommon); +} + use vars::common::instance::GIMMICK_TIMER; use vars::rosetta::instance::*; use vars::rosetta::status::*; @@ -97,7 +102,8 @@ pub unsafe fn moveset(fighter: &mut L2CFighterCommon, boma: &mut BattleObjectMod pub extern "C" fn rosetta_frame_wrapper(fighter: &mut smash::lua2cpp::L2CFighterCommon) { unsafe { common::opff::fighter_common_opff(fighter); - rosetta_frame(fighter) + rosetta_frame(fighter); + fuse_rosetta_common(fighter); } } diff --git a/fighters/shizue/src/opff.rs b/fighters/shizue/src/opff.rs index 4a3455bd38..c2d186b39c 100644 --- a/fighters/shizue/src/opff.rs +++ b/fighters/shizue/src/opff.rs @@ -135,11 +135,17 @@ extern "Rust" { fn ac_common(fighter: &mut smash::lua2cpp::L2CFighterCommon); } +// symbol-based call for link's arrow fuse +extern "Rust" { + fn fuse_pocket_common(fighter: &mut smash::lua2cpp::L2CFighterCommon); +} + pub extern "C" fn shizue_frame_wrapper(fighter: &mut smash::lua2cpp::L2CFighterCommon) { unsafe { common::opff::fighter_common_opff(fighter); shizue_frame(fighter); ac_common(fighter); + fuse_pocket_common(fighter); } } From a4c34391f735e1512913f4241af9af94ce279ee6 Mon Sep 17 00:00:00 2001 From: SuddyN Date: Fri, 9 Oct 2026 16:45:20 -0400 Subject: [PATCH 06/20] fix krown arrow duplication --- .../src/function_hooks/vtables/krool.rs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/fighters/common/src/function_hooks/vtables/krool.rs b/fighters/common/src/function_hooks/vtables/krool.rs index 5b0c5a13a2..7ff0abd51c 100644 --- a/fighters/common/src/function_hooks/vtables/krool.rs +++ b/fighters/common/src/function_hooks/vtables/krool.rs @@ -24,7 +24,31 @@ pub unsafe extern "C" fn hook_on_damage(vtable: u64, battle_object: *mut Fighter let ret = call_original!(vtable, battle_object, log); - if opponent_boma.is_item() && opponent_boma.kind() == *ITEM_KIND_KROOLCROWN + // a crown fused to one of link's arrows, whether the crown or the arrow made contact + let fuse_arrow_id = if opponent_boma.is_item() && LinkModule::is_link(opponent_boma, *ITEM_LINK_NO_HAVE) { + LinkModule::get_parent_id(opponent_boma, *ITEM_LINK_NO_HAVE, true) as u32 + } + else { + opponent_id + }; + let mut fuse_arrow = std::ptr::null_mut(); + if sv_battle_object::is_active(fuse_arrow_id) { + let arrow_boma = &mut *sv_battle_object::module_accessor(fuse_arrow_id); + if arrow_boma.is_weapon() && arrow_boma.kind() == *WEAPON_KIND_LINK_BOWARROW { + fuse_arrow = get_battle_object_from_id(fuse_arrow_id); + } + } + let is_crown_fuse_arrow = !fuse_arrow.is_null() + && VarModule::is_flag(fuse_arrow, vars::link_bowarrow::instance::IS_ARROW_FUSE) + && VarModule::get_int(fuse_arrow, vars::link_bowarrow::instance::FUSED_ITEM_KIND) == *ITEM_KIND_KROOLCROWN; + + if is_crown_fuse_arrow + && boma.is_flag(*FIGHTER_KROOL_INSTANCE_WORK_ID_FLAG_DROP_CROWN) { + crate::opff::fuse::fuse_remove_item(fuse_arrow); + EffectModule::req_follow(boma, Hash40::new("sys_item_get"), Hash40::new("crown1"), &Vector3f::zero(), &Vector3f::zero(), 1.0, false, 0, 0, 0, 0, 0, false, false); + boma.off_flag(*FIGHTER_KROOL_INSTANCE_WORK_ID_FLAG_DROP_CROWN); + } + else if opponent_boma.is_item() && opponent_boma.kind() == *ITEM_KIND_KROOLCROWN && boma.is_flag(*FIGHTER_KROOL_INSTANCE_WORK_ID_FLAG_DROP_CROWN) { StatusModule::change_status_request(opponent_boma, *ITEM_STATUS_KIND_DEAD, false); EffectModule::req_follow(boma, Hash40::new("sys_item_get"), Hash40::new("crown1"), &Vector3f::zero(), &Vector3f::zero(), 1.0, false, 0, 0, 0, 0, 0, false, false); From 023ef6911da999319d41350bbce5d103821fee33 Mon Sep 17 00:00:00 2001 From: SuddyN Date: Fri, 9 Oct 2026 16:47:09 -0400 Subject: [PATCH 07/20] various fuse arrow fixes --- dynamic/src/consts.rs | 5 ++ fighters/common/src/opff/fuse.rs | 121 ++++++++++++++++++++++----- fighters/kirby/src/opff.rs | 4 + fighters/link/src/bowarrow/status.rs | 51 ++++------- fighters/link/src/opff.rs | 8 +- 5 files changed, 131 insertions(+), 58 deletions(-) diff --git a/dynamic/src/consts.rs b/dynamic/src/consts.rs index 2d8223d8c7..81b7f18a89 100644 --- a/dynamic/src/consts.rs +++ b/dynamic/src/consts.rs @@ -929,8 +929,13 @@ pub mod vars { // link arrow fuse pub const IS_ARROW_FUSE: i32 = 0x01F9; // flag + pub const FUSE_DEDEDE_ITEM: i32 = 0x01FA; // flag + pub const FUSE_DEDEDE_ITEM_CHECKED: i32 = 0x01FB; // flag pub const FUSED_ITEM_ID: i32 = 0x01F8; pub const TEAM_NO: i32 = 0x01F9; + pub const FUSED_ITEM_KIND: i32 = 0x01FA; // pocketed fused item + pub const FUSE_POCKET_TARGET_ID: i32 = 0x01FB; + pub const FUSE_DEDEDE_ITEM_KIND: i32 = 0x01FC; pub use super::super::bayonetta::instance::SPECIAL_N_CANCEL_TYPE; pub use super::super::ptrainer::instance::SPECIAL_N_PLEDGE_TIMER; diff --git a/fighters/common/src/opff/fuse.rs b/fighters/common/src/opff/fuse.rs index 7546fcfa25..a3ab9faabf 100644 --- a/fighters/common/src/opff/fuse.rs +++ b/fighters/common/src/opff/fuse.rs @@ -23,7 +23,31 @@ pub struct CreateItemParam { #[skyline::from_offset(0x15db0b0)] unsafe fn create_item(item_manager: *const smash_rs::app::ItemManager, create_item_param: *mut CreateItemParam, unk: bool, unk2: bool, unk3: bool) -> *mut BattleObject; -unsafe fn get_owner(weapon_boma: *mut BattleObjectModuleAccessor) -> (*mut BattleObjectModuleAccessor, *mut BattleObject, i32) { +extern "C" { + #[link_name = "_ZN3app10pacmanboss11PACMAN_LIFEEv"] + fn pacmanboss_life() -> i32; +} + +// restores item state that is normally set up when a fighter throws the item +#[no_mangle] +pub unsafe extern "Rust" fn fuse_on_item_released(item_boma: *mut BattleObjectModuleAccessor) { + if utility::get_kind(&mut *item_boma) == *ITEM_KIND_PACMANBOSS { + WorkModule::on_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_THROW); + WorkModule::off_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_DROP); + WorkModule::off_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_HIT); + WorkModule::off_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_HOP); + WorkModule::set_int(item_boma, 0, *ITEM_PACMAN_INSTANCE_WORK_INT_BOUND_COUNT); + WorkModule::set_int(item_boma, pacmanboss_life(), *ITEM_PACMAN_INSTANCE_WORK_INT_LIFE); + WorkModule::set_int(item_boma, *PACMANBOSS_STATE_FIRST, *ITEM_PACMANBOSS_INSTANCE_WORK_INT_STATE); + WorkModule::set_int(item_boma, 0, *ITEM_PACMANBOSS_INSTANCE_WORK_INT_THROW_FRAME); + WorkModule::set_int(item_boma, 0, *ITEM_PACMANBOSS_INSTANCE_WORK_INT_ROT_FRAME); + WorkModule::set_float(item_boma, 0.0, *ITEM_PACMANBOSS_INSTANCE_WORK_FLOAT_ROT_ANGLE); + } +} + +// returns the boma, object and fighter kind of the arrow's owner +#[no_mangle] +pub unsafe extern "Rust" fn fuse_get_owner(weapon_boma: *mut BattleObjectModuleAccessor) -> (*mut BattleObjectModuleAccessor, *mut BattleObject, i32) { let owner_id = WorkModule::get_int(weapon_boma, *WEAPON_INSTANCE_WORK_ID_INT_LINK_OWNER) as u32; let owner_boma = sv_battle_object::module_accessor(owner_id); let owner_object = get_battle_object_from_id(owner_id); @@ -46,6 +70,22 @@ unsafe fn owner_team_no_var(owner_kind: i32) -> i32 { } } +// returns the (stored item kind, pocket target id, team no) vars a fighter uses to pocket a fused arrow +unsafe fn pocket_vars(fighter_kind: i32) -> Option<(i32, i32, i32)> { + if fighter_kind == *FIGHTER_KIND_MURABITO { + Some((vars::murabito::instance::FUSED_ITEM_KIND, vars::murabito::instance::FUSE_POCKET_TARGET_ID, vars::murabito::instance::TEAM_NO)) + } + else if fighter_kind == *FIGHTER_KIND_SHIZUE { + Some((vars::shizue::instance::FUSED_ITEM_KIND, vars::shizue::instance::FUSE_POCKET_TARGET_ID, vars::shizue::instance::TEAM_NO)) + } + else if fighter_kind == *FIGHTER_KIND_KIRBY { + Some((vars::kirby::instance::FUSED_ITEM_KIND, vars::kirby::instance::FUSE_POCKET_TARGET_ID, vars::kirby::instance::TEAM_NO)) + } + else { + None + } +} + // returns the boma and object of the given id if it is an active Link arrow unsafe fn get_arrow(object_id: u32) -> Option<(*mut BattleObjectModuleAccessor, *mut BattleObject)> { if object_id == *BATTLE_OBJECT_ID_INVALID as u32 || !sv_battle_object::is_active(object_id) { @@ -62,7 +102,7 @@ unsafe fn get_arrow(object_id: u32) -> Option<(*mut BattleObjectModuleAccessor, // returns the team the arrow's owner had when the arrow was fused #[no_mangle] pub unsafe extern "Rust" fn fuse_get_owner_team_no(weapon_boma: *mut BattleObjectModuleAccessor) -> i32 { - let (_, owner_object, owner_kind) = get_owner(weapon_boma); + let (_, owner_object, owner_kind) = fuse_get_owner(weapon_boma); VarModule::get_int(owner_object, owner_team_no_var(owner_kind)) } @@ -106,7 +146,7 @@ pub unsafe extern "Rust" fn fuse_remove_item(arrow_object: *mut BattleObject) { // pass ITEM_KIND_NONE / BATTLE_OBJECT_ID_INVALID to use the item the owner is currently holding. #[no_mangle] pub unsafe extern "Rust" fn fuse_set_arrow_params(arrow_boma: *mut BattleObjectModuleAccessor, item: i32, id: u32) { - let (owner_boma, owner_object, owner_kind) = get_owner(arrow_boma); + let (owner_boma, owner_object, owner_kind) = fuse_get_owner(arrow_boma); let arrow_object = get_battle_object_from_id((*arrow_boma).battle_object_id); let kind = if item == *ITEM_KIND_NONE { @@ -189,12 +229,18 @@ pub unsafe extern "Rust" fn fuse_create_item(arrow_boma: *mut BattleObjectModule fuse_set_arrow_params(arrow_boma, item, (*item_boma).battle_object_id); } -// ddd re-creates the fused item when spitting the arrow back out +// ddd (and kirby with ddd's hat) re-creates the fused item when spitting the arrow back out #[no_mangle] pub unsafe extern "Rust" fn fuse_dedede_common(fighter: &mut L2CFighterCommon) { - if !fighter.is_status(*FIGHTER_DEDEDE_STATUS_KIND_SPECIAL_N_SHOT_OBJECT_HIT) { - VarModule::off_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM); - VarModule::off_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM_CHECKED); + let (status, fuse_item_flag, checked_flag, fused_item_kind_var) = if fighter.kind() == *FIGHTER_KIND_KIRBY { + (*FIGHTER_KIRBY_STATUS_KIND_DEDEDE_SPECIAL_N_SHOT_OBJECT_HIT, vars::kirby::instance::FUSE_DEDEDE_ITEM, vars::kirby::instance::FUSE_DEDEDE_ITEM_CHECKED, vars::kirby::instance::FUSE_DEDEDE_ITEM_KIND) + } + else { + (*FIGHTER_DEDEDE_STATUS_KIND_SPECIAL_N_SHOT_OBJECT_HIT, vars::dedede::instance::FUSE_ITEM, vars::dedede::instance::FUSE_ITEM_CHECKED, vars::dedede::instance::FUSED_ITEM_KIND) + }; + if !fighter.is_status(status) { + VarModule::off_flag(fighter.battle_object, fuse_item_flag); + VarModule::off_flag(fighter.battle_object, checked_flag); return; } let obj_id = WorkModule::get_int(fighter.module_accessor, *FIGHTER_DEDEDE_STATUS_SPECIAL_N_WORK_INT_SHOT_OBJECT_ID) as u32; @@ -204,8 +250,8 @@ pub unsafe extern "Rust" fn fuse_dedede_common(fighter: &mut L2CFighterCommon) { }; if WorkModule::is_flag(fighter.module_accessor, *FIGHTER_DEDEDE_STATUS_SPECIAL_N_FLAG_SHOT_OBJECT_SHOOT) - && !VarModule::is_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM_CHECKED) { - VarModule::on_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM_CHECKED); + && !VarModule::is_flag(fighter.battle_object, checked_flag) { + VarModule::on_flag(fighter.battle_object, checked_flag); if VarModule::is_flag(obj_object, vars::link_bowarrow::instance::IS_ARROW_FUSE) { // skip if the arrow still carries its item let fused_item_id = VarModule::get_int(obj_object, vars::link_bowarrow::instance::FUSED_ITEM_ID) as u32; @@ -213,41 +259,50 @@ pub unsafe extern "Rust" fn fuse_dedede_common(fighter: &mut L2CFighterCommon) { && LinkModule::is_link(sv_battle_object::module_accessor(fused_item_id), *ITEM_LINK_NO_HAVE); if !is_fused_item_attached { let fused_item = VarModule::get_int(obj_object, vars::link_bowarrow::instance::FUSED_ITEM_KIND); - VarModule::set_int(fighter.battle_object, vars::dedede::instance::FUSED_ITEM_KIND, fused_item); - VarModule::on_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM); + VarModule::set_int(fighter.battle_object, fused_item_kind_var, fused_item); + VarModule::on_flag(fighter.battle_object, fuse_item_flag); } } } - if VarModule::is_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM) + if VarModule::is_flag(fighter.battle_object, fuse_item_flag) && MotionModule::frame(fighter.module_accessor) >= 7.0 { - let item = VarModule::get_int(fighter.battle_object, vars::dedede::instance::FUSED_ITEM_KIND); + let item = VarModule::get_int(fighter.battle_object, fused_item_kind_var); fuse_create_item(obj_boma, item, fighter.module_accessor, (*fighter.module_accessor).battle_object_id); - VarModule::set_int(fighter.battle_object, vars::dedede::instance::FUSED_ITEM_KIND, *ITEM_KIND_NONE); - VarModule::off_flag(fighter.battle_object, vars::dedede::instance::FUSE_ITEM); + VarModule::set_int(fighter.battle_object, fused_item_kind_var, *ITEM_KIND_NONE); + VarModule::off_flag(fighter.battle_object, fuse_item_flag); } } -// villager/isabelle store the fused item when pocketing the arrow, and delete the original +// villager/isabelle (and kirby with their hat) store the fused item when pocketing the arrow, and delete the original // the item is re-created when the arrow is pulled back out #[no_mangle] pub unsafe extern "Rust" fn fuse_pocket_common(fighter: &mut L2CFighterCommon) { - let (fused_item_kind_var, team_no_var, target_id_var) = if fighter.kind() == *FIGHTER_KIND_SHIZUE { - (vars::shizue::instance::FUSED_ITEM_KIND, vars::shizue::instance::TEAM_NO, vars::shizue::instance::FUSE_POCKET_TARGET_ID) + let (fused_item_kind_var, target_id_var, team_no_var) = match pocket_vars(fighter.kind()) { + Some(pocket_vars) => pocket_vars, + None => return + }; + let search_statuses = if fighter.kind() == *FIGHTER_KIND_KIRBY { + let copy_chara = WorkModule::get_int(fighter.module_accessor, *FIGHTER_KIRBY_INSTANCE_WORK_ID_INT_COPY_CHARA); + if ![*FIGHTER_KIND_MURABITO, *FIGHTER_KIND_SHIZUE].contains(©_chara) { + VarModule::set_int(fighter.battle_object, fused_item_kind_var, *ITEM_KIND_NONE); + } + [*FIGHTER_KIRBY_STATUS_KIND_MURABITO_SPECIAL_N_SEARCH, *FIGHTER_KIRBY_STATUS_KIND_SHIZUE_SPECIAL_N_SEARCH] } else { - (vars::murabito::instance::FUSED_ITEM_KIND, vars::murabito::instance::TEAM_NO, vars::murabito::instance::FUSE_POCKET_TARGET_ID) + [*FIGHTER_MURABITO_STATUS_KIND_SPECIAL_N_SEARCH, *FIGHTER_MURABITO_STATUS_KIND_SPECIAL_N_SEARCH] }; // the pocket is lost on death if fighter.is_status(*FIGHTER_STATUS_KIND_DEAD) { VarModule::set_int(fighter.battle_object, fused_item_kind_var, *ITEM_KIND_NONE); } - if !fighter.is_status(*FIGHTER_MURABITO_STATUS_KIND_SPECIAL_N_SEARCH) { + if !fighter.is_status_one_of(&search_statuses) { VarModule::set_int(fighter.battle_object, target_id_var, *BATTLE_OBJECT_ID_INVALID); return; } + // kirby's copy abilities use the copied fighter's instance work ids let obj_id = WorkModule::get_int(fighter.module_accessor, *FIGHTER_MURABITO_INSTANCE_WORK_ID_INT_TARGET_OBJECT_ID) as u32; if obj_id == *BATTLE_OBJECT_ID_INVALID as u32 || obj_id == VarModule::get_int(fighter.battle_object, target_id_var) as u32 { @@ -270,6 +325,32 @@ pub unsafe extern "Rust" fn fuse_pocket_common(fighter: &mut L2CFighterCommon) { } } +// returns the fused item the arrow's owner has pocketed, if any +#[no_mangle] +pub unsafe extern "Rust" fn fuse_get_pocket_item(weapon_boma: *mut BattleObjectModuleAccessor) -> i32 { + let (_, owner_object, owner_kind) = fuse_get_owner(weapon_boma); + let item = match pocket_vars(owner_kind) { + Some((fused_item_kind_var, _, _)) => VarModule::get_int(owner_object, fused_item_kind_var), + None => *ITEM_KIND_NONE + }; + // the var starts at 0 (ITEM_KIND_ASSIST), which can't be fused + if item > *ITEM_KIND_ASSIST { item } else { *ITEM_KIND_NONE } +} + +// re-creates the owner's pocketed fused item on the arrow being pulled back out +#[no_mangle] +pub unsafe extern "Rust" fn fuse_take_out_pocket_item(weapon_boma: *mut BattleObjectModuleAccessor) { + let item = fuse_get_pocket_item(weapon_boma); + if item == *ITEM_KIND_NONE { + return; + } + let (owner_boma, owner_object, owner_kind) = fuse_get_owner(weapon_boma); + fuse_create_item(weapon_boma, item, weapon_boma, (*owner_boma).battle_object_id); + if let Some((fused_item_kind_var, _, _)) = pocket_vars(owner_kind) { + VarModule::set_int(owner_object, fused_item_kind_var, *ITEM_KIND_NONE); + } +} + // kirby's inhale deletes the fused item #[no_mangle] pub unsafe extern "Rust" fn fuse_kirby_common(fighter: &mut L2CFighterCommon) { diff --git a/fighters/kirby/src/opff.rs b/fighters/kirby/src/opff.rs index f8e912c33f..c52b7bccee 100644 --- a/fighters/kirby/src/opff.rs +++ b/fighters/kirby/src/opff.rs @@ -13,6 +13,8 @@ extern "Rust" { // symbol-based call for link's arrow fuse extern "Rust" { fn fuse_kirby_common(fighter: &mut L2CFighterCommon); + fn fuse_pocket_common(fighter: &mut L2CFighterCommon); + fn fuse_dedede_common(fighter: &mut L2CFighterCommon); } unsafe fn final_cutter_landing_bugfix(fighter: &mut L2CFighterCommon) { @@ -115,6 +117,8 @@ pub extern "C" fn kirby_frame_wrapper(fighter: &mut smash::lua2cpp::L2CFighterCo common::opff::fighter_common_opff(fighter); kirby_frame(fighter); fuse_kirby_common(fighter); + fuse_pocket_common(fighter); + fuse_dedede_common(fighter); } } diff --git a/fighters/link/src/bowarrow/status.rs b/fighters/link/src/bowarrow/status.rs index a3b67ced84..2dbb04192f 100644 --- a/fighters/link/src/bowarrow/status.rs +++ b/fighters/link/src/bowarrow/status.rs @@ -2,28 +2,24 @@ use super::*; // symbol-based calls for link's arrow fuse extern "Rust" { + fn fuse_get_owner(weapon_boma: *mut BattleObjectModuleAccessor) -> (*mut BattleObjectModuleAccessor, *mut BattleObject, i32); fn fuse_set_arrow_params(arrow_boma: *mut BattleObjectModuleAccessor, item: i32, id: u32); - fn fuse_create_item(arrow_boma: *mut BattleObjectModuleAccessor, item: i32, founder_boma: *mut BattleObjectModuleAccessor, owner_id: u32); fn fuse_detach_item(item_boma: *mut BattleObjectModuleAccessor) -> bool; fn fuse_attach_item(item_boma: *mut BattleObjectModuleAccessor, arrow_id: u32) -> bool; fn fuse_remove_item(arrow_object: *mut BattleObject); fn fuse_get_owner_team_no(weapon_boma: *mut BattleObjectModuleAccessor) -> i32; -} - -unsafe fn get_owner(weapon_boma: *mut BattleObjectModuleAccessor) -> (*mut BattleObjectModuleAccessor, *mut BattleObject, i32) { - let owner_id = WorkModule::get_int(weapon_boma, *WEAPON_INSTANCE_WORK_ID_INT_LINK_OWNER) as u32; - let owner_boma = sv_battle_object::module_accessor(owner_id); - let owner_object = get_battle_object_from_id(owner_id); - let owner_kind = utility::get_kind(&mut *owner_boma); - (owner_boma, owner_object, owner_kind) + fn fuse_get_pocket_item(weapon_boma: *mut BattleObjectModuleAccessor) -> i32; + fn fuse_take_out_pocket_item(weapon_boma: *mut BattleObjectModuleAccessor); + fn fuse_on_item_released(item_boma: *mut BattleObjectModuleAccessor); } // WN_LINK_BOWARROW_STATUS_KIND_HAVED // unsafe extern "C" fn haved_main(weapon: &mut L2CWeaponCommon) -> L2CValue { - let (owner_boma, owner_object, owner_kind) = get_owner(weapon.module_accessor); + let (owner_boma, owner_object, owner_kind) = fuse_get_owner(weapon.module_accessor); let mut is_fused = false; - if ItemModule::is_have_item(owner_boma, 0) { + if ItemModule::is_have_item(owner_boma, 0) + && fuse_get_pocket_item(weapon.module_accessor) == *ITEM_KIND_NONE { let kind = ItemModule::get_have_item_kind(owner_boma, 0); let trait_flag = ItemModule::get_have_item_trait(owner_boma, 0); // trait flags are bitmasks, so swing/shoot items can carry other bits as well @@ -45,43 +41,25 @@ unsafe extern "C" fn haved_main(weapon: &mut L2CWeaponCommon) -> L2CValue { VarModule::set_flag(owner_object, vars::kirby::instance::IS_ARROW_FUSE, is_fused); } + let ret = smashline::original_status(Main, weapon, *WN_LINK_BOWARROW_STATUS_KIND_HAVED)(weapon); if is_fused { // move the held item from the owner's hand onto the arrow let item_id = VarModule::get_int(weapon.battle_object, vars::link_bowarrow::instance::FUSED_ITEM_ID) as u32; let item_boma = sv_battle_object::module_accessor(item_id); + ItemModule::drop_item(owner_boma, 90.0, 0.0, 0); + StatusModule::change_status_request(item_boma, *ITEM_STATUS_KIND_HAVE, false); fuse_detach_item(item_boma); if fuse_attach_item(item_boma, (*weapon.module_accessor).battle_object_id) { // TODO: PLAY_SE(weapon, Hash40::new("se_link_fuse")); } MotionModule::change_motion(weapon.module_accessor, Hash40::new("haved"), 0.0, 1.0, false, 0.0, false, false); } - else { - MotionModule::change_motion(weapon.module_accessor, Hash40::new("haved_hide"), 0.0, 1.0, false, 0.0, false, false); - } - weapon.fastshift(L2CValue::Ptr(haved_main_loop as *const () as _)) + ret } -unsafe extern "C" fn haved_main_loop(weapon: &mut L2CWeaponCommon) -> L2CValue { - 0.into() -} - -// re-creates the item stored by Villager/Isabelle when a pocketed fused arrow is pulled back out +// re-creates the item stored by Villager/Isabelle/Kirby when a pocketed fused arrow is pulled back out unsafe extern "C" fn haved_end(weapon: &mut L2CWeaponCommon) -> L2CValue { - let (owner_boma, owner_object, owner_kind) = get_owner(weapon.module_accessor); - let fused_item_kind_var = if owner_kind == *FIGHTER_KIND_MURABITO { - vars::murabito::instance::FUSED_ITEM_KIND - } - else if owner_kind == *FIGHTER_KIND_SHIZUE { - vars::shizue::instance::FUSED_ITEM_KIND - } - else { - return 0.into(); - }; - let item = VarModule::get_int(owner_object, fused_item_kind_var); - if item != *ITEM_KIND_NONE && item > *ITEM_KIND_ASSIST { - fuse_create_item(weapon.module_accessor, item, weapon.module_accessor, (*owner_boma).battle_object_id); - VarModule::set_int(owner_object, fused_item_kind_var, *ITEM_KIND_NONE); - } + fuse_take_out_pocket_item(weapon.module_accessor); 0.into() } @@ -118,6 +96,7 @@ unsafe extern "C" fn fly_end(weapon: &mut L2CWeaponCommon) -> L2CValue { if fuse_detach_item(item_boma) { let status = VarModule::get_int(weapon.battle_object, vars::link_bowarrow::instance::FUSED_ITEM_POST_STATUS); StatusModule::change_status_request(item_boma, status, false); + fuse_on_item_released(item_boma); } } } @@ -135,7 +114,7 @@ unsafe extern "C" fn fly_end(weapon: &mut L2CWeaponCommon) -> L2CValue { // restores the arrow's team after a reflected fused arrow sticks unsafe extern "C" fn stick_end(weapon: &mut L2CWeaponCommon) -> L2CValue { if VarModule::is_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_REFLECT_FIX) { - let (owner_boma, _, _) = get_owner(weapon.module_accessor); + let (owner_boma, _, _) = fuse_get_owner(weapon.module_accessor); TeamModule::set_team(weapon.module_accessor, fuse_get_owner_team_no(weapon.module_accessor), true); TeamModule::set_team_owner_id(weapon.module_accessor, (*owner_boma).battle_object_id); VarModule::off_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_REFLECT_FIX); diff --git a/fighters/link/src/opff.rs b/fighters/link/src/opff.rs index 729ca378c0..45cc578df5 100644 --- a/fighters/link/src/opff.rs +++ b/fighters/link/src/opff.rs @@ -38,8 +38,12 @@ unsafe fn shield_scale_fix(fighter: &mut smash::lua2cpp::L2CFighterCommon) { return; } - if let Some(target) = smashline::api::get_target_function("lua2cpp_link.nrs", 0x6e40) { - let shield_set_scale: extern "C" fn(&mut L2CFighterCommon) = std::mem::transmute(target); + static mut FUNC_SHIELD_SET_SCALE: usize = 0; + if FUNC_SHIELD_SET_SCALE == 0 { + FUNC_SHIELD_SET_SCALE = smashline::api::get_target_function("lua2cpp_link.nrs", 0x6e40).unwrap_or(0); + } + if FUNC_SHIELD_SET_SCALE != 0 { + let shield_set_scale: extern "C" fn(&mut L2CFighterCommon) = std::mem::transmute(FUNC_SHIELD_SET_SCALE); shield_set_scale(fighter); } } From 42ee72639660c676fb162f44745332131f8c3392 Mon Sep 17 00:00:00 2001 From: SuddyN Date: Sat, 10 Oct 2026 16:02:13 -0400 Subject: [PATCH 08/20] clean up consts usage and shared functions --- dynamic/src/consts.rs | 46 +--- fighters/common/src/opff/fuse.rs | 238 +++++++----------- fighters/link/src/bowarrow/status.rs | 60 ++++- .../link/motion/body/motion_patch.yaml | 6 + romfs/source/fighter/link/param/vl.prcxml | 1 + 5 files changed, 157 insertions(+), 194 deletions(-) diff --git a/dynamic/src/consts.rs b/dynamic/src/consts.rs index 81b7f18a89..afa301461b 100644 --- a/dynamic/src/consts.rs +++ b/dynamic/src/consts.rs @@ -205,6 +205,10 @@ pub mod vars { pub const DISABLE_FLOAT: i32 = 0x0071; + // link arrow fuse + pub const FUSE_IS_STORED_ITEM: i32 = 0x0072; + pub const FUSE_IS_STORED_ITEM_CHECKED: i32 = 0x0073; + // ints pub const LAST_ATTACK_RECEIVER_ENTRY_ID: i32 = 0x0000; @@ -252,6 +256,11 @@ pub mod vars { pub const DISABLE_ESCAPE_AIR_EFFECT_HANDLE: i32 = 0x0017; + // link arrow fuse + pub const FUSE_TEAM_NO: i32 = 0x0018; + pub const FUSE_STORED_ITEM_KIND: i32 = 0x0019; + pub const FUSE_STORED_TARGET_ID: i32 = 0x001A; + // floats @@ -563,14 +572,6 @@ pub mod vars { //floats pub const SPECIAL_N_STICK_Y: i32 = 0x0105; pub const SPECIAL_S_TOSS_LR: i32 = 0x0106; - - // link arrow fuse - // flags - pub const FUSE_ITEM: i32 = 0x0107; - pub const FUSE_ITEM_CHECKED: i32 = 0x0109; - - // ints - pub const FUSED_ITEM_KIND: i32 = 0x0108; } pub mod status{ //flags @@ -927,16 +928,6 @@ pub mod vars { pub const SPECIAL_N_PTRAINER_PLEDGE_STATE: i32 = 0x01F6; // Unique var as it doesn't like borrowing from ptrainer pub const SPECIAL_N_PTRAINER_PLEDGE_EFFECT_HANDLE: i32 = 0x01F7; - // link arrow fuse - pub const IS_ARROW_FUSE: i32 = 0x01F9; // flag - pub const FUSE_DEDEDE_ITEM: i32 = 0x01FA; // flag - pub const FUSE_DEDEDE_ITEM_CHECKED: i32 = 0x01FB; // flag - pub const FUSED_ITEM_ID: i32 = 0x01F8; - pub const TEAM_NO: i32 = 0x01F9; - pub const FUSED_ITEM_KIND: i32 = 0x01FA; // pocketed fused item - pub const FUSE_POCKET_TARGET_ID: i32 = 0x01FB; - pub const FUSE_DEDEDE_ITEM_KIND: i32 = 0x01FC; - pub use super::super::bayonetta::instance::SPECIAL_N_CANCEL_TYPE; pub use super::super::ptrainer::instance::SPECIAL_N_PLEDGE_TIMER; @@ -1026,14 +1017,6 @@ pub mod vars { } pub mod link { - pub mod instance { - // flags - pub const IS_ARROW_FUSE: i32 = 0x0100; - - // ints - pub const FUSED_ITEM_ID: i32 = 0x0100; - pub const TEAM_NO: i32 = 0x0101; - } pub mod status { // flags pub const ENABLE_SPECIAL_LW_CANCEL: i32 = 0x1000; @@ -1051,6 +1034,7 @@ pub mod vars { pub const FUSED_ITEM_TYPE: i32 = 0x0101; pub const FUSED_ITEM_POST_STATUS: i32 = 0x0102; pub const FUSED_ITEM_ID: i32 = 0x0103; + pub const FUSED_ITEM_OWNER_ID: i32 = 0x0104; } } @@ -1412,11 +1396,6 @@ pub mod vars { // ints pub const ATTACK_AIR_HI_TURNIP_COUNT: i32 = 0x0104; pub const ATTACK_AIR_LW_TURNIP_COUNT: i32 = 0x0105; - - // link arrow fuse - pub const FUSED_ITEM_KIND: i32 = 0x0106; - pub const TEAM_NO: i32 = 0x0107; - pub const FUSE_POCKET_TARGET_ID: i32 = 0x0108; } } @@ -1926,11 +1905,6 @@ pub mod vars { // ints pub const SPECIAL_LW_LLOID_TIMER: i32 = 0x0100; - - // link arrow fuse - pub const FUSED_ITEM_KIND: i32 = 0x0101; - pub const TEAM_NO: i32 = 0x0102; - pub const FUSE_POCKET_TARGET_ID: i32 = 0x0103; } pub mod status { // flags diff --git a/fighters/common/src/opff/fuse.rs b/fighters/common/src/opff/fuse.rs index a3ab9faabf..63be00feca 100644 --- a/fighters/common/src/opff/fuse.rs +++ b/fighters/common/src/opff/fuse.rs @@ -23,25 +23,24 @@ pub struct CreateItemParam { #[skyline::from_offset(0x15db0b0)] unsafe fn create_item(item_manager: *const smash_rs::app::ItemManager, create_item_param: *mut CreateItemParam, unk: bool, unk2: bool, unk3: bool) -> *mut BattleObject; -extern "C" { - #[link_name = "_ZN3app10pacmanboss11PACMAN_LIFEEv"] - fn pacmanboss_life() -> i32; +#[no_mangle] +pub unsafe extern "Rust" fn item_owner_id_ptr(item_id: u32) -> *mut u32 { + let item = smash_rs::app::ItemManager::instance().unwrap().find_active_item_from_id(item_id); + if item.is_null() { + return std::ptr::null_mut(); + } + (item as *mut u8).add(0x250) as *mut u32 } -// restores item state that is normally set up when a fighter throws the item +// gives a released fused bomb back to whoever owned it before it was fused #[no_mangle] -pub unsafe extern "Rust" fn fuse_on_item_released(item_boma: *mut BattleObjectModuleAccessor) { - if utility::get_kind(&mut *item_boma) == *ITEM_KIND_PACMANBOSS { - WorkModule::on_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_THROW); - WorkModule::off_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_DROP); - WorkModule::off_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_HIT); - WorkModule::off_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_HOP); - WorkModule::set_int(item_boma, 0, *ITEM_PACMAN_INSTANCE_WORK_INT_BOUND_COUNT); - WorkModule::set_int(item_boma, pacmanboss_life(), *ITEM_PACMAN_INSTANCE_WORK_INT_LIFE); - WorkModule::set_int(item_boma, *PACMANBOSS_STATE_FIRST, *ITEM_PACMANBOSS_INSTANCE_WORK_INT_STATE); - WorkModule::set_int(item_boma, 0, *ITEM_PACMANBOSS_INSTANCE_WORK_INT_THROW_FRAME); - WorkModule::set_int(item_boma, 0, *ITEM_PACMANBOSS_INSTANCE_WORK_INT_ROT_FRAME); - WorkModule::set_float(item_boma, 0.0, *ITEM_PACMANBOSS_INSTANCE_WORK_FLOAT_ROT_ANGLE); +pub unsafe extern "Rust" fn restore_fused_item_owner(arrow_object: *mut BattleObject, item_boma: *mut BattleObjectModuleAccessor) { + if utility::get_kind(&mut *item_boma) != *ITEM_KIND_LINKBOMB { + return; + } + let owner_ptr = item_owner_id_ptr((*item_boma).battle_object_id); + if !owner_ptr.is_null() { + *owner_ptr = VarModule::get_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_OWNER_ID) as u32; } } @@ -55,39 +54,9 @@ pub unsafe extern "Rust" fn fuse_get_owner(weapon_boma: *mut BattleObjectModuleA (owner_boma, owner_object, owner_kind) } -unsafe fn owner_team_no_var(owner_kind: i32) -> i32 { - if owner_kind == *FIGHTER_KIND_MURABITO { - vars::murabito::instance::TEAM_NO - } - else if owner_kind == *FIGHTER_KIND_SHIZUE { - vars::shizue::instance::TEAM_NO - } - else if owner_kind == *FIGHTER_KIND_KIRBY { - vars::kirby::instance::TEAM_NO - } - else { - vars::link::instance::TEAM_NO - } -} - -// returns the (stored item kind, pocket target id, team no) vars a fighter uses to pocket a fused arrow -unsafe fn pocket_vars(fighter_kind: i32) -> Option<(i32, i32, i32)> { - if fighter_kind == *FIGHTER_KIND_MURABITO { - Some((vars::murabito::instance::FUSED_ITEM_KIND, vars::murabito::instance::FUSE_POCKET_TARGET_ID, vars::murabito::instance::TEAM_NO)) - } - else if fighter_kind == *FIGHTER_KIND_SHIZUE { - Some((vars::shizue::instance::FUSED_ITEM_KIND, vars::shizue::instance::FUSE_POCKET_TARGET_ID, vars::shizue::instance::TEAM_NO)) - } - else if fighter_kind == *FIGHTER_KIND_KIRBY { - Some((vars::kirby::instance::FUSED_ITEM_KIND, vars::kirby::instance::FUSE_POCKET_TARGET_ID, vars::kirby::instance::TEAM_NO)) - } - else { - None - } -} - // returns the boma and object of the given id if it is an active Link arrow -unsafe fn get_arrow(object_id: u32) -> Option<(*mut BattleObjectModuleAccessor, *mut BattleObject)> { +#[no_mangle] +pub unsafe extern "Rust" fn get_arrow(object_id: u32) -> Option<(*mut BattleObjectModuleAccessor, *mut BattleObject)> { if object_id == *BATTLE_OBJECT_ID_INVALID as u32 || !sv_battle_object::is_active(object_id) { return None; } @@ -99,11 +68,16 @@ unsafe fn get_arrow(object_id: u32) -> Option<(*mut BattleObjectModuleAccessor, Some((boma, get_battle_object_from_id(object_id))) } -// returns the team the arrow's owner had when the arrow was fused +// attaches an item to the arrow's "top" bone, returning whether it was newly attached #[no_mangle] -pub unsafe extern "Rust" fn fuse_get_owner_team_no(weapon_boma: *mut BattleObjectModuleAccessor) -> i32 { - let (_, owner_object, owner_kind) = fuse_get_owner(weapon_boma); - VarModule::get_int(owner_object, owner_team_no_var(owner_kind)) +pub unsafe extern "Rust" fn fuse_attach_item(item_boma: *mut BattleObjectModuleAccessor, arrow_id: u32) -> bool { + if !LinkModule::is_link(item_boma, *ITEM_LINK_NO_HAVE) { + VisibilityModule::set_whole(item_boma, true); + LinkModule::link(item_boma, *ITEM_LINK_NO_HAVE, arrow_id); + LinkModule::set_model_constraint_pos_ort(item_boma, *ITEM_LINK_NO_HAVE, Hash40::new("top"), Hash40::new("top"), (*CONSTRAINT_FLAG_ORIENTATION | *CONSTRAINT_FLAG_POSITION) as u32, true); + return true; + } + false } // unlinks an item from whatever it is attached to, returning whether it was attached @@ -117,18 +91,6 @@ pub unsafe extern "Rust" fn fuse_detach_item(item_boma: *mut BattleObjectModuleA false } -// attaches an item to the arrow's "top" bone, returning whether it was newly attached -#[no_mangle] -pub unsafe extern "Rust" fn fuse_attach_item(item_boma: *mut BattleObjectModuleAccessor, arrow_id: u32) -> bool { - if !LinkModule::is_link(item_boma, *ITEM_LINK_NO_HAVE) { - VisibilityModule::set_whole(item_boma, true); - LinkModule::link(item_boma, *ITEM_LINK_NO_HAVE, arrow_id); - LinkModule::set_model_constraint_pos_ort(item_boma, *ITEM_LINK_NO_HAVE, Hash40::new("top"), Hash40::new("top"), (*CONSTRAINT_FLAG_ORIENTATION | *CONSTRAINT_FLAG_POSITION) as u32, true); - return true; - } - false -} - // deletes the item fused to an arrow, if any #[no_mangle] pub unsafe extern "Rust" fn fuse_remove_item(arrow_object: *mut BattleObject) { @@ -161,14 +123,7 @@ pub unsafe extern "Rust" fn fuse_set_arrow_params(arrow_boma: *mut BattleObjectM else { id }; - - VarModule::set_int(owner_object, owner_team_no_var(owner_kind), TeamModule::team_no(owner_boma) as i32); - if owner_kind == *FIGHTER_KIND_LINK { - VarModule::set_int(owner_object, vars::link::instance::FUSED_ITEM_ID, item_id as i32); - } - else if owner_kind == *FIGHTER_KIND_KIRBY { - VarModule::set_int(owner_object, vars::kirby::instance::FUSED_ITEM_ID, item_id as i32); - } + VarModule::set_int(owner_object, vars::common::instance::FUSE_TEAM_NO, TeamModule::team_no(owner_boma) as i32); // 0: item travels with the arrow normally // 1: arrow is fired straight and fast @@ -188,6 +143,9 @@ pub unsafe extern "Rust" fn fuse_set_arrow_params(arrow_boma: *mut BattleObjectM VarModule::set_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_TYPE, item_type); VarModule::set_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_POST_STATUS, post_status); VarModule::set_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_ID, item_id as i32); + let owner_ptr = item_owner_id_ptr(item_id); + let item_owner_id = if owner_ptr.is_null() { *BATTLE_OBJECT_ID_INVALID as u32 } else { *owner_ptr }; + VarModule::set_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_OWNER_ID, item_owner_id as i32); } // spawns a new item of the given kind and fuses it to the given arrow @@ -232,15 +190,16 @@ pub unsafe extern "Rust" fn fuse_create_item(arrow_boma: *mut BattleObjectModule // ddd (and kirby with ddd's hat) re-creates the fused item when spitting the arrow back out #[no_mangle] pub unsafe extern "Rust" fn fuse_dedede_common(fighter: &mut L2CFighterCommon) { - let (status, fuse_item_flag, checked_flag, fused_item_kind_var) = if fighter.kind() == *FIGHTER_KIND_KIRBY { - (*FIGHTER_KIRBY_STATUS_KIND_DEDEDE_SPECIAL_N_SHOT_OBJECT_HIT, vars::kirby::instance::FUSE_DEDEDE_ITEM, vars::kirby::instance::FUSE_DEDEDE_ITEM_CHECKED, vars::kirby::instance::FUSE_DEDEDE_ITEM_KIND) + let status = if fighter.kind() == *FIGHTER_KIND_KIRBY { + *FIGHTER_KIRBY_STATUS_KIND_DEDEDE_SPECIAL_N_SHOT_OBJECT_HIT } else { - (*FIGHTER_DEDEDE_STATUS_KIND_SPECIAL_N_SHOT_OBJECT_HIT, vars::dedede::instance::FUSE_ITEM, vars::dedede::instance::FUSE_ITEM_CHECKED, vars::dedede::instance::FUSED_ITEM_KIND) + *FIGHTER_DEDEDE_STATUS_KIND_SPECIAL_N_SHOT_OBJECT_HIT }; + if !fighter.is_status(status) { - VarModule::off_flag(fighter.battle_object, fuse_item_flag); - VarModule::off_flag(fighter.battle_object, checked_flag); + VarModule::off_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM); + VarModule::off_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM_CHECKED); return; } let obj_id = WorkModule::get_int(fighter.module_accessor, *FIGHTER_DEDEDE_STATUS_SPECIAL_N_WORK_INT_SHOT_OBJECT_ID) as u32; @@ -250,8 +209,8 @@ pub unsafe extern "Rust" fn fuse_dedede_common(fighter: &mut L2CFighterCommon) { }; if WorkModule::is_flag(fighter.module_accessor, *FIGHTER_DEDEDE_STATUS_SPECIAL_N_FLAG_SHOT_OBJECT_SHOOT) - && !VarModule::is_flag(fighter.battle_object, checked_flag) { - VarModule::on_flag(fighter.battle_object, checked_flag); + && !VarModule::is_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM_CHECKED) { + VarModule::on_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM_CHECKED); if VarModule::is_flag(obj_object, vars::link_bowarrow::instance::IS_ARROW_FUSE) { // skip if the arrow still carries its item let fused_item_id = VarModule::get_int(obj_object, vars::link_bowarrow::instance::FUSED_ITEM_ID) as u32; @@ -259,18 +218,18 @@ pub unsafe extern "Rust" fn fuse_dedede_common(fighter: &mut L2CFighterCommon) { && LinkModule::is_link(sv_battle_object::module_accessor(fused_item_id), *ITEM_LINK_NO_HAVE); if !is_fused_item_attached { let fused_item = VarModule::get_int(obj_object, vars::link_bowarrow::instance::FUSED_ITEM_KIND); - VarModule::set_int(fighter.battle_object, fused_item_kind_var, fused_item); - VarModule::on_flag(fighter.battle_object, fuse_item_flag); + VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, fused_item); + VarModule::on_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM); } } } - if VarModule::is_flag(fighter.battle_object, fuse_item_flag) + if VarModule::is_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM) && MotionModule::frame(fighter.module_accessor) >= 7.0 { - let item = VarModule::get_int(fighter.battle_object, fused_item_kind_var); + let item = VarModule::get_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND); fuse_create_item(obj_boma, item, fighter.module_accessor, (*fighter.module_accessor).battle_object_id); - VarModule::set_int(fighter.battle_object, fused_item_kind_var, *ITEM_KIND_NONE); - VarModule::off_flag(fighter.battle_object, fuse_item_flag); + VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, *ITEM_KIND_NONE); + VarModule::off_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM); } } @@ -278,14 +237,14 @@ pub unsafe extern "Rust" fn fuse_dedede_common(fighter: &mut L2CFighterCommon) { // the item is re-created when the arrow is pulled back out #[no_mangle] pub unsafe extern "Rust" fn fuse_pocket_common(fighter: &mut L2CFighterCommon) { - let (fused_item_kind_var, target_id_var, team_no_var) = match pocket_vars(fighter.kind()) { - Some(pocket_vars) => pocket_vars, - None => return - }; + if ![*FIGHTER_KIND_MURABITO, *FIGHTER_KIND_SHIZUE, *FIGHTER_KIND_KIRBY].contains(&fighter.kind()) { + return; + } + let search_statuses = if fighter.kind() == *FIGHTER_KIND_KIRBY { let copy_chara = WorkModule::get_int(fighter.module_accessor, *FIGHTER_KIRBY_INSTANCE_WORK_ID_INT_COPY_CHARA); if ![*FIGHTER_KIND_MURABITO, *FIGHTER_KIND_SHIZUE].contains(©_chara) { - VarModule::set_int(fighter.battle_object, fused_item_kind_var, *ITEM_KIND_NONE); + VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, *ITEM_KIND_NONE); } [*FIGHTER_KIRBY_STATUS_KIND_MURABITO_SPECIAL_N_SEARCH, *FIGHTER_KIRBY_STATUS_KIND_SHIZUE_SPECIAL_N_SEARCH] } @@ -295,62 +254,36 @@ pub unsafe extern "Rust" fn fuse_pocket_common(fighter: &mut L2CFighterCommon) { // the pocket is lost on death if fighter.is_status(*FIGHTER_STATUS_KIND_DEAD) { - VarModule::set_int(fighter.battle_object, fused_item_kind_var, *ITEM_KIND_NONE); + VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, *ITEM_KIND_NONE); } if !fighter.is_status_one_of(&search_statuses) { - VarModule::set_int(fighter.battle_object, target_id_var, *BATTLE_OBJECT_ID_INVALID); + VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_TARGET_ID, *BATTLE_OBJECT_ID_INVALID); return; } // kirby's copy abilities use the copied fighter's instance work ids let obj_id = WorkModule::get_int(fighter.module_accessor, *FIGHTER_MURABITO_INSTANCE_WORK_ID_INT_TARGET_OBJECT_ID) as u32; if obj_id == *BATTLE_OBJECT_ID_INVALID as u32 - || obj_id == VarModule::get_int(fighter.battle_object, target_id_var) as u32 { + || obj_id == VarModule::get_int(fighter.battle_object, vars::common::instance::FUSE_STORED_TARGET_ID) as u32 { return; } // handle each pocketed object once, replacing whatever fused item was stored before - VarModule::set_int(fighter.battle_object, target_id_var, obj_id as i32); - VarModule::set_int(fighter.battle_object, fused_item_kind_var, *ITEM_KIND_NONE); + VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_TARGET_ID, obj_id as i32); + VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, *ITEM_KIND_NONE); let obj_object = match get_arrow(obj_id) { Some((_, obj_object)) => obj_object, None => return }; - VarModule::set_int(fighter.battle_object, team_no_var, TeamModule::team_no(fighter.module_accessor) as i32); + VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_TEAM_NO, TeamModule::team_no(fighter.module_accessor) as i32); if VarModule::is_flag(obj_object, vars::link_bowarrow::instance::IS_ARROW_FUSE) { let fused_item = VarModule::get_int(obj_object, vars::link_bowarrow::instance::FUSED_ITEM_KIND); - VarModule::set_int(fighter.battle_object, fused_item_kind_var, fused_item); + VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, fused_item); fuse_remove_item(obj_object); } } -// returns the fused item the arrow's owner has pocketed, if any -#[no_mangle] -pub unsafe extern "Rust" fn fuse_get_pocket_item(weapon_boma: *mut BattleObjectModuleAccessor) -> i32 { - let (_, owner_object, owner_kind) = fuse_get_owner(weapon_boma); - let item = match pocket_vars(owner_kind) { - Some((fused_item_kind_var, _, _)) => VarModule::get_int(owner_object, fused_item_kind_var), - None => *ITEM_KIND_NONE - }; - // the var starts at 0 (ITEM_KIND_ASSIST), which can't be fused - if item > *ITEM_KIND_ASSIST { item } else { *ITEM_KIND_NONE } -} - -// re-creates the owner's pocketed fused item on the arrow being pulled back out -#[no_mangle] -pub unsafe extern "Rust" fn fuse_take_out_pocket_item(weapon_boma: *mut BattleObjectModuleAccessor) { - let item = fuse_get_pocket_item(weapon_boma); - if item == *ITEM_KIND_NONE { - return; - } - let (owner_boma, owner_object, owner_kind) = fuse_get_owner(weapon_boma); - fuse_create_item(weapon_boma, item, weapon_boma, (*owner_boma).battle_object_id); - if let Some((fused_item_kind_var, _, _)) = pocket_vars(owner_kind) { - VarModule::set_int(owner_object, fused_item_kind_var, *ITEM_KIND_NONE); - } -} - // kirby's inhale deletes the fused item #[no_mangle] pub unsafe extern "Rust" fn fuse_kirby_common(fighter: &mut L2CFighterCommon) { @@ -378,29 +311,44 @@ pub unsafe extern "Rust" fn fuse_rosetta_common(fighter: &mut L2CFighterCommon) // drops the fused item if Link's (or Kirby's) NSpecial ends before the arrow is fired #[no_mangle] pub unsafe extern "Rust" fn fuse_special_n_exit(fighter: &mut L2CFighterCommon) { - let (is_arrow_fuse_var, fused_item_id_var) = if fighter.kind() == *FIGHTER_KIND_KIRBY { - (vars::kirby::instance::IS_ARROW_FUSE, vars::kirby::instance::FUSED_ITEM_ID) + if !ArticleModule::is_exist(fighter.module_accessor, *FIGHTER_LINK_GENERATE_ARTICLE_BOWARROW) { + return; } - else { - (vars::link::instance::IS_ARROW_FUSE, vars::link::instance::FUSED_ITEM_ID) - }; - if VarModule::is_flag(fighter.battle_object, is_arrow_fuse_var) - && ArticleModule::is_exist(fighter.module_accessor, *FIGHTER_LINK_GENERATE_ARTICLE_BOWARROW) { - let article = ArticleModule::get_article(fighter.module_accessor, *FIGHTER_LINK_GENERATE_ARTICLE_BOWARROW); - if !article.is_null() { - let arrow_id = smash::app::lua_bind::Article::get_battle_object_id(article) as u32; - if sv_battle_object::is_active(arrow_id) { - VarModule::off_flag(get_battle_object_from_id(arrow_id), vars::link_bowarrow::instance::IS_ARROW_FUSE); - } - } - let item_id = VarModule::get_int(fighter.battle_object, fused_item_id_var) as u32; - if sv_battle_object::is_active(item_id) { - let item_boma = sv_battle_object::module_accessor(item_id); - if fuse_detach_item(item_boma) { - StatusModule::change_status_request(item_boma, *ITEM_STATUS_KIND_FALL, false); - } - } + let arrow_article = ArticleModule::get_article(fighter.module_accessor, *FIGHTER_LINK_GENERATE_ARTICLE_BOWARROW); + if arrow_article.is_null() { + return; + } + + // exit if the arrow is not active + let arrow_id = smash::app::lua_bind::Article::get_battle_object_id(arrow_article) as u32; + if !sv_battle_object::is_active(arrow_id) { + return; + } + + // exit if the arrow is not fused + let arrow_object = get_battle_object_from_id(arrow_id); + if !VarModule::is_flag(arrow_object, vars::link_bowarrow::instance::IS_ARROW_FUSE) { + return; + } + VarModule::off_flag(arrow_object, vars::link_bowarrow::instance::IS_ARROW_FUSE); + + // exit if fused item is not active + let fused_item_id = VarModule::get_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_ID) as u32; + if !sv_battle_object::is_active(fused_item_id) { + return; + } + + // detach the item from the arrow and make it fall + let fused_item_boma = &mut (*sv_battle_object::module_accessor(fused_item_id)); + let fused_item_kind = VarModule::get_int(arrow_object, vars::link_bowarrow::instance::FUSED_ITEM_KIND); + let item_next_status = if fused_item_kind == *ITEM_KIND_LINKBOMB { + (*ITEM_STATUS_KIND_BORN) // links bomb blows up in his face when dropped } - VarModule::off_flag(fighter.battle_object, is_arrow_fuse_var); + else { + (*ITEM_STATUS_KIND_FALL) + }; + fuse_detach_item(fused_item_boma); + restore_fused_item_owner(arrow_object, fused_item_boma); + StatusModule::change_status_request(fused_item_boma, item_next_status, false); } diff --git a/fighters/link/src/bowarrow/status.rs b/fighters/link/src/bowarrow/status.rs index 2dbb04192f..074394ecb4 100644 --- a/fighters/link/src/bowarrow/status.rs +++ b/fighters/link/src/bowarrow/status.rs @@ -2,15 +2,54 @@ use super::*; // symbol-based calls for link's arrow fuse extern "Rust" { + fn restore_fused_item_owner(arrow_object: *mut BattleObject, item_boma: *mut BattleObjectModuleAccessor); fn fuse_get_owner(weapon_boma: *mut BattleObjectModuleAccessor) -> (*mut BattleObjectModuleAccessor, *mut BattleObject, i32); fn fuse_set_arrow_params(arrow_boma: *mut BattleObjectModuleAccessor, item: i32, id: u32); fn fuse_detach_item(item_boma: *mut BattleObjectModuleAccessor) -> bool; fn fuse_attach_item(item_boma: *mut BattleObjectModuleAccessor, arrow_id: u32) -> bool; fn fuse_remove_item(arrow_object: *mut BattleObject); - fn fuse_get_owner_team_no(weapon_boma: *mut BattleObjectModuleAccessor) -> i32; - fn fuse_get_pocket_item(weapon_boma: *mut BattleObjectModuleAccessor) -> i32; - fn fuse_take_out_pocket_item(weapon_boma: *mut BattleObjectModuleAccessor); - fn fuse_on_item_released(item_boma: *mut BattleObjectModuleAccessor); + fn fuse_create_item(arrow_boma: *mut BattleObjectModuleAccessor, item: i32, founder_boma: *mut BattleObjectModuleAccessor, owner_id: u32); +} + +extern "C" { + #[link_name = "_ZN3app10pacmanboss11PACMAN_LIFEEv"] + fn pacmanboss_life() -> i32; +} + +// returns the fused item the arrow's owner has pocketed, if any +unsafe extern "C" fn fuse_get_pocket_item(weapon_boma: *mut BattleObjectModuleAccessor) -> i32 { + let (_, owner_object, _) = fuse_get_owner(weapon_boma); + let item = VarModule::get_int(owner_object, vars::common::instance::FUSE_STORED_ITEM_KIND); + // the var starts at 0 (ITEM_KIND_ASSIST), which can't be fused + if item > *ITEM_KIND_ASSIST { item } else { *ITEM_KIND_NONE } +} + +// re-creates the owner's pocketed fused item on the arrow being pulled back out +unsafe extern "C" fn fuse_take_out_pocket_item(weapon_boma: *mut BattleObjectModuleAccessor) { + let item = fuse_get_pocket_item(weapon_boma); + if item == *ITEM_KIND_NONE { + return; + } + let (owner_boma, owner_object, _) = fuse_get_owner(weapon_boma); + fuse_create_item(weapon_boma, item, weapon_boma, (*owner_boma).battle_object_id); + VarModule::set_int(owner_object, vars::common::instance::FUSE_STORED_ITEM_KIND, *ITEM_KIND_NONE); +} + +// restores item state that is normally set up when a fighter throws the item +unsafe extern "C" fn fuse_on_item_released(arrow_object: *mut BattleObject, item_boma: *mut BattleObjectModuleAccessor) { + restore_fused_item_owner(arrow_object, item_boma); + if utility::get_kind(&mut *item_boma) == *ITEM_KIND_PACMANBOSS { + WorkModule::on_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_THROW); + WorkModule::off_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_DROP); + WorkModule::off_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_HIT); + WorkModule::off_flag(item_boma, *ITEM_PACMAN_INSTANCE_WORK_FLAG_HOP); + WorkModule::set_int(item_boma, 0, *ITEM_PACMAN_INSTANCE_WORK_INT_BOUND_COUNT); + WorkModule::set_int(item_boma, pacmanboss_life(), *ITEM_PACMAN_INSTANCE_WORK_INT_LIFE); + WorkModule::set_int(item_boma, *PACMANBOSS_STATE_FIRST, *ITEM_PACMANBOSS_INSTANCE_WORK_INT_STATE); + WorkModule::set_int(item_boma, 0, *ITEM_PACMANBOSS_INSTANCE_WORK_INT_THROW_FRAME); + WorkModule::set_int(item_boma, 0, *ITEM_PACMANBOSS_INSTANCE_WORK_INT_ROT_FRAME); + WorkModule::set_float(item_boma, 0.0, *ITEM_PACMANBOSS_INSTANCE_WORK_FLOAT_ROT_ANGLE); + } } // WN_LINK_BOWARROW_STATUS_KIND_HAVED // @@ -34,12 +73,6 @@ unsafe extern "C" fn haved_main(weapon: &mut L2CWeaponCommon) -> L2CValue { } } VarModule::set_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_ARROW_FUSE, is_fused); - if owner_kind == *FIGHTER_KIND_LINK { - VarModule::set_flag(owner_object, vars::link::instance::IS_ARROW_FUSE, is_fused); - } - else if owner_kind == *FIGHTER_KIND_KIRBY { - VarModule::set_flag(owner_object, vars::kirby::instance::IS_ARROW_FUSE, is_fused); - } let ret = smashline::original_status(Main, weapon, *WN_LINK_BOWARROW_STATUS_KIND_HAVED)(weapon); if is_fused { @@ -96,7 +129,7 @@ unsafe extern "C" fn fly_end(weapon: &mut L2CWeaponCommon) -> L2CValue { if fuse_detach_item(item_boma) { let status = VarModule::get_int(weapon.battle_object, vars::link_bowarrow::instance::FUSED_ITEM_POST_STATUS); StatusModule::change_status_request(item_boma, status, false); - fuse_on_item_released(item_boma); + fuse_on_item_released(weapon.battle_object, item_boma); } } } @@ -114,8 +147,9 @@ unsafe extern "C" fn fly_end(weapon: &mut L2CWeaponCommon) -> L2CValue { // restores the arrow's team after a reflected fused arrow sticks unsafe extern "C" fn stick_end(weapon: &mut L2CWeaponCommon) -> L2CValue { if VarModule::is_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_REFLECT_FIX) { - let (owner_boma, _, _) = fuse_get_owner(weapon.module_accessor); - TeamModule::set_team(weapon.module_accessor, fuse_get_owner_team_no(weapon.module_accessor), true); + let (owner_boma, owner_object, owner_kind) = fuse_get_owner(weapon.module_accessor); + let owner_team_no = VarModule::get_int(owner_object, vars::common::instance::FUSE_TEAM_NO); + TeamModule::set_team(weapon.module_accessor, owner_team_no, true); TeamModule::set_team_owner_id(weapon.module_accessor, (*owner_boma).battle_object_id); VarModule::off_flag(weapon.battle_object, vars::link_bowarrow::instance::IS_REFLECT_FIX); } diff --git a/romfs/source/fighter/link/motion/body/motion_patch.yaml b/romfs/source/fighter/link/motion/body/motion_patch.yaml index f4b2613cc4..a37a82f112 100644 --- a/romfs/source/fighter/link/motion/body/motion_patch.yaml +++ b/romfs/source/fighter/link/motion/body/motion_patch.yaml @@ -143,6 +143,12 @@ attack_air_f: special_n_start: flags: move: false +special_n_end: + extra: + cancel_frame: 25 +special_air_n_end: + extra: + cancel_frame: 25 special_lw_blast: extra: cancel_frame: 40 diff --git a/romfs/source/fighter/link/param/vl.prcxml b/romfs/source/fighter/link/param/vl.prcxml index 7561132122..7b5385a6f8 100644 --- a/romfs/source/fighter/link/param/vl.prcxml +++ b/romfs/source/fighter/link/param/vl.prcxml @@ -16,6 +16,7 @@ + 60 2.3 11 17 From e39eed475b833cd1415628634bcd9b175e2cef57 Mon Sep 17 00:00:00 2001 From: SuddyN Date: Sat, 10 Oct 2026 16:12:33 -0400 Subject: [PATCH 09/20] fix link crash --- fighters/link/src/opff.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fighters/link/src/opff.rs b/fighters/link/src/opff.rs index 45cc578df5..729ca378c0 100644 --- a/fighters/link/src/opff.rs +++ b/fighters/link/src/opff.rs @@ -38,12 +38,8 @@ unsafe fn shield_scale_fix(fighter: &mut smash::lua2cpp::L2CFighterCommon) { return; } - static mut FUNC_SHIELD_SET_SCALE: usize = 0; - if FUNC_SHIELD_SET_SCALE == 0 { - FUNC_SHIELD_SET_SCALE = smashline::api::get_target_function("lua2cpp_link.nrs", 0x6e40).unwrap_or(0); - } - if FUNC_SHIELD_SET_SCALE != 0 { - let shield_set_scale: extern "C" fn(&mut L2CFighterCommon) = std::mem::transmute(FUNC_SHIELD_SET_SCALE); + if let Some(target) = smashline::api::get_target_function("lua2cpp_link.nrs", 0x6e40) { + let shield_set_scale: extern "C" fn(&mut L2CFighterCommon) = std::mem::transmute(target); shield_set_scale(fighter); } } From 15280218c56cd0855b1b44d442585aa7334af9c1 Mon Sep 17 00:00:00 2001 From: SuddyN Date: Sat, 10 Oct 2026 17:04:08 -0400 Subject: [PATCH 10/20] temp disable DDD fuse arrow solution --- dynamic/src/consts.rs | 4 -- fighters/common/src/opff/fuse.rs | 90 +++++++++++++++++--------------- 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/dynamic/src/consts.rs b/dynamic/src/consts.rs index afa301461b..5d3e179c63 100644 --- a/dynamic/src/consts.rs +++ b/dynamic/src/consts.rs @@ -205,10 +205,6 @@ pub mod vars { pub const DISABLE_FLOAT: i32 = 0x0071; - // link arrow fuse - pub const FUSE_IS_STORED_ITEM: i32 = 0x0072; - pub const FUSE_IS_STORED_ITEM_CHECKED: i32 = 0x0073; - // ints pub const LAST_ATTACK_RECEIVER_ENTRY_ID: i32 = 0x0000; diff --git a/fighters/common/src/opff/fuse.rs b/fighters/common/src/opff/fuse.rs index 63be00feca..ba8983f347 100644 --- a/fighters/common/src/opff/fuse.rs +++ b/fighters/common/src/opff/fuse.rs @@ -187,50 +187,51 @@ pub unsafe extern "Rust" fn fuse_create_item(arrow_boma: *mut BattleObjectModule fuse_set_arrow_params(arrow_boma, item, (*item_boma).battle_object_id); } -// ddd (and kirby with ddd's hat) re-creates the fused item when spitting the arrow back out +// ddd (and kirby with ddd's hat) store and re-create the fused item #[no_mangle] pub unsafe extern "Rust" fn fuse_dedede_common(fighter: &mut L2CFighterCommon) { - let status = if fighter.kind() == *FIGHTER_KIND_KIRBY { - *FIGHTER_KIRBY_STATUS_KIND_DEDEDE_SPECIAL_N_SHOT_OBJECT_HIT - } - else { - *FIGHTER_DEDEDE_STATUS_KIND_SPECIAL_N_SHOT_OBJECT_HIT - }; + // TODO: the code below doesn't work. DDD strips the arrow of its fused item during NSpecial + // the old solution was to store the item on Link and copy it to DDD when he spits the arrow + // but that is unstable for obvious reasons. for now DDD simply spits back a normal arrow - if !fighter.is_status(status) { - VarModule::off_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM); - VarModule::off_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM_CHECKED); - return; - } - let obj_id = WorkModule::get_int(fighter.module_accessor, *FIGHTER_DEDEDE_STATUS_SPECIAL_N_WORK_INT_SHOT_OBJECT_ID) as u32; - let (obj_boma, obj_object) = match get_arrow(obj_id) { - Some(arrow) => arrow, - None => return - }; + // let nspecial_status = if fighter.kind() == *FIGHTER_KIND_KIRBY { + // if WorkModule::get_int(fighter.module_accessor, *FIGHTER_KIRBY_INSTANCE_WORK_ID_INT_COPY_CHARA) != *FIGHTER_KIND_DEDEDE { + // return; + // } + // *FIGHTER_KIRBY_STATUS_KIND_DEDEDE_SPECIAL_N_SHOT_OBJECT_HIT + // } + // else { + // *FIGHTER_DEDEDE_STATUS_KIND_SPECIAL_N_SHOT_OBJECT_HIT + // }; - if WorkModule::is_flag(fighter.module_accessor, *FIGHTER_DEDEDE_STATUS_SPECIAL_N_FLAG_SHOT_OBJECT_SHOOT) - && !VarModule::is_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM_CHECKED) { - VarModule::on_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM_CHECKED); - if VarModule::is_flag(obj_object, vars::link_bowarrow::instance::IS_ARROW_FUSE) { - // skip if the arrow still carries its item - let fused_item_id = VarModule::get_int(obj_object, vars::link_bowarrow::instance::FUSED_ITEM_ID) as u32; - let is_fused_item_attached = sv_battle_object::is_active(fused_item_id) - && LinkModule::is_link(sv_battle_object::module_accessor(fused_item_id), *ITEM_LINK_NO_HAVE); - if !is_fused_item_attached { - let fused_item = VarModule::get_int(obj_object, vars::link_bowarrow::instance::FUSED_ITEM_KIND); - VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, fused_item); - VarModule::on_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM); - } - } - } + // if !fighter.is_status(nspecial_status) { + // VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, *ITEM_KIND_NONE); + // VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_TARGET_ID, *BATTLE_OBJECT_ID_INVALID); + // return; + // } + // let obj_id = WorkModule::get_int(fighter.module_accessor, *FIGHTER_DEDEDE_STATUS_SPECIAL_N_WORK_INT_SHOT_OBJECT_ID) as u32; + // let (obj_boma, obj_object) = match get_arrow(obj_id) { + // Some(arrow) => arrow, + // None => return + // }; - if VarModule::is_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM) - && MotionModule::frame(fighter.module_accessor) >= 7.0 { - let item = VarModule::get_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND); - fuse_create_item(obj_boma, item, fighter.module_accessor, (*fighter.module_accessor).battle_object_id); - VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, *ITEM_KIND_NONE); - VarModule::off_flag(fighter.battle_object, vars::common::instance::FUSE_IS_STORED_ITEM); - } + // // store the arrow's item once, as it comes in + // if obj_id != VarModule::get_int(fighter.battle_object, vars::common::instance::FUSE_STORED_TARGET_ID) as u32 { + // VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_TARGET_ID, obj_id as i32); + // let fused_item = VarModule::get_int(obj_object, vars::link_bowarrow::instance::FUSED_ITEM_KIND); + // let stored_item = if fused_item > *ITEM_KIND_ASSIST { fused_item } else { *ITEM_KIND_NONE }; + // VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, stored_item); + // fuse_remove_item(obj_object); + // } + + // // re-create it once the arrow is spit + // let stored_item = VarModule::get_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND); + // if MotionModule::frame(fighter.module_accessor) >= 7.0 + // && stored_item > *ITEM_KIND_ASSIST + // && WorkModule::is_flag(fighter.module_accessor, *FIGHTER_DEDEDE_STATUS_SPECIAL_N_FLAG_SHOT_OBJECT_SHOOT) { + // fuse_create_item(obj_boma, stored_item, fighter.module_accessor, (*fighter.module_accessor).battle_object_id); + // VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, *ITEM_KIND_NONE); + // } } // villager/isabelle (and kirby with their hat) store the fused item when pocketing the arrow, and delete the original @@ -241,11 +242,18 @@ pub unsafe extern "Rust" fn fuse_pocket_common(fighter: &mut L2CFighterCommon) { return; } - let search_statuses = if fighter.kind() == *FIGHTER_KIND_KIRBY { + if fighter.kind() == *FIGHTER_KIND_KIRBY { let copy_chara = WorkModule::get_int(fighter.module_accessor, *FIGHTER_KIRBY_INSTANCE_WORK_ID_INT_COPY_CHARA); if ![*FIGHTER_KIND_MURABITO, *FIGHTER_KIND_SHIZUE].contains(©_chara) { - VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, *ITEM_KIND_NONE); + // if kirby is not storing a fused arrow, clear the stored item + if copy_chara != *FIGHTER_KIND_DEDEDE { + VarModule::set_int(fighter.battle_object, vars::common::instance::FUSE_STORED_ITEM_KIND, *ITEM_KIND_NONE); + } + return; } + } + + let search_statuses = if fighter.kind() == *FIGHTER_KIND_KIRBY { [*FIGHTER_KIRBY_STATUS_KIND_MURABITO_SPECIAL_N_SEARCH, *FIGHTER_KIRBY_STATUS_KIND_SHIZUE_SPECIAL_N_SEARCH] } else { From ead964421724f689a5759da286cbf841df672bdf Mon Sep 17 00:00:00 2001 From: SuddyN Date: Sat, 10 Oct 2026 19:48:23 -0400 Subject: [PATCH 11/20] link normals adjustments --- fighters/link/src/acmd/aerials.rs | 42 +++++++++++++++---------------- fighters/link/src/acmd/ground.rs | 4 +-- fighters/link/src/acmd/smashes.rs | 12 ++++----- fighters/link/src/acmd/tilts.rs | 32 ++++++++++++++--------- 4 files changed, 49 insertions(+), 41 deletions(-) diff --git a/fighters/link/src/acmd/aerials.rs b/fighters/link/src/acmd/aerials.rs index 563a26e27f..5f90066dcf 100644 --- a/fighters/link/src/acmd/aerials.rs +++ b/fighters/link/src/acmd/aerials.rs @@ -13,22 +13,19 @@ unsafe extern "C" fn game_attackairn(agent: &mut L2CAgentBase) { FT_MOTION_RATE(agent, 1.0); if is_excute(agent) { ATTACK(agent, 0, 0, Hash40::new("kneer"), 10.0, 361, 100, 0, 15, 4.5, -2.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); - ATTACK(agent, 1, 0, Hash40::new("kneer"), 12.0, 361, 100, 0, 15, 4.5, 3.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); - ATTACK(agent, 2, 0, Hash40::new("kneel"), 9.0, 361, 100, 0, 15, 4.0, 1.75, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + ATTACK(agent, 1, 0, Hash40::new("kneer"), 12.0, 361, 100, 0, 15, 4.5, 3.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + ATTACK(agent, 2, 0, Hash40::new("kneel"), 9.0, 361, 100, 0, 15, 4.0, 1.75, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); } wait(lua_state, 3.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("kneer"), 8.0, 361, 100, 0, 10, 4.0, -2.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); - ATTACK(agent, 1, 0, Hash40::new("kneer"), 8.0, 361, 100, 0, 10, 4.0, 3.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); - ATTACK(agent, 2, 0, Hash40::new("kneel"), 8.0, 361, 100, 0, 10, 3.5, 1.75, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + ATTACK(agent, 0, 0, Hash40::new("kneer"), 7.0, 361, 100, 0, 10, 4.0, -2.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + ATTACK(agent, 1, 0, Hash40::new("kneer"), 7.0, 361, 100, 0, 10, 3.5, 3.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + ATTACK(agent, 2, 0, Hash40::new("kneel"), 7.0, 361, 100, 0, 10, 3.5, 1.75, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); } - frame(lua_state, 34.0); + frame(lua_state, 36.0); if is_excute(agent) { AttackModule::clear_all(boma); VarModule::on_flag(agent.battle_object, vars::link::status::ENABLE_SPECIAL_LW_CANCEL); - } - frame(lua_state, 36.0); - if is_excute(agent) { WorkModule::off_flag(boma, *FIGHTER_STATUS_ATTACK_AIR_FLAG_ENABLE_LANDING); } } @@ -44,10 +41,10 @@ unsafe extern "C" fn game_attackairf(agent: &mut L2CAgentBase) { frame(lua_state, 13.0); FT_MOTION_RATE(agent, 1.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 12.0, 361, 103, 0, 30, 3.0, -1.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 12.0, 361, 100, 0, 30, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 30, 3.5, 4.2, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 30, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 11.0, 48, 100, 0, 30, 3.0, -1.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 11.0, 48, 100, 0, 30, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 30, 3.5, 4.2, 0.0, 0.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 30, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); } frame(lua_state, 16.0); FT_MOTION_RATE_RANGE(agent, 16.0, 20.0, 7.0); @@ -128,12 +125,15 @@ unsafe extern "C" fn game_attackairb(agent: &mut L2CAgentBase) { frame(lua_state, 6.0); FT_MOTION_RATE_RANGE(agent, 6.0, 14.0, 10.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("hip"), 5.0, 70, 100, 40, 0, 4.8, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_G, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); - ATTACK(agent, 1, 0, Hash40::new("hip"), 5.0, 365, 100, 40, 0, 4.8, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_A, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); - ATTACK(agent, 2, 0, Hash40::new("kneer"), 5.0, 70, 100, 40, 0, 4.3, -0.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_B, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_G, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); - ATTACK(agent, 3, 0, Hash40::new("kneer"), 5.0, 365, 100, 40, 0, 4.3, -0.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_B, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_A, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); - ATTACK(agent, 4, 0, Hash40::new("kneer"), 5.0, 70, 100, 40, 0, 4.3, 5.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_B, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_G, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); - ATTACK(agent, 5, 0, Hash40::new("kneer"), 5.0, 365, 100, 40, 0, 4.3, 5.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_B, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_A, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + // ground + ATTACK(agent, 0, 0, Hash40::new("hip"), 3.0, 70, 30, 0, 45, 4.8, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_G, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + ATTACK(agent, 1, 0, Hash40::new("kneer"), 3.0, 70, 30, 0, 45, 4.3, -0.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_B, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_G, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + ATTACK(agent, 2, 0, Hash40::new("kneer"), 3.0, 70, 30, 0, 45, 4.3, 5.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_B, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_G, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + + // air + ATTACK(agent, 3, 0, Hash40::new("hip"), 3.0, 365, 30, 0, 45, 4.8, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_A, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + ATTACK(agent, 4, 0, Hash40::new("kneer"), 3.0, 365, 30, 0, 45, 4.3, -0.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_B, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_A, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + ATTACK(agent, 5, 0, Hash40::new("kneer"), 3.0, 365, 30, 0, 45, 4.3, 5.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_B, true, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_A, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); } wait(lua_state, 3.0); if is_excute(agent) { @@ -142,9 +142,9 @@ unsafe extern "C" fn game_attackairb(agent: &mut L2CAgentBase) { frame(lua_state, 14.0); FT_MOTION_RATE(agent, 1.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("hip"), 7.0, 48, 90, 0, 25, 4.8, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + ATTACK(agent, 0, 0, Hash40::new("hip"), 7.0, 48, 90, 0, 25, 4.8, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); ATTACK(agent, 1, 0, Hash40::new("kneel"), 7.0, 48, 90, 0, 25, 4.3, -0.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_B, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); - ATTACK(agent, 2, 0, Hash40::new("kneel"), 7.0, 48, 90, 0, 25, 4.3, 5.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_B, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); + ATTACK(agent, 2, 0, Hash40::new("kneel"), 7.0, 48, 90, 0, 25, 4.3, 5.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_B, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_KICK); } frame(lua_state, 19.0); if is_excute(agent) { diff --git a/fighters/link/src/acmd/ground.rs b/fighters/link/src/acmd/ground.rs index 26bc9a06d3..a4cd8b9bc6 100644 --- a/fighters/link/src/acmd/ground.rs +++ b/fighters/link/src/acmd/ground.rs @@ -4,8 +4,8 @@ unsafe extern "C" fn game_attack11(agent: &mut L2CAgentBase) { let lua_state = agent.lua_state_agent; let boma = agent.boma(); frame(lua_state, 1.0); - FT_MOTION_RATE_RANGE(agent, 1.0, 6.0, 4.0); - frame(lua_state, 6.0); + FT_MOTION_RATE_RANGE(agent, 1.0, 7.0, 4.0); + frame(lua_state, 7.0); FT_MOTION_RATE(agent, 1.0); if is_excute(agent) { ATTACK(agent, 0, 0, Hash40::new("armr"), 4.0, 70, 30, 0, 25, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA_d, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); diff --git a/fighters/link/src/acmd/smashes.rs b/fighters/link/src/acmd/smashes.rs index 9362e91257..6a8f92cd7c 100644 --- a/fighters/link/src/acmd/smashes.rs +++ b/fighters/link/src/acmd/smashes.rs @@ -21,7 +21,7 @@ unsafe extern "C" fn game_attacks4(agent: &mut L2CAgentBase) { } frame(lua_state, 15.0); FT_MOTION_RATE(agent, 1.0); - frame(lua_state, 18.0); + frame(lua_state, 17.0); if is_excute(agent) { AttackModule::clear_all(boma); } @@ -214,11 +214,11 @@ unsafe extern "C" fn game_attackhi4(agent: &mut L2CAgentBase) { frame(lua_state, 41.0); FT_MOTION_RATE(agent, 1.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("sword2"), 9.0, 90, 93, 0, 70, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 10, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 90, 93, 0, 70, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 10, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 9.0, 90, 93, 0, 70, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 10, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("armr"), 9.0, 90, 93, 0, 70, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 10, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 4, 0, Hash40::new("top"), 9.0, 90, 93, 0, 70, 3.0, 0.0, 12.5, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 10, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("sword2"), 9.0, 90, 93, 0, 70, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 10, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 90, 93, 0, 70, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 10, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 9.0, 90, 93, 0, 70, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 10, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("armr"), 9.0, 90, 93, 0, 70, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 10, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 4, 0, Hash40::new("top"), 9.0, 90, 93, 0, 70, 3.0, 0.0, 12.5, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 10, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); } frame(lua_state, 48.0); if is_excute(agent) { diff --git a/fighters/link/src/acmd/tilts.rs b/fighters/link/src/acmd/tilts.rs index bc51146d07..b34caf02c8 100644 --- a/fighters/link/src/acmd/tilts.rs +++ b/fighters/link/src/acmd/tilts.rs @@ -14,10 +14,10 @@ unsafe extern "C" fn game_attacks3(agent: &mut L2CAgentBase) { frame(lua_state, 15.5); FT_MOTION_RATE(agent, 2.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 13.0, 41, 90, 0, 35, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 13.0, 41, 90, 0, 35, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 13.0, 41, 90, 0, 35, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 35, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 13.0, 41, 90, 0, 35, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 13.0, 41, 90, 0, 35, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 13.0, 41, 90, 0, 35, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 35, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); AttackModule::set_attack_height_all(boma, app::AttackHeight(*ATTACK_HEIGHT_HIGH), false); } frame(lua_state, 16.0); @@ -25,6 +25,14 @@ unsafe extern "C" fn game_attacks3(agent: &mut L2CAgentBase) { frame(lua_state, 18.0); FT_MOTION_RATE(agent, 1.0); frame(lua_state, 19.0); + if is_excute(agent) { + ATTACK(agent, 4, 0, Hash40::new("top"), 13.0, 41, 90, 0, 35, 2.5, 0.0, 1.5, 8.0, Some(0.0), Some(1.5), Some(21.0), 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + AttackModule::clear(boma, 0, false); + AttackModule::clear(boma, 1, false); + AttackModule::clear(boma, 2, false); + AttackModule::clear(boma, 3, false); + } + frame(lua_state, 21.0); if is_excute(agent) { AttackModule::clear_all(boma); } @@ -100,10 +108,10 @@ unsafe extern "C" fn game_attackhi3(agent: &mut L2CAgentBase) { let boma = agent.boma(); frame(lua_state, 8.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 9.0, 70, 122, 0, 30, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 70, 122, 0, 30, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 9.0, 70, 122, 0, 30, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 10.0, 85, 115, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 9.0, 70, 122, 0, 30, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 70, 122, 0, 30, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 9.0, 70, 122, 0, 30, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 10.0, 85, 115, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); } frame(lua_state, 14.0); if is_excute(agent) { @@ -142,10 +150,10 @@ unsafe extern "C" fn game_attacklw3(agent: &mut L2CAgentBase) { frame(lua_state, 13.0); FT_MOTION_RATE(agent, 1.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 10.0, 64, 101, 0, 25, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 11.0, 82, 91, 0, 45, 3.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_G, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 11.0, 82, 91, 0, 45, 3.5, 4.25, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 4, 0, Hash40::new("sword2"), 12.0, 82, 91, 0, 50, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 10.0, 64, 101, 0, 25, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 11.0, 82, 91, 0, 45, 3.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_G, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 11.0, 82, 91, 0, 45, 3.5, 4.25, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 4, 0, Hash40::new("sword2"), 12.0, 82, 91, 0, 50, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); AttackModule::set_attack_height_all(boma, app::AttackHeight(*ATTACK_HEIGHT_LOW), false); } frame(lua_state, 16.0); From de092f64a422d1cd680b0b6dadbb769ee5d24161 Mon Sep 17 00:00:00 2001 From: SuddyN Date: Sun, 11 Oct 2026 00:12:16 -0400 Subject: [PATCH 12/20] custom link bomb throw --- dynamic/src/consts.rs | 4 ++ fighters/link/src/acmd/specials.rs | 56 +++++++++++++++ fighters/link/src/status/mod.rs | 12 ++++ fighters/link/src/status/special_lw.rs | 69 +++++++++++++++++++ .../link/motion/body/motion_patch.yaml | 62 ++++++++++++++++- romfs/source/item/common/param/param.prcxml | 4 ++ 6 files changed, 206 insertions(+), 1 deletion(-) diff --git a/dynamic/src/consts.rs b/dynamic/src/consts.rs index 5d3e179c63..7b245506b5 100644 --- a/dynamic/src/consts.rs +++ b/dynamic/src/consts.rs @@ -2231,6 +2231,10 @@ pub mod statuses { pub const SPECIAL_N_FIRE_HI: i32 = 0x1FA; } + pub mod link { + pub const SPECIAL_LW_THROW: i32 = 0x1E8; + } + pub mod littlemac { pub const SPECIAL_LW_CANCEL: i32 = 0x1F4; pub const SPECIAL_LW_CANCEL_JUMP: i32 = 0x1F5; diff --git a/fighters/link/src/acmd/specials.rs b/fighters/link/src/acmd/specials.rs index ad3bdd1af5..823f6f63fb 100644 --- a/fighters/link/src/acmd/specials.rs +++ b/fighters/link/src/acmd/specials.rs @@ -325,9 +325,65 @@ unsafe extern "C" fn effect_specialairhi(agent: &mut L2CAgentBase) { } } +unsafe extern "C" fn game_speciallwthrow(agent: &mut L2CAgentBase) { + let lua_state = agent.lua_state_agent; + let boma = agent.boma(); + frame(lua_state, 7.0); + if is_excute(agent) { + let have_item = ItemModule::get_have_item_id(boma, 0) as u32; + let have_item_boma = sv_battle_object::module_accessor(have_item); + ItemModule::throw_item(boma, 48.0, 2.5, 1.0, 0, true, agent.get_float(*ITEM_FIGHTER_VAR_FLOAT_ITEM_THROW_POWER)); + PostureModule::add_pos_2d(have_item_boma, &Vector2f {x: (8.0 * agent.lr()), y: 0.0}); + } +} + +unsafe extern "C" fn effect_speciallwthrow(agent: &mut L2CAgentBase) { + let lua_state = agent.lua_state_agent; + let boma = agent.boma(); + frame(lua_state, 5.0); + if is_excute(agent) { + LANDING_EFFECT(agent, Hash40::new("sys_atk_smoke"), Hash40::new("top"), 0, 0, 0, 0, 0, 0, 0.9, 0, 0, 0, 0, 0, 0, false); + } +} + +unsafe extern "C" fn sound_speciallwthrow(agent: &mut L2CAgentBase) { + let lua_state = agent.lua_state_agent; + let boma = agent.boma(); + frame(lua_state, 7.0); + if is_excute(agent) { + PLAY_SE(agent, Hash40::new("se_item_item_throw")); + } +} + +unsafe extern "C" fn expression_speciallwthrow(agent: &mut L2CAgentBase) { + let lua_state = agent.lua_state_agent; + let boma = agent.boma(); + if is_excute(agent) { + slope!(agent, *MA_MSC_CMD_SLOPE_SLOPE, *SLOPE_STATUS_LR); + VisibilityModule::set_int64(boma, hash40("shield"), hash40("shield_back")); + } + frame(lua_state, 5.0); + if is_excute(agent) { + ControlModule::set_rumble(boma, Hash40::new("rbkind_nohits"), 5, false, *BATTLE_OBJECT_ID_INVALID as u32); + } + frame(lua_state, 26.0); + if is_excute(agent) { + VisibilityModule::set_int64(boma, hash40("shield"), hash40("shield_normal")); + } +} + pub fn install(agent: &mut Agent) { agent.acmd("game_specialhi", game_specialhi, Priority::Low); agent.acmd("effect_specialhi", effect_specialhi, Priority::Low); agent.acmd("game_specialairhi", game_specialairhi, Priority::Low); agent.acmd("effect_specialairhi", effect_specialairhi, Priority::Low); + + agent.acmd("game_speciallwthrow", game_speciallwthrow, Priority::Low); + agent.acmd("game_specialairlwthrow", game_speciallwthrow, Priority::Low); + agent.acmd("effect_speciallwthrow", effect_speciallwthrow, Priority::Low); + agent.acmd("effect_specialairlwthrow", effect_speciallwthrow, Priority::Low); + agent.acmd("sound_speciallwthrow", sound_speciallwthrow, Priority::Low); + agent.acmd("sound_specialairlwthrow", sound_speciallwthrow, Priority::Low); + agent.acmd("expression_speciallwthrow", expression_speciallwthrow, Priority::Low); + agent.acmd("expression_specialairlwthrow", expression_speciallwthrow, Priority::Low); } diff --git a/fighters/link/src/status/mod.rs b/fighters/link/src/status/mod.rs index 66b8ed961f..6121ec6cb4 100644 --- a/fighters/link/src/status/mod.rs +++ b/fighters/link/src/status/mod.rs @@ -21,7 +21,19 @@ pub unsafe extern "C" fn link_situation_helper(fighter: &mut L2CFighterCommon) - return 0.into() } +// unsafe extern "C" fn should_use_special_lw_callback(fighter: &mut L2CFighterCommon) -> L2CValue { +// return true.into() +// } + +unsafe extern "C" fn on_start(fighter: &mut L2CFighterCommon) { + // fighter.global_table[globals::USE_SPECIAL_LW_CALLBACK].assign(&L2CValue::Ptr(should_use_special_lw_callback as *const () as _)); + fighter.global_table[0x27].assign(&false.into()); // ground special transition handler + fighter.global_table[0x26].assign(&false.into()); // air special transition handler +} + pub fn install(agent: &mut Agent) { + agent.on_start(on_start); + special_n::install(agent); special_hi::install(agent); special_lw::install(agent); diff --git a/fighters/link/src/status/special_lw.rs b/fighters/link/src/status/special_lw.rs index ad03eac111..d773358ff2 100644 --- a/fighters/link/src/status/special_lw.rs +++ b/fighters/link/src/status/special_lw.rs @@ -1,6 +1,11 @@ use super::*; unsafe extern "C" fn special_lw_pre(fighter: &mut L2CFighterCommon) -> L2CValue { + if ItemModule::is_have_item(fighter.module_accessor, 0) + && ItemModule::get_have_item_kind(fighter.module_accessor, 0) == *ITEM_KIND_LINKBOMB { + fighter.set_status_kind_interrupt(statuses::link::SPECIAL_LW_THROW); + return 1.into() + } let ret = smashline::original_status(Pre, fighter, *FIGHTER_STATUS_KIND_SPECIAL_LW)(fighter); FighterStatusModuleImpl::set_fighter_status_data( fighter.module_accessor, @@ -47,7 +52,71 @@ unsafe extern "C" fn special_lw_blast_pre(fighter: &mut L2CFighterCommon) -> L2C return 0.into(); } +// statuses::link::SPECIAL_LW_THROW + +unsafe extern "C" fn special_lw_throw_pre(fighter: &mut L2CFighterCommon) -> L2CValue { + StatusModule::init_settings( + fighter.module_accessor, + app::SituationKind(*SITUATION_KIND_NONE), + *FIGHTER_KINETIC_TYPE_UNIQ, + *GROUND_CORRECT_KIND_KEEP as u32, + app::GroundCliffCheckKind(*GROUND_CLIFF_CHECK_KIND_ON_DROP), + true, + *FIGHTER_STATUS_WORK_KEEP_FLAG_NONE_FLAG, + *FIGHTER_STATUS_WORK_KEEP_FLAG_NONE_INT, + *FIGHTER_STATUS_WORK_KEEP_FLAG_NONE_FLOAT, + 0 + ); + FighterStatusModuleImpl::set_fighter_status_data( + fighter.module_accessor, + false, + *FIGHTER_TREADED_KIND_NO_REAC, + false, + false, + false, + *FIGHTER_LOG_MASK_FLAG_ATTACK_KIND_THROW_ITEM as u64, + *FIGHTER_STATUS_ATTR_START_TURN as u32, + *FIGHTER_POWER_UP_ATTACK_BIT_ITEM_SHOOT as u32, + 0 + ); + 0.into() +} + +unsafe extern "C" fn special_lw_throw_main(fighter: &mut L2CFighterCommon) -> L2CValue { + fighter.change_motion_by_situation("special_lw_throw", "special_air_lw_throw", 0.0, 1.0, false, 0.0, false, false); + fighter.change_kinetic_by_situation(*FIGHTER_KINETIC_TYPE_GROUND_STOP, *FIGHTER_KINETIC_TYPE_MOTION_FALL); + fighter.ground_correct_by_situation(*GROUND_CORRECT_KIND_GROUND, *GROUND_CORRECT_KIND_AIR); + fighter.main_shift(special_lw_throw_main_loop) +} + +unsafe extern "C" fn special_lw_throw_main_loop(fighter: &mut L2CFighterCommon) -> L2CValue { + fighter.sub_air_check_dive(); + if CancelModule::is_enable_cancel(fighter.module_accessor) { + if fighter.sub_wait_ground_check_common(false.into()).get_bool() + || fighter.sub_air_check_fall_common().get_bool() { + return 1.into(); + } + } + if MotionModule::is_end(fighter.module_accessor) { + fighter.change_status_by_situation(*FIGHTER_STATUS_KIND_WAIT, *FIGHTER_STATUS_KIND_FALL, false); + } + if StatusModule::is_situation_changed(fighter.module_accessor) { + fighter.change_motion_inherit_frame_by_situation("special_lw_throw", "special_air_lw_throw", -1.0, 1.0, 0.0, false, false); + fighter.change_kinetic_by_situation(*FIGHTER_KINETIC_TYPE_GROUND_STOP, *FIGHTER_KINETIC_TYPE_MOTION_FALL); + fighter.ground_correct_by_situation(*GROUND_CORRECT_KIND_GROUND, *GROUND_CORRECT_KIND_AIR); + } + 0.into() +} + +unsafe extern "C" fn special_lw_throw_end(fighter: &mut L2CFighterCommon) -> L2CValue { + 0.into() +} + pub fn install(agent: &mut Agent) { agent.status(Pre, *FIGHTER_STATUS_KIND_SPECIAL_LW, special_lw_pre); agent.status(Pre, *FIGHTER_LINK_STATUS_KIND_SPECIAL_LW_BLAST, special_lw_blast_pre); + + agent.status(Pre, statuses::link::SPECIAL_LW_THROW, special_lw_throw_pre); + agent.status(Main, statuses::link::SPECIAL_LW_THROW, special_lw_throw_main); + agent.status(End, statuses::link::SPECIAL_LW_THROW, special_lw_throw_end); } \ No newline at end of file diff --git a/romfs/source/fighter/link/motion/body/motion_patch.yaml b/romfs/source/fighter/link/motion/body/motion_patch.yaml index a37a82f112..415ff03d6c 100644 --- a/romfs/source/fighter/link/motion/body/motion_patch.yaml +++ b/romfs/source/fighter/link/motion/body/motion_patch.yaml @@ -168,4 +168,64 @@ step_pose_back: extra: cancel_frame: 6 cliff_wait: - blend_frames: 2 \ No newline at end of file + blend_frames: 2 +special_lw_throw: + game_script: game_speciallwthrow + flags: + turn: false + loop: false + move: false + fix_trans: false + fix_rot: false + fix_scale: false + unk_40: false + unk_80: true + unk_100: false + unk_200: false + unk_400: false + unk_800: false + unk_1000: false + unk_2000: false + blend_frames: 0 + animations: + - name: h01lightthrowf.nuanmb + unk: 0 + scripts: + - effect_speciallwthrow + - sound_speciallwthrow + - expression_speciallwthrow + extra: + xlu_start: 0 + xlu_end: 0 + cancel_frame: 25 + no_stop_intp: false +special_air_lw_throw: + game_script: game_specialairlwthrow + flags: + turn: false + loop: false + move: false + fix_trans: false + fix_rot: false + fix_scale: false + unk_40: false + unk_80: true + unk_100: false + unk_200: false + unk_400: false + unk_800: false + unk_1000: false + unk_2000: false + blend_frames: 0 + animations: + - name: h02lightthrowairf.nuanmb + unk: 0 + scripts: + - expression_specialairlwthrow + - sound_specialairlwthrow + - effect_specialairlwthrow + extra: + xlu_start: 0 + xlu_end: 0 + cancel_frame: 25 + no_stop_intp: false diff --git a/romfs/source/item/common/param/param.prcxml b/romfs/source/item/common/param/param.prcxml index 0d194da44e..f72bebac55 100644 --- a/romfs/source/item/common/param/param.prcxml +++ b/romfs/source/item/common/param/param.prcxml @@ -147,7 +147,11 @@ dummy 4.2 + 25 2.5 + 0.1 + 0.0 + 0.25 item_shield_kind_hop From e9b59ecc00061f0be1ee388237be44829ae95aac Mon Sep 17 00:00:00 2001 From: SuddyN Date: Sun, 11 Oct 2026 00:19:43 -0400 Subject: [PATCH 13/20] revert health nerf --- romfs/source/item/common/param/param.prcxml | 1 - 1 file changed, 1 deletion(-) diff --git a/romfs/source/item/common/param/param.prcxml b/romfs/source/item/common/param/param.prcxml index f72bebac55..45bb564f47 100644 --- a/romfs/source/item/common/param/param.prcxml +++ b/romfs/source/item/common/param/param.prcxml @@ -147,7 +147,6 @@ dummy 4.2 - 25 2.5 0.1 0.0 From 48b83f087abf445b17d7ebb5d80f69e202a2f420 Mon Sep 17 00:00:00 2001 From: SuddyN Date: Sun, 11 Oct 2026 16:25:42 -0400 Subject: [PATCH 14/20] UTilt rework --- fighters/link/src/acmd/tilts.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/fighters/link/src/acmd/tilts.rs b/fighters/link/src/acmd/tilts.rs index b34caf02c8..69ab6c84da 100644 --- a/fighters/link/src/acmd/tilts.rs +++ b/fighters/link/src/acmd/tilts.rs @@ -108,10 +108,18 @@ unsafe extern "C" fn game_attackhi3(agent: &mut L2CAgentBase) { let boma = agent.boma(); frame(lua_state, 8.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 9.0, 70, 122, 0, 30, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 70, 122, 0, 30, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 9.0, 70, 122, 0, 30, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 10.0, 85, 115, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("head"), 9.0, 99, 122, 0, 30, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 99, 122, 0, 30, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 9.0, 99, 122, 0, 30, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 10.0, 108, 112, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + } + frame(lua_state, 11.0); + if is_excute(agent) { + AttackModule::clear(boma, 0, false); + ATTACK(agent, 0, 0, Hash40::new("armr"), 9.0, 81, 122, 0, 30, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 81, 122, 0, 30, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 9.0, 81, 122, 0, 30, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 10.0, 90, 112, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); } frame(lua_state, 14.0); if is_excute(agent) { From 40523868ebe3cfbb1d42992929cc1961be9885a6 Mon Sep 17 00:00:00 2001 From: SuddyN Date: Mon, 12 Oct 2026 14:20:14 -0400 Subject: [PATCH 15/20] DTilt kb rework --- fighters/link/src/acmd/tilts.rs | 11 ++++------- .../source/fighter/link/motion/body/motion_patch.yaml | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/fighters/link/src/acmd/tilts.rs b/fighters/link/src/acmd/tilts.rs index 69ab6c84da..416d929b65 100644 --- a/fighters/link/src/acmd/tilts.rs +++ b/fighters/link/src/acmd/tilts.rs @@ -153,15 +153,12 @@ unsafe extern "C" fn effect_attackhi3(agent: &mut L2CAgentBase) { unsafe extern "C" fn game_attacklw3(agent: &mut L2CAgentBase) { let lua_state = agent.lua_state_agent; let boma = agent.boma(); - frame(lua_state, 1.0); - FT_MOTION_RATE_RANGE(agent, 1.0, 13.0, 9.0); frame(lua_state, 13.0); - FT_MOTION_RATE(agent, 1.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 10.0, 64, 101, 0, 25, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 11.0, 82, 91, 0, 45, 3.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_G, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 11.0, 82, 91, 0, 45, 3.5, 4.25, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 4, 0, Hash40::new("sword2"), 12.0, 82, 91, 0, 50, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 9.0, 70, 80, 0, 55, 2.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 70, 80, 0, 55, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 11.0, 96, 80, 0, 55, 3.0, 4.25, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 4, 0, Hash40::new("sword2"), 11.0, 96, 80, 0, 55, 3.0, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); AttackModule::set_attack_height_all(boma, app::AttackHeight(*ATTACK_HEIGHT_LOW), false); } frame(lua_state, 16.0); diff --git a/romfs/source/fighter/link/motion/body/motion_patch.yaml b/romfs/source/fighter/link/motion/body/motion_patch.yaml index 415ff03d6c..2a6bef912c 100644 --- a/romfs/source/fighter/link/motion/body/motion_patch.yaml +++ b/romfs/source/fighter/link/motion/body/motion_patch.yaml @@ -100,7 +100,7 @@ attack_13: cancel_frame: 31 attack_lw3: extra: - cancel_frame: 33 + cancel_frame: 30 special_hi: extra: cancel_frame: 80 From b197c74194b5ef7df4399678d7ae1f645863831b Mon Sep 17 00:00:00 2001 From: SuddyN Date: Mon, 12 Oct 2026 15:05:43 -0400 Subject: [PATCH 16/20] reimplement SSpecial statuses --- fighters/link/src/status/mod.rs | 2 + fighters/link/src/status/special_s.rs | 226 ++++++++++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 fighters/link/src/status/special_s.rs diff --git a/fighters/link/src/status/mod.rs b/fighters/link/src/status/mod.rs index 6121ec6cb4..00441b54a1 100644 --- a/fighters/link/src/status/mod.rs +++ b/fighters/link/src/status/mod.rs @@ -3,6 +3,7 @@ use globals::*; // status script import mod special_n; +mod special_s; mod special_hi; mod special_lw; @@ -35,6 +36,7 @@ pub fn install(agent: &mut Agent) { agent.on_start(on_start); special_n::install(agent); + special_s::install(agent); special_hi::install(agent); special_lw::install(agent); } \ No newline at end of file diff --git a/fighters/link/src/status/special_s.rs b/fighters/link/src/status/special_s.rs new file mode 100644 index 0000000000..60e7dde107 --- /dev/null +++ b/fighters/link/src/status/special_s.rs @@ -0,0 +1,226 @@ +use super::*; + +// FIGHTER_STATUS_KIND_SPECIAL_S + +unsafe extern "C" fn special_s_pre(fighter: &mut L2CFighterCommon) -> L2CValue { + let log_mask = if !fighter.is_flag(*FIGHTER_LINK_INSTANCE_WORK_ID_FLAG_BOOMERANG) { + (*FIGHTER_LOG_MASK_FLAG_ATTACK_KIND_SPECIAL_S | *FIGHTER_LOG_MASK_FLAG_ACTION_CATEGORY_ATTACK | *FIGHTER_LOG_MASK_FLAG_ACTION_TRIGGER_ON | *FIGHTER_LOG_MASK_FLAG_SHOOT) as u64 + } + else { + 0 + }; + StatusModule::init_settings( + fighter.module_accessor, + app::SituationKind(*SITUATION_KIND_NONE), + *FIGHTER_KINETIC_TYPE_UNIQ, + *GROUND_CORRECT_KIND_KEEP as u32, + app::GroundCliffCheckKind(*GROUND_CLIFF_CHECK_KIND_NONE), + true, + 0, + 0, + 0, + 0 + ); + FighterStatusModuleImpl::set_fighter_status_data( + fighter.module_accessor, + false, + *FIGHTER_TREADED_KIND_NO_REAC, + false, + false, + false, + log_mask, + *FIGHTER_STATUS_ATTR_START_TURN as u32, + *FIGHTER_POWER_UP_ATTACK_BIT_SPECIAL_S as u32, + 0 + ); + return false.into(); +} + +unsafe extern "C" fn special_s_init(fighter: &mut L2CFighterCommon) -> L2CValue { + let dash_stick_x = fighter.get_param_float("common", "dash_stick_x"); + let flick_frame = FighterControlModuleImpl::get_param_dash_s4_frame(fighter.module_accessor) + fighter.get_param_int("common", "dash_flick_x") as f32; + let stick_x = fighter.global_table[STICK_X].get_f32().abs(); + let flick_x = (ControlModule::get_flick_no_reset_x(fighter.module_accessor) & 0xff) as f32; + if dash_stick_x <= stick_x && flick_x < flick_frame { + fighter.on_flag(*FIGHTER_LINK_STATUS_BOOMERANG_FLAG_FLICK); + fighter.clear_lua_stack(); + lua_args!(fighter, Hash40::new_raw(0x20cbc92683), 1, FIGHTER_LOG_DATA_INT_HAJIKI_NUM); + app::sv_battle_object::notify_event_msc_cmd(fighter.lua_state_agent); + fighter.pop_lua_stack(1); + } + return false.into(); +} + +unsafe extern "C" fn special_s_main(fighter: &mut L2CFighterCommon) -> L2CValue { + PostureModule::set_stick_lr(fighter.module_accessor, 0.0); + PostureModule::update_rot_y_lr(fighter.module_accessor); + let (motion, motion_air) = if fighter.is_flag(*FIGHTER_LINK_INSTANCE_WORK_ID_FLAG_BOOMERANG) { + (hash40("special_s1_blank"), hash40("special_air_s1_blank")) + } + else { + (hash40("special_s1"), hash40("special_air_s1")) + }; + fighter.set_int64(motion, *FIGHTER_LINK_STATUS_BOOMERANG_WORK_INT_MOTION); + fighter.set_int64(motion_air, *FIGHTER_LINK_STATUS_BOOMERANG_WORK_INT_MOTION_AIR); + fighter.sub_shift_status_main(L2CValue::Ptr(special_s_main_loop as *const () as _)) +} + +unsafe extern "C" fn special_s_main_loop(fighter: &mut L2CFighterCommon) -> L2CValue { + if fighter.sub_transition_group_check_air_cliff().get_bool() { + return true.into(); + } + if CancelModule::is_enable_cancel(fighter.module_accessor) + && (fighter.sub_wait_ground_check_common(false.into()).get_bool() + || fighter.sub_air_check_fall_common().get_bool()) { + return false.into(); + } + if !StatusModule::is_changing(fighter.module_accessor) + && MotionModule::is_end(fighter.module_accessor) { + if fighter.global_table[SITUATION_KIND] == SITUATION_KIND_GROUND { + fighter.change_status(FIGHTER_STATUS_KIND_WAIT.into(), false.into()); + return true.into(); + } + if fighter.global_table[SITUATION_KIND] == SITUATION_KIND_AIR { + fighter.change_status(FIGHTER_STATUS_KIND_FALL.into(), false.into()); + return true.into(); + } + } + if link_situation_helper(fighter).get_bool() { + special_s_set_kinetics(fighter); + } + return false.into(); +} + +unsafe extern "C" fn special_s_set_kinetics(fighter: &mut L2CFighterCommon) { + let motion_id = if fighter.global_table[SITUATION_KIND] == SITUATION_KIND_GROUND { + KineticModule::change_kinetic(fighter.module_accessor, *FIGHTER_KINETIC_TYPE_GROUND_STOP); + GroundModule::correct(fighter.module_accessor, app::GroundCorrectKind(*GROUND_CORRECT_KIND_GROUND_CLIFF_STOP_ATTACK)); + *FIGHTER_LINK_STATUS_BOOMERANG_WORK_INT_MOTION + } + else { + KineticModule::change_kinetic(fighter.module_accessor, *FIGHTER_KINETIC_TYPE_AIR_STOP); + GroundModule::correct(fighter.module_accessor, app::GroundCorrectKind(*GROUND_CORRECT_KIND_AIR)); + *FIGHTER_LINK_STATUS_BOOMERANG_WORK_INT_MOTION_AIR + }; + let motion = Hash40::new_raw(fighter.get_int64(motion_id)); + if fighter.is_flag(*FIGHTER_LINK_STATUS_BOOMERANG_FLAG_FIRST) { + MotionModule::change_motion_inherit_frame(fighter.module_accessor, motion, -1.0, 1.0, 0.0, false, false); + } + else { + MotionModule::change_motion(fighter.module_accessor, motion, 0.0, 1.0, false, 0.0, false, false); + fighter.on_flag(*FIGHTER_LINK_STATUS_BOOMERANG_FLAG_FIRST); + } +} + +unsafe extern "C" fn special_s_end(fighter: &mut L2CFighterCommon) -> L2CValue { + return false.into(); +} + +unsafe extern "C" fn special_s_exit(fighter: &mut L2CFighterCommon) -> L2CValue { + if !fighter.is_flag(*FIGHTER_LINK_INSTANCE_WORK_ID_FLAG_BOOMERANG) { + ArticleModule::remove_exist(fighter.module_accessor, *FIGHTER_LINK_GENERATE_ARTICLE_BOOMERANG, app::ArticleOperationTarget(*ARTICLE_OPE_TARGET_ALL)); + } + return false.into(); +} + +// FIGHTER_LINK_STATUS_KIND_SPECIAL_S2 + +unsafe extern "C" fn special_s2_pre(fighter: &mut L2CFighterCommon) -> L2CValue { + StatusModule::init_settings( + fighter.module_accessor, + app::SituationKind(*SITUATION_KIND_NONE), + *FIGHTER_KINETIC_TYPE_UNIQ, + *GROUND_CORRECT_KIND_KEEP as u32, + app::GroundCliffCheckKind(*GROUND_CLIFF_CHECK_KIND_NONE), + true, + 0, + 0, + 0, + 0 + ); + FighterStatusModuleImpl::set_fighter_status_data( + fighter.module_accessor, + false, + *FIGHTER_TREADED_KIND_NO_REAC, + false, + false, + false, + 0, + 0, + *FIGHTER_POWER_UP_ATTACK_BIT_SPECIAL_S as u32, + 0 + ); + false.into() +} + +unsafe extern "C" fn special_s2_main(fighter: &mut L2CFighterCommon) -> L2CValue { + special_s2_set_kinetics(fighter); + fighter.sub_shift_status_main(L2CValue::Ptr(special_s2_main_loop as *const () as _)) +} + +unsafe extern "C" fn special_s2_main_loop(fighter: &mut L2CFighterCommon) -> L2CValue { + if fighter.sub_transition_group_check_air_cliff().get_bool() { + return true.into(); + } + if CancelModule::is_enable_cancel(fighter.module_accessor) + && (fighter.sub_wait_ground_check_common(false.into()).get_bool() + || fighter.sub_air_check_fall_common().get_bool()) { + return false.into(); + } + if MotionModule::is_end(fighter.module_accessor) { + if fighter.global_table[SITUATION_KIND] == SITUATION_KIND_GROUND { + fighter.change_status(FIGHTER_STATUS_KIND_WAIT.into(), false.into()); + return true.into(); + } + if fighter.global_table[SITUATION_KIND] == SITUATION_KIND_AIR { + fighter.change_status(FIGHTER_STATUS_KIND_FALL.into(), false.into()); + return true.into(); + } + } + if !StatusModule::is_changing(fighter.module_accessor) { + let mtrans = fighter.get_int(*FIGHTER_LINK_STATUS_BOOMERANG_CATCH_INT_MTRANS); + if fighter.global_table[PREV_SITUATION_KIND] != mtrans + && fighter.global_table[SITUATION_KIND] == mtrans { + special_s2_set_kinetics(fighter); + } + } + return false.into(); +} + +unsafe extern "C" fn special_s2_set_kinetics(fighter: &mut L2CFighterCommon) { + let (motion, other_situation) = if fighter.global_table[SITUATION_KIND] == SITUATION_KIND_GROUND { + KineticModule::change_kinetic(fighter.module_accessor, *FIGHTER_KINETIC_TYPE_GROUND_STOP); + GroundModule::correct(fighter.module_accessor, app::GroundCorrectKind(*GROUND_CORRECT_KIND_GROUND_CLIFF_STOP_ATTACK)); + (Hash40::new("special_s2"), *SITUATION_KIND_AIR) + } + else { + KineticModule::change_kinetic(fighter.module_accessor, *FIGHTER_KINETIC_TYPE_AIR_STOP); + GroundModule::correct(fighter.module_accessor, app::GroundCorrectKind(*GROUND_CORRECT_KIND_AIR)); + (Hash40::new("special_air_s2"), *SITUATION_KIND_GROUND) + }; + if fighter.is_flag(*FIGHTER_LINK_STATUS_BOOMERANG_CATCH_FLAG_FIRST) { + MotionModule::change_motion_inherit_frame(fighter.module_accessor, motion, -1.0, 1.0, 0.0, false, false); + } + else { + MotionModule::change_motion(fighter.module_accessor, motion, 0.0, 1.0, false, 0.0, false, false); + fighter.on_flag(*FIGHTER_LINK_STATUS_BOOMERANG_CATCH_FLAG_FIRST); + } + fighter.set_int(other_situation, *FIGHTER_LINK_STATUS_BOOMERANG_CATCH_INT_MTRANS); +} + +unsafe extern "C" fn special_s2_end(fighter: &mut L2CFighterCommon) -> L2CValue { + ArticleModule::remove_exist(fighter.module_accessor, *FIGHTER_LINK_GENERATE_ARTICLE_BOOMERANG, app::ArticleOperationTarget(*ARTICLE_OPE_TARGET_ALL)); + return false.into(); +} + +pub fn install(agent: &mut Agent) { + agent.status(Pre, *FIGHTER_STATUS_KIND_SPECIAL_S, special_s_pre); + agent.status(Init, *FIGHTER_STATUS_KIND_SPECIAL_S, special_s_init); + agent.status(Main, *FIGHTER_STATUS_KIND_SPECIAL_S, special_s_main); + agent.status(End, *FIGHTER_STATUS_KIND_SPECIAL_S, special_s_end); + agent.status(Exit, *FIGHTER_STATUS_KIND_SPECIAL_S, special_s_exit); + + agent.status(Pre, *FIGHTER_LINK_STATUS_KIND_SPECIAL_S2, special_s2_pre); + agent.status(Main, *FIGHTER_LINK_STATUS_KIND_SPECIAL_S2, special_s2_main); + agent.status(End, *FIGHTER_LINK_STATUS_KIND_SPECIAL_S2, special_s2_end); +} From f9ae860311e21c35120d30447f1afad3ba469d89 Mon Sep 17 00:00:00 2001 From: SuddyN Date: Mon, 12 Oct 2026 20:31:16 -0400 Subject: [PATCH 17/20] boomerang adjustments --- fighters/link/src/acmd/specials.rs | 52 +++++++++++++++++++ fighters/link/src/boomerang/acmd.rs | 10 ++-- fighters/link/src/status/mod.rs | 19 +++++-- fighters/link/src/status/special_s.rs | 27 +++++----- .../link/motion/body/motion_patch.yaml | 6 +++ 5 files changed, 90 insertions(+), 24 deletions(-) diff --git a/fighters/link/src/acmd/specials.rs b/fighters/link/src/acmd/specials.rs index 823f6f63fb..6ae34cb2c2 100644 --- a/fighters/link/src/acmd/specials.rs +++ b/fighters/link/src/acmd/specials.rs @@ -1,5 +1,52 @@ use super::*; +unsafe extern "C" fn game_specials1(agent: &mut L2CAgentBase) { + let lua_state = agent.lua_state_agent; + let boma = agent.boma(); + frame(lua_state, 5.0); + if is_excute(agent) { + ArticleModule::generate_article(boma, *FIGHTER_LINK_GENERATE_ARTICLE_BOOMERANG, false, -1); + } + + frame(lua_state, 10.0); + let startup = if agent.is_flag(*FIGHTER_LINK_STATUS_BOOMERANG_FLAG_FLICK) { + 28.0 + } else { + 24.0 + }; + FT_MOTION_RATE_RANGE(agent, 10.0, 25.0, startup - 12.0); + + frame(lua_state, 25.0); + FT_MOTION_RATE(agent, 1.0); + + frame(lua_state, 27.0); + let endlag = if agent.is_flag(*FIGHTER_LINK_STATUS_BOOMERANG_FLAG_FLICK) { + 16.0 + } else { + 20.0 + }; + FT_MOTION_RATE_RANGE(agent, 27.0, 46.0, endlag); + if is_excute(agent) { + ArticleModule::shoot(boma, *FIGHTER_LINK_GENERATE_ARTICLE_BOOMERANG, app::ArticleOperationTarget(*ARTICLE_OPE_TARGET_ALL), false); + } + + frame(lua_state, 46.0); + FT_MOTION_RATE(agent, 1.0); +} + +unsafe extern "C" fn sound_specials1(agent: &mut L2CAgentBase) { + let lua_state = agent.lua_state_agent; + let boma = agent.boma(); + frame(lua_state, 3.0); + if is_excute(agent) { + PLAY_SE(agent, Hash40::new("vc_link_attack03")); + } + frame(lua_state, 25.0); + if is_excute(agent) { + PLAY_SE(agent, Hash40::new("se_link_special_s01")); + } +} + unsafe extern "C" fn game_specialhi(agent: &mut L2CAgentBase) { let lua_state = agent.lua_state_agent; let boma = agent.boma(); @@ -373,6 +420,11 @@ unsafe extern "C" fn expression_speciallwthrow(agent: &mut L2CAgentBase) { } pub fn install(agent: &mut Agent) { + agent.acmd("game_specials1", game_specials1, Priority::Low); + agent.acmd("game_specialairs1", game_specials1, Priority::Low); + agent.acmd("sound_specials1", sound_specials1, Priority::Low); + agent.acmd("sound_specialsair1", sound_specials1, Priority::Low); + agent.acmd("game_specialhi", game_specialhi, Priority::Low); agent.acmd("effect_specialhi", effect_specialhi, Priority::Low); agent.acmd("game_specialairhi", game_specialairhi, Priority::Low); diff --git a/fighters/link/src/boomerang/acmd.rs b/fighters/link/src/boomerang/acmd.rs index e5177c8701..6b974a8424 100644 --- a/fighters/link/src/boomerang/acmd.rs +++ b/fighters/link/src/boomerang/acmd.rs @@ -4,16 +4,16 @@ unsafe extern "C" fn game_fly(agent: &mut L2CAgentBase) { let lua_state = agent.lua_state_agent; let boma = agent.boma(); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("top"), 10.0, 80, 29, 0, 91, 4.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_SPEED, false, 0, 0.0, 0, true, false, false, false, false, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_OBJECT); + ATTACK(agent, 0, 0, Hash40::new("top"), 11.0, 78, 41, 0, 60, 3.6, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_SPEED, false, 0, 0.0, 0, true, false, false, false, false, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_OBJECT); AttackModule::enable_safe_pos(boma); } - frame(lua_state, 10.0); + frame(lua_state, 8.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("top"), 8.0, 80, 37, 0, 74, 3.6, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_SPEED, false, 0, 0.0, 0, true, false, false, false, false, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_OBJECT); + ATTACK(agent, 0, 0, Hash40::new("top"), 8.0, 80, 46, 0, 57, 3.6, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_SPEED, false, 0, 0.0, 0, true, false, false, false, false, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_OBJECT); } frame(lua_state, 23.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("top"), 6.0, 80, 44, 0, 55, 3.6, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_SPEED, false, 0, 0.0, 0, true, false, false, false, false, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_OBJECT); + ATTACK(agent, 0, 0, Hash40::new("top"), 5.0, 84, 51, 0, 54, 3.6, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_SPEED, false, 0, 0.0, 0, true, false, false, false, false, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_OBJECT); } } @@ -39,7 +39,7 @@ unsafe extern "C" fn game_turn(agent: &mut L2CAgentBase) { let lua_state = agent.lua_state_agent; let boma = agent.boma(); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("top"), 4.0, 80, 40, 0, 50, 3.6, 0.0, 0.0, 0.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_SPEED, false, 0, 0.0, 0, true, false, false, false, false, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_OBJECT); + ATTACK(agent, 0, 0, Hash40::new("top"), 5.0, 84, 51, 0, 54, 3.6, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_SPEED, false, 0, 0.0, 0, true, false, false, false, false, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_normal"), *ATTACK_SOUND_LEVEL_S, *COLLISION_SOUND_ATTR_KICK, *ATTACK_REGION_OBJECT); } } diff --git a/fighters/link/src/status/mod.rs b/fighters/link/src/status/mod.rs index 00441b54a1..7fbab027a4 100644 --- a/fighters/link/src/status/mod.rs +++ b/fighters/link/src/status/mod.rs @@ -22,12 +22,23 @@ pub unsafe extern "C" fn link_situation_helper(fighter: &mut L2CFighterCommon) - return 0.into() } -// unsafe extern "C" fn should_use_special_lw_callback(fighter: &mut L2CFighterCommon) -> L2CValue { -// return true.into() -// } +// attempting to boomerang when one was already out would use a fail motion anyways +// so lets just prevent using boomerang in that instance, removing the annoying fail motion +unsafe extern "C" fn should_use_special_s_callback(fighter: &mut L2CFighterCommon) -> L2CValue { + if fighter.is_flag(*FIGHTER_LINK_INSTANCE_WORK_ID_FLAG_BOOMERANG) { + return false.into() + } + return true.into() +} + +// fixes some issues where DSpecial wouldn't work unexpectedly +unsafe extern "C" fn should_use_special_lw_callback(fighter: &mut L2CFighterCommon) -> L2CValue { + return true.into() +} unsafe extern "C" fn on_start(fighter: &mut L2CFighterCommon) { - // fighter.global_table[globals::USE_SPECIAL_LW_CALLBACK].assign(&L2CValue::Ptr(should_use_special_lw_callback as *const () as _)); + fighter.global_table[globals::USE_SPECIAL_S_CALLBACK].assign(&L2CValue::Ptr(should_use_special_s_callback as *const () as _)); + fighter.global_table[globals::USE_SPECIAL_LW_CALLBACK].assign(&L2CValue::Ptr(should_use_special_lw_callback as *const () as _)); fighter.global_table[0x27].assign(&false.into()); // ground special transition handler fighter.global_table[0x26].assign(&false.into()); // air special transition handler } diff --git a/fighters/link/src/status/special_s.rs b/fighters/link/src/status/special_s.rs index 60e7dde107..0bdf982b1e 100644 --- a/fighters/link/src/status/special_s.rs +++ b/fighters/link/src/status/special_s.rs @@ -37,17 +37,6 @@ unsafe extern "C" fn special_s_pre(fighter: &mut L2CFighterCommon) -> L2CValue { } unsafe extern "C" fn special_s_init(fighter: &mut L2CFighterCommon) -> L2CValue { - let dash_stick_x = fighter.get_param_float("common", "dash_stick_x"); - let flick_frame = FighterControlModuleImpl::get_param_dash_s4_frame(fighter.module_accessor) + fighter.get_param_int("common", "dash_flick_x") as f32; - let stick_x = fighter.global_table[STICK_X].get_f32().abs(); - let flick_x = (ControlModule::get_flick_no_reset_x(fighter.module_accessor) & 0xff) as f32; - if dash_stick_x <= stick_x && flick_x < flick_frame { - fighter.on_flag(*FIGHTER_LINK_STATUS_BOOMERANG_FLAG_FLICK); - fighter.clear_lua_stack(); - lua_args!(fighter, Hash40::new_raw(0x20cbc92683), 1, FIGHTER_LOG_DATA_INT_HAJIKI_NUM); - app::sv_battle_object::notify_event_msc_cmd(fighter.lua_state_agent); - fighter.pop_lua_stack(1); - } return false.into(); } @@ -88,6 +77,13 @@ unsafe extern "C" fn special_s_main_loop(fighter: &mut L2CFighterCommon) -> L2CV if link_situation_helper(fighter).get_bool() { special_s_set_kinetics(fighter); } + + // tap/hold input for boomerang distance + if fighter.check_hold_input(0, 8, Buttons::SpecialAll) { + fighter.on_flag(*FIGHTER_LINK_STATUS_BOOMERANG_FLAG_FLICK); + notify_event_msc_cmd!(fighter, Hash40::new_raw(0x20cbc92683), 1, FIGHTER_LOG_DATA_INT_HAJIKI_NUM); + } + return false.into(); } @@ -162,10 +158,11 @@ unsafe extern "C" fn special_s2_main_loop(fighter: &mut L2CFighterCommon) -> L2C if fighter.sub_transition_group_check_air_cliff().get_bool() { return true.into(); } - if CancelModule::is_enable_cancel(fighter.module_accessor) - && (fighter.sub_wait_ground_check_common(false.into()).get_bool() - || fighter.sub_air_check_fall_common().get_bool()) { - return false.into(); + if CancelModule::is_enable_cancel(fighter.module_accessor) { + if fighter.sub_wait_ground_check_common(false.into()).get_bool() + || fighter.sub_air_check_fall_common().get_bool() { + return true.into(); + } } if MotionModule::is_end(fighter.module_accessor) { if fighter.global_table[SITUATION_KIND] == SITUATION_KIND_GROUND { diff --git a/romfs/source/fighter/link/motion/body/motion_patch.yaml b/romfs/source/fighter/link/motion/body/motion_patch.yaml index 2a6bef912c..26b1def458 100644 --- a/romfs/source/fighter/link/motion/body/motion_patch.yaml +++ b/romfs/source/fighter/link/motion/body/motion_patch.yaml @@ -229,3 +229,9 @@ special_air_lw_throw: xlu_end: 0 cancel_frame: 25 no_stop_intp: false +special_s2: + extra: + cancel_frame: 1 +special_airs2: + extra: + cancel_frame: 1 \ No newline at end of file From 7e1c1746f67a22b4f5c9ad6d72ea4e9237b62cdd Mon Sep 17 00:00:00 2001 From: SuddyN Date: Mon, 12 Oct 2026 20:55:25 -0400 Subject: [PATCH 18/20] arrow charge nerf --- romfs/source/fighter/link/param/vl.prcxml | 1 + 1 file changed, 1 insertion(+) diff --git a/romfs/source/fighter/link/param/vl.prcxml b/romfs/source/fighter/link/param/vl.prcxml index 7b5385a6f8..407d337946 100644 --- a/romfs/source/fighter/link/param/vl.prcxml +++ b/romfs/source/fighter/link/param/vl.prcxml @@ -8,6 +8,7 @@ + 80 21 dummy From ece1f3c266fdfaf20e6781ffd10991badc2acace Mon Sep 17 00:00:00 2001 From: SuddyN Date: Tue, 13 Oct 2026 00:01:30 -0400 Subject: [PATCH 19/20] more normals adjustments --- fighters/link/src/acmd/smashes.rs | 38 +++++++++++++++---------------- fighters/link/src/acmd/tilts.rs | 14 ++++++------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/fighters/link/src/acmd/smashes.rs b/fighters/link/src/acmd/smashes.rs index 6a8f92cd7c..f9defe6c3d 100644 --- a/fighters/link/src/acmd/smashes.rs +++ b/fighters/link/src/acmd/smashes.rs @@ -11,10 +11,10 @@ unsafe extern "C" fn game_attacks4(agent: &mut L2CAgentBase) { frame(lua_state, 14.75); FT_MOTION_RATE_RANGE(agent, 14.75, 15.0, 1.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 15.0, 45, 93, 0, 25, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 15.0, 45, 93, 0, 25, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 45, 93, 0, 25, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 45, 93, 0, 25, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 15.0, 45, 93, 0, 25, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 15.0, 45, 93, 0, 25, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 45, 93, 0, 25, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 45, 93, 0, 25, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); if DamageModule::damage(boma, 0) == 0.0 { ArticleModule::generate_article(boma,*FIGHTER_LINK_GENERATE_ARTICLE_SWORD_BEAM, false, 0); } @@ -128,11 +128,11 @@ unsafe extern "C" fn game_attacks4s2(agent: &mut L2CAgentBase) { frame(lua_state, 10.0); FT_MOTION_RATE(agent, 1.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("shoulderr"), 19.0, 65, 100, 0, 30, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.25, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("armr"), 19.0, 65, 100, 0, 30, 3.0, 1.0, 0.0, 0.0, None, None, None, 1.25, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 19.0, 65, 100, 0, 30, 3.0, 0.0, 0.0, -2.0, None, None, None, 1.25, 1.0, *ATTACK_SETOFF_KIND_OFF, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 17.0, 65, 100, 0, 30, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 4, 0, Hash40::new("sword2"), 17.0, 65, 100, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("shoulderr"), 19.0, 65, 100, 0, 30, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.2, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("armr"), 19.0, 65, 100, 0, 30, 3.0, 1.0, 0.0, 0.0, None, None, None, 1.2, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 19.0, 65, 100, 0, 30, 3.0, 0.0, 0.0, -2.0, None, None, None, 1.2, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 17.0, 65, 100, 0, 30, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 4, 0, Hash40::new("sword2"), 17.0, 65, 100, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); } frame(lua_state, 11.0); FT_MOTION_RATE_RANGE(agent, 11.0, 11.75, 1.0); @@ -351,11 +351,11 @@ unsafe extern "C" fn game_attacklw4(agent: &mut L2CAgentBase) { } frame(lua_state, 9.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 13.0, 75, 95, 0, 30, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 16.0, 75, 95, 0, 30, 3.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 16.0, 75, 95, 0, 30, 3.5, 4.25, 0.0, 0.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 16.0, 75, 95, 0, 30, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 4, 0, Hash40::new("kneel"), 13.0, 75, 95, 0, 30, 2.7, 0.5, 0.0, -0.9, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 13.0, 75, 95, 0, 30, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 16.0, 75, 95, 0, 30, 3.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 16.0, 75, 95, 0, 30, 3.5, 4.25, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 16.0, 75, 95, 0, 30, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 4, 0, Hash40::new("kneel"), 13.0, 75, 95, 0, 30, 2.7, 0.5, 0.0, -0.9, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); AttackModule::set_attack_height_all(boma, app::AttackHeight(*ATTACK_HEIGHT_LOW), false); } wait(lua_state, 2.0); @@ -364,11 +364,11 @@ unsafe extern "C" fn game_attacklw4(agent: &mut L2CAgentBase) { } frame(lua_state, 21.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 10.0, 75, 98, 0, 20, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 14.0, 86, 72, 0, 40, 3.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 86, 72, 0, 40, 3.5, 4.25, 0.0, 0.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 86, 72, 0, 40, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 4, 0, Hash40::new("kneer"), 10.0, 75, 98, 0, 20, 2.7, 1.5, 0.0, -0.7, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 10.0, 75, 98, 0, 20, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 14.0, 86, 72, 0, 40, 3.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 86, 72, 0, 40, 3.5, 4.25, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 86, 72, 0, 40, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 4, 0, Hash40::new("kneer"), 10.0, 75, 98, 0, 20, 2.7, 1.5, 0.0, -0.7, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); AttackModule::set_attack_height_all(boma, app::AttackHeight(*ATTACK_HEIGHT_LOW), false); } frame(lua_state, 23.0); diff --git a/fighters/link/src/acmd/tilts.rs b/fighters/link/src/acmd/tilts.rs index 416d929b65..e7985ebc29 100644 --- a/fighters/link/src/acmd/tilts.rs +++ b/fighters/link/src/acmd/tilts.rs @@ -14,10 +14,10 @@ unsafe extern "C" fn game_attacks3(agent: &mut L2CAgentBase) { frame(lua_state, 15.5); FT_MOTION_RATE(agent, 2.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 13.0, 41, 90, 0, 35, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 13.0, 41, 90, 0, 35, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 13.0, 41, 90, 0, 35, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 35, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 13.0, 41, 90, 0, 40, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 13.0, 41, 90, 0, 40, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 40, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 40, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); AttackModule::set_attack_height_all(boma, app::AttackHeight(*ATTACK_HEIGHT_HIGH), false); } frame(lua_state, 16.0); @@ -26,7 +26,7 @@ unsafe extern "C" fn game_attacks3(agent: &mut L2CAgentBase) { FT_MOTION_RATE(agent, 1.0); frame(lua_state, 19.0); if is_excute(agent) { - ATTACK(agent, 4, 0, Hash40::new("top"), 13.0, 41, 90, 0, 35, 2.5, 0.0, 1.5, 8.0, Some(0.0), Some(1.5), Some(21.0), 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 4, 0, Hash40::new("top"), 13.0, 41, 90, 0, 40, 2.5, 0.0, 1.5, 8.0, Some(0.0), Some(1.5), Some(21.0), 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); AttackModule::clear(boma, 0, false); AttackModule::clear(boma, 1, false); AttackModule::clear(boma, 2, false); @@ -111,7 +111,7 @@ unsafe extern "C" fn game_attackhi3(agent: &mut L2CAgentBase) { ATTACK(agent, 0, 0, Hash40::new("head"), 9.0, 99, 122, 0, 30, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 99, 122, 0, 30, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); ATTACK(agent, 2, 0, Hash40::new("sword2"), 9.0, 99, 122, 0, 30, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 10.0, 108, 112, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 10.0, 105, 112, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); } frame(lua_state, 11.0); if is_excute(agent) { @@ -119,7 +119,7 @@ unsafe extern "C" fn game_attackhi3(agent: &mut L2CAgentBase) { ATTACK(agent, 0, 0, Hash40::new("armr"), 9.0, 81, 122, 0, 30, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 81, 122, 0, 30, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); ATTACK(agent, 2, 0, Hash40::new("sword2"), 9.0, 81, 122, 0, 30, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 10.0, 90, 112, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 10.0, 87, 112, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); } frame(lua_state, 14.0); if is_excute(agent) { From 8b890402a36e1223441345b0281be9d8b915f8fc Mon Sep 17 00:00:00 2001 From: SuddyN Date: Tue, 13 Oct 2026 22:43:11 -0400 Subject: [PATCH 20/20] quick link followups --- fighters/link/src/acmd/aerials.rs | 4 ++-- fighters/link/src/acmd/smashes.rs | 18 +++++++++--------- fighters/link/src/acmd/specials.rs | 4 ++-- fighters/link/src/acmd/tilts.rs | 20 ++++++++++---------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/fighters/link/src/acmd/aerials.rs b/fighters/link/src/acmd/aerials.rs index 5f90066dcf..887c7baa87 100644 --- a/fighters/link/src/acmd/aerials.rs +++ b/fighters/link/src/acmd/aerials.rs @@ -41,8 +41,8 @@ unsafe extern "C" fn game_attackairf(agent: &mut L2CAgentBase) { frame(lua_state, 13.0); FT_MOTION_RATE(agent, 1.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 11.0, 48, 100, 0, 30, 3.0, -1.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 11.0, 48, 100, 0, 30, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 11.0, 44, 100, 0, 30, 3.0, -1.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 11.0, 44, 100, 0, 30, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 30, 3.5, 4.2, 0.0, 0.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 30, 3.5, 8.5, 0.0, 0.0, None, None, None, 1.1, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); } diff --git a/fighters/link/src/acmd/smashes.rs b/fighters/link/src/acmd/smashes.rs index f9defe6c3d..ca18e1372b 100644 --- a/fighters/link/src/acmd/smashes.rs +++ b/fighters/link/src/acmd/smashes.rs @@ -11,10 +11,10 @@ unsafe extern "C" fn game_attacks4(agent: &mut L2CAgentBase) { frame(lua_state, 14.75); FT_MOTION_RATE_RANGE(agent, 14.75, 15.0, 1.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 15.0, 45, 93, 0, 25, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 15.0, 45, 93, 0, 25, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 45, 93, 0, 25, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 45, 93, 0, 25, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 15.0, 45, 93, 0, 25, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 15.0, 45, 93, 0, 25, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 45, 93, 0, 25, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 45, 93, 0, 25, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); if DamageModule::damage(boma, 0) == 0.0 { ArticleModule::generate_article(boma,*FIGHTER_LINK_GENERATE_ARTICLE_SWORD_BEAM, false, 0); } @@ -128,11 +128,11 @@ unsafe extern "C" fn game_attacks4s2(agent: &mut L2CAgentBase) { frame(lua_state, 10.0); FT_MOTION_RATE(agent, 1.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("shoulderr"), 19.0, 65, 100, 0, 30, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.2, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("armr"), 19.0, 65, 100, 0, 30, 3.0, 1.0, 0.0, 0.0, None, None, None, 1.2, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 19.0, 65, 100, 0, 30, 3.0, 0.0, 0.0, -2.0, None, None, None, 1.2, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 17.0, 65, 100, 0, 30, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 4, 0, Hash40::new("sword2"), 17.0, 65, 100, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 5, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("shoulderr"), 19.0, 65, 100, 0, 30, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.2, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("armr"), 19.0, 65, 100, 0, 30, 3.0, 1.0, 0.0, 0.0, None, None, None, 1.2, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 19.0, 65, 100, 0, 30, 3.0, 0.0, 0.0, -2.0, None, None, None, 1.2, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 17.0, 65, 100, 0, 30, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 4, 0, Hash40::new("sword2"), 17.0, 65, 100, 0, 30, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); } frame(lua_state, 11.0); FT_MOTION_RATE_RANGE(agent, 11.0, 11.75, 1.0); diff --git a/fighters/link/src/acmd/specials.rs b/fighters/link/src/acmd/specials.rs index 6ae34cb2c2..abfab42088 100644 --- a/fighters/link/src/acmd/specials.rs +++ b/fighters/link/src/acmd/specials.rs @@ -12,7 +12,7 @@ unsafe extern "C" fn game_specials1(agent: &mut L2CAgentBase) { let startup = if agent.is_flag(*FIGHTER_LINK_STATUS_BOOMERANG_FLAG_FLICK) { 28.0 } else { - 24.0 + 23.0 }; FT_MOTION_RATE_RANGE(agent, 10.0, 25.0, startup - 12.0); @@ -21,7 +21,7 @@ unsafe extern "C" fn game_specials1(agent: &mut L2CAgentBase) { frame(lua_state, 27.0); let endlag = if agent.is_flag(*FIGHTER_LINK_STATUS_BOOMERANG_FLAG_FLICK) { - 16.0 + 15.0 } else { 20.0 }; diff --git a/fighters/link/src/acmd/tilts.rs b/fighters/link/src/acmd/tilts.rs index e7985ebc29..3a2be0f466 100644 --- a/fighters/link/src/acmd/tilts.rs +++ b/fighters/link/src/acmd/tilts.rs @@ -14,10 +14,10 @@ unsafe extern "C" fn game_attacks3(agent: &mut L2CAgentBase) { frame(lua_state, 15.5); FT_MOTION_RATE(agent, 2.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 13.0, 41, 90, 0, 40, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 13.0, 41, 90, 0, 40, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 40, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 40, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 13.0, 41, 90, 0, 35, 2.5, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 13.0, 41, 90, 0, 35, 3.5, 0.0, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 2, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 35, 3.5, 4.25, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 3, 0, Hash40::new("sword2"), 14.0, 361, 100, 0, 35, 3.5, 8.5, 0.0, -2.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_POS, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); AttackModule::set_attack_height_all(boma, app::AttackHeight(*ATTACK_HEIGHT_HIGH), false); } frame(lua_state, 16.0); @@ -155,8 +155,8 @@ unsafe extern "C" fn game_attacklw3(agent: &mut L2CAgentBase) { let boma = agent.boma(); frame(lua_state, 13.0); if is_excute(agent) { - ATTACK(agent, 0, 0, Hash40::new("armr"), 9.0, 70, 80, 0, 55, 2.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); - ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 70, 80, 0, 55, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 0, 0, Hash40::new("armr"), 9.0, 78, 80, 0, 55, 2.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); + ATTACK(agent, 1, 0, Hash40::new("sword2"), 9.0, 78, 80, 0, 55, 3.0, 0.0, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_M, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); ATTACK(agent, 3, 0, Hash40::new("sword2"), 11.0, 96, 80, 0, 55, 3.0, 4.25, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); ATTACK(agent, 4, 0, Hash40::new("sword2"), 11.0, 96, 80, 0, 55, 3.0, 8.5, 0.0, 0.0, None, None, None, 1.0, 1.0, *ATTACK_SETOFF_KIND_ON, *ATTACK_LR_CHECK_F, false, 0, 0.0, 0, false, false, false, false, true, *COLLISION_SITUATION_MASK_GA, *COLLISION_CATEGORY_MASK_ALL, *COLLISION_PART_MASK_ALL, false, Hash40::new("collision_attr_cutup"), *ATTACK_SOUND_LEVEL_L, *COLLISION_SOUND_ATTR_CUTUP, *ATTACK_REGION_SWORD); AttackModule::set_attack_height_all(boma, app::AttackHeight(*ATTACK_HEIGHT_LOW), false); @@ -165,6 +165,10 @@ unsafe extern "C" fn game_attacklw3(agent: &mut L2CAgentBase) { if is_excute(agent) { AttackModule::clear_all(boma); } + frame(lua_state, 21.0); + if is_excute(agent) { + VarModule::on_flag(agent.battle_object, vars::link::status::ENABLE_SPECIAL_LW_CANCEL); + } } unsafe extern "C" fn effect_attacklw3(agent: &mut L2CAgentBase) { @@ -181,10 +185,6 @@ unsafe extern "C" fn effect_attacklw3(agent: &mut L2CAgentBase) { AFTER_IMAGE_OFF(agent, 4); EFFECT_OFF_KIND(agent, Hash40::new("link_sword"), false, false); } - frame(lua_state, 21.0); - if is_excute(agent) { - VarModule::on_flag(agent.battle_object, vars::link::status::ENABLE_SPECIAL_LW_CANCEL); - } } unsafe extern "C" fn expression_attacklw3(agent: &mut L2CAgentBase) {