mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-06-26 10:41:53 -04:00
Vanilla bugfix, Hookshot with parent + Hookshot nospawn (#6805)
This commit is contained in:
@@ -2,6 +2,11 @@
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
#include "soh/ShipInit.hpp"
|
||||
|
||||
extern "C" {
|
||||
extern void Player_UseItem(PlayState*, Player*, s32);
|
||||
extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
// Dying or using Din's Fire in the Outside Temple of Time area crashes the game.
|
||||
// In vanilla this can never happen, but with CrowdControl, Sail, Unrestricted Items
|
||||
// and others this *can* happen. Because it checks for a camId of -1, this code path
|
||||
@@ -15,4 +20,30 @@ void RegisterFixOutsideTotCrash() {
|
||||
});
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initFunc(RegisterFixOutsideTotCrash, { "" });
|
||||
// Vanilla bug: If Hookshot doesn't spawn, player is softlocked. (eg. use as child, no memory left)
|
||||
// Fix: Change item to none if no spawn. (Ranged weapon state is removed by `Player_InitItemAction`)
|
||||
void RegisterPreventHookshotNoSpawnSoftlock() {
|
||||
COND_VB_SHOULD(VB_INIT_HOOKSHOT_IA, true, {
|
||||
Player* player = va_arg(args, Player*);
|
||||
if (player->heldActor == NULL) {
|
||||
Player_UseItem(gPlayState, player, 0xFF);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Vanilla bug: When pulling out Hookshot, if `this->actor.parent` is set but not Hookshot, player
|
||||
// is locked into repeated fly-land-fly. Possible with enemies that grab player and set themselves
|
||||
// as parent (such as Moblin in water, eaten by Like like that despawns falling through En_Holl).
|
||||
// Fix: Ensure that parent actor has Hookshot actor ID before starting flying.
|
||||
void RegisterPreventHookshotParentSoftlock() {
|
||||
COND_VB_SHOULD(VB_PREVENT_HOOKSHOT_PARENT_SOFTLOCK, true, {
|
||||
s16* parentId = va_arg(args, s16*);
|
||||
if (*parentId != ACTOR_ARMS_HOOK) {
|
||||
*should = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static RegisterShipInitFunc initFuncFixOutsideTotCrash(RegisterFixOutsideTotCrash, { "" });
|
||||
static RegisterShipInitFunc initFuncHookshotNospawnSoftlock(RegisterPreventHookshotNoSpawnSoftlock, { "" });
|
||||
static RegisterShipInitFunc initFuncHookshotParentSoftlock(RegisterPreventHookshotParentSoftlock, { "" });
|
||||
|
||||
@@ -3066,6 +3066,22 @@ typedef enum {
|
||||
// - `*EnItem00`
|
||||
VB_ITEM00_KILL,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// true
|
||||
// ```
|
||||
// #### `args`
|
||||
// - `*Player`
|
||||
VB_INIT_HOOKSHOT_IA,
|
||||
|
||||
// #### `result`
|
||||
// ```c
|
||||
// !(this->stateFlags1 & PLAYER_STATE1_ON_HORSE) && Player_HoldsHookshot(this)
|
||||
// ```
|
||||
// #### `args`
|
||||
// - `s16* (&this->actor.parent->id)`
|
||||
VB_PREVENT_HOOKSHOT_PARENT_SOFTLOCK,
|
||||
|
||||
// true
|
||||
// ```
|
||||
// #### `args`
|
||||
|
||||
@@ -2300,6 +2300,8 @@ void Player_InitHookshotIA(PlayState* play, Player* this) {
|
||||
this->heldActor =
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_ARMS_HOOK, this->actor.world.pos.x,
|
||||
this->actor.world.pos.y, this->actor.world.pos.z, 0, this->actor.shape.rot.y, 0, 0);
|
||||
|
||||
GameInteractor_Should(VB_INIT_HOOKSHOT_IA, true, this);
|
||||
}
|
||||
|
||||
void Player_InitBoomerangIA(PlayState* play, Player* this) {
|
||||
@@ -3572,7 +3574,10 @@ int Player_CanUpdateItems(Player* this) {
|
||||
* depending on some conditions. See details below.
|
||||
*/
|
||||
s32 Player_UpdateUpperBody(Player* this, PlayState* play) {
|
||||
if (!(this->stateFlags1 & PLAYER_STATE1_ON_HORSE) && (this->actor.parent != NULL) && Player_HoldsHookshot(this)) {
|
||||
if (this->actor.parent != NULL &&
|
||||
GameInteractor_Should(VB_PREVENT_HOOKSHOT_PARENT_SOFTLOCK,
|
||||
!(this->stateFlags1 & PLAYER_STATE1_ON_HORSE) && Player_HoldsHookshot(this),
|
||||
&this->actor.parent->id)) {
|
||||
Player_SetupAction(play, this, Player_Action_80850AEC, 1);
|
||||
this->stateFlags3 |= PLAYER_STATE3_FLYING_WITH_HOOKSHOT;
|
||||
Player_AnimPlayOnce(play, this, &gPlayerAnim_link_hook_fly_start);
|
||||
|
||||
Reference in New Issue
Block a user