From dca75252bd1f59b5ab9b1a15c9452a1c8e94e388 Mon Sep 17 00:00:00 2001 From: UltiNaruto Date: Fri, 21 Jun 2024 04:18:18 +0200 Subject: [PATCH] Spring Ball can now be bound to any items or no items --- src/patch_config.rs | 26 ++++++++++++++- src/patches.rs | 77 ++++++++++++++++++++++++++++++--------------- 2 files changed, 77 insertions(+), 26 deletions(-) diff --git a/src/patch_config.rs b/src/patch_config.rs index eb79abef..5c0367b9 100644 --- a/src/patch_config.rs +++ b/src/patch_config.rs @@ -1319,6 +1319,7 @@ pub struct PatchConfig { pub starting_room: String, pub starting_memo: Option, pub spring_ball: bool, + pub spring_ball_item: PickupType, pub warp_to_start: bool, pub warp_to_start_delay_s: f32, @@ -1418,6 +1419,7 @@ struct GameConfig { starting_room: Option, starting_memo: Option, spring_ball: Option, + spring_ball_item: Option, warp_to_start: Option, warp_to_start_delay_s: Option, @@ -1597,7 +1599,10 @@ impl PatchConfig { .takes_value(true)) .arg(Arg::with_name("spring ball") .long("spring-ball") - .help("Allows player to use spring ball when bombs are acquired")) + .help("Allows player to use spring ball when bombs are acquired if not set")) + .arg(Arg::with_name("spring ball item") + .long("spring-ball-item") + .help("Spring ball checks for this item when enabled")) .arg(Arg::with_name("warp to start") .long("warp-to-start") .help("Allows player to warp to start from any save station")) @@ -1758,6 +1763,9 @@ impl PatchConfig { if let Some(run_mode) = matches.value_of("run mode") { patch_config.run_mode = Some(run_mode.to_string()); } + if let Some(spring_ball_item_str) = matches.value_of("spring ball item") { + patch_config.game_config.spring_ball_item = Some(spring_ball_item_str.to_string()); + } // integer/float if let Some(s) = matches.value_of("seed") { @@ -2428,6 +2436,21 @@ impl PatchConfigPrivate { } }; + let spring_ball_item = { + match self + .game_config + .spring_ball_item + .as_deref() + { + Some(s) => PickupType::from_str(s), + None => PickupType::MorphBallBomb + } + }; + + if spring_ball_item as u32 > PickupType::Nothing as u32 { + panic!("Spring ball item cannot be {}!", spring_ball_item.name()) + } + let result = PatchConfig { run_mode, logbook_filename: self.logbook_filename.clone(), @@ -2497,6 +2520,7 @@ impl PatchConfigPrivate { starting_room, starting_memo: self.game_config.starting_memo.clone(), spring_ball, + spring_ball_item, warp_to_start, warp_to_start_delay_s: self.game_config.warp_to_start_delay_s.unwrap_or(0.0), diff --git a/src/patches.rs b/src/patches.rs index df7e4da6..a0b0b398 100644 --- a/src/patches.rs +++ b/src/patches.rs @@ -10866,7 +10866,10 @@ fn patch_dol( (0x148, 0x268, 0x27c, 0x284, 0x2c0, 0x2bc, 0x778) }; - let spring_ball_patch = ppcasm!(new_text_section_end, { + let compute_spring_ball_movement = new_text_section_end; + let compute_spring_ball_movement_data = compute_spring_ball_movement + 0x1b4; + + let spring_ball_patch_start = ppcasm!(new_text_section_end, { // stack init (at +0x000) stwu r1, -0x20(r1); mflr r0; @@ -10883,8 +10886,8 @@ fn patch_dol( // function body (at +0x02c) lwz r14, 0x84c(r30); lwz r15, 0x8b8(r30); - lis r16, data@h; - addi r16, r16, data@l; + lis r16, { compute_spring_ball_movement_data }@h; + addi r16, r16, { compute_spring_ball_movement_data }@l; lwz r17, { morph_ball_offset }(r14); lfs f1, 0x40(r14); stfs f1, 0x00(r16); @@ -10894,43 +10897,67 @@ fn patch_dol( stfs f1, 0x08(r16); lwz r0, 0x0c(r16); cmplwi r0, 0; - bgt { new_text_section_end + 0x14c }; + bgt { compute_spring_ball_movement + 0x14c }; lwz r0, { movement_state_offset }(r14); cmplwi r0, 0; - beq { new_text_section_end + 0x84 }; - b { new_text_section_end + 0x14c }; + beq { compute_spring_ball_movement + 0x84 }; + b { compute_spring_ball_movement + 0x14c }; cmplwi r0, 4; - bne { new_text_section_end + 0x14c }; + bne { compute_spring_ball_movement + 0x14c }; lwz r0, { out_of_water_ticks_offset }(r14); cmplwi r0, 2; - bne { new_text_section_end + 0x90 }; + bne { compute_spring_ball_movement + 0x90 }; lwz r0, { surface_restraint_type_offset }(r14); - b { new_text_section_end + 0x94 }; + b { compute_spring_ball_movement + 0x94 }; li r0, 4; cmplwi r0, 7; - beq { new_text_section_end + 0x14c }; + beq { compute_spring_ball_movement + 0x14c }; mr r3, r28; bl { symbol_addr!("IsMovementAllowed__10CMorphBallCFv", version) }; cmplwi r3, 0; - beq { new_text_section_end + 0x14c }; - lwz r3, 0x0(r15); - li r4, 6; - bl { symbol_addr!("HasPowerUp__12CPlayerStateCFQ212CPlayerState9EItemType", version) }; - cmplwi r3, 0; - beq { new_text_section_end + 0x14c }; + beq { compute_spring_ball_movement + 0x14c }; + }); + + new_text_section_end += spring_ball_patch_start.encoded_bytes().len() as u32; + new_text_section.extend(spring_ball_patch_start.encoded_bytes()); + + let spring_ball_item_condition_patch = if config.spring_ball_item != PickupType::Nothing { + let _spring_ball_item_condition_patch = ppcasm!(new_text_section_end, { + lwz r3, 0x0(r15); + li r4, { config.spring_ball_item.kind() }; + bl { symbol_addr!("HasPowerUp__12CPlayerStateCFQ212CPlayerState9EItemType", version) }; + cmplwi r3, 0; + beq { compute_spring_ball_movement + 0x14c }; + }); + _spring_ball_item_condition_patch.encoded_bytes() + } else { + let _spring_ball_item_condition_patch = ppcasm!(new_text_section_end, { + nop; + nop; + nop; + nop; + nop; + }); + _spring_ball_item_condition_patch.encoded_bytes() + }; + + new_text_section_end += spring_ball_item_condition_patch.len() as u32; + new_text_section.extend(spring_ball_item_condition_patch); + + let spring_ball_patch_end = ppcasm!(new_text_section_end, { lhz r0, { attached_actor_offset }(r14); cmplwi r0, 65535; - bne { new_text_section_end + 0x14c }; + bne { compute_spring_ball_movement + 0x14c }; addi r3, r14, { energy_drain_offset }; bl { symbol_addr!("GetEnergyDrainIntensity__18CPlayerEnergyDrainCFv", version) }; fcmpu cr0, f1, f14; - bgt { new_text_section_end + 0x14c }; + bgt { compute_spring_ball_movement + 0x14c }; lwz r0, 0x187c(r28); cmplwi r0, 0; - bne { new_text_section_end + 0x14c }; + bne { compute_spring_ball_movement + 0x14c }; lfs f1, 0x14(r29); fcmpu cr0, f1, f14; - ble { new_text_section_end + 0x14c }; + ble { compute_spring_ball_movement + 0x14c }; lfs f16, { velocity_offset }(r14); lfs f17, { velocity_offset + 4 }(r14); mr r3, r14; @@ -10941,7 +10968,7 @@ fn patch_dol( stfs f17, { velocity_offset + 4 }(r14); lfs f17, 0x1dfc(r17); fcmpu cr0, f17, f14; - ble { new_text_section_end + 0x130 }; + ble { compute_spring_ball_movement + 0x130 }; lfs f17, 0x10(r16); lfs f16, { velocity_offset + 8 }(r14); fdivs f16, f16, f17; @@ -10952,10 +10979,10 @@ fn patch_dol( bl { symbol_addr!("SetMoveState__7CPlayerFQ27NPlayer20EPlayerMovementStateR13CStateManager", version) }; li r3, 40; stw r3, 0x0c(r16); - b { new_text_section_end + 0x160 }; + b { compute_spring_ball_movement + 0x160 }; lwz r3, 0x0c(r16); cmplwi r3, 0; - beq { new_text_section_end + 0x160 }; + beq { compute_spring_ball_movement + 0x160 }; addi r3, r3, -1; stw r3, 0x0c(r16); @@ -10993,8 +11020,8 @@ fn patch_dol( .float 1.5; }); - new_text_section_end += spring_ball_patch.encoded_bytes().len() as u32; - new_text_section.extend(spring_ball_patch.encoded_bytes()); + new_text_section_end += spring_ball_patch_end.encoded_bytes().len() as u32; + new_text_section.extend(spring_ball_patch_end.encoded_bytes()); let spring_ball_cooldown = new_text_section_end - 8;