mirror of
https://github.com/zeldaret/oot.git
synced 2024-12-29 00:06:33 +00:00
Document Hookshot Attachment (#2300)
* document hookshot attachment * change comment * swap hookshot function comment * remove comments
This commit is contained in:
parent
e0e0e93644
commit
6239f8e0b3
10 changed files with 83 additions and 59 deletions
|
@ -153,8 +153,13 @@ typedef struct ActorShape {
|
|||
// Actor will not shake when a quake occurs
|
||||
#define ACTOR_FLAG_IGNORE_QUAKE (1 << 12)
|
||||
|
||||
// The hookshot is currently attached to this actor.
|
||||
// The behavior that occurs after attachment is determined by `ACTOR_FLAG_9` and `ACTOR_FLAG_10`.
|
||||
// If neither of those flags are set attachment cannot occur, and the hookshot will simply act as a damage source.
|
||||
//
|
||||
#define ACTOR_FLAG_13 (1 << 13)
|
||||
// This flag is also reused to indicate that an actor is attached to the boomerang.
|
||||
// This only has an effect for Gold Skulltula Tokens (EN_SI) which has overlapping behavior for hookshot and boomerang
|
||||
#define ACTOR_FLAG_HOOKSHOT_ATTACHED (1 << 13)
|
||||
|
||||
// When hit by an arrow, the actor will be able to attach to the arrow and fly with it in the air
|
||||
#define ACTOR_FLAG_CAN_ATTACH_TO_ARROW (1 << 14)
|
||||
|
@ -806,7 +811,7 @@ int func_8002DD6C(struct Player* player);
|
|||
int func_8002DD78(struct Player* player);
|
||||
s32 func_8002DDE4(struct PlayState* play);
|
||||
s32 func_8002DDF4(struct PlayState* play);
|
||||
void func_8002DE04(struct PlayState* play, Actor* actorA, Actor* actorB);
|
||||
void Actor_SwapHookshotAttachment(struct PlayState* play, Actor* srcActor, Actor* destActor);
|
||||
void func_8002DE74(struct PlayState* play, struct Player* player);
|
||||
void Actor_MountHorse(struct PlayState* play, struct Player* player, Actor* horse);
|
||||
int func_8002DEEC(struct Player* player);
|
||||
|
|
|
@ -1119,15 +1119,24 @@ s32 func_8002DDF4(PlayState* play) {
|
|||
return player->stateFlags2 & PLAYER_STATE2_12;
|
||||
}
|
||||
|
||||
void func_8002DE04(PlayState* play, Actor* actorA, Actor* actorB) {
|
||||
/**
|
||||
* Swap hookshot attachment state from one actor to another.
|
||||
*
|
||||
* Note: There is no safety check for a NULL hookshot pointer.
|
||||
* The responsibility is on the caller to make sure the hookshot exists.
|
||||
*/
|
||||
void Actor_SwapHookshotAttachment(PlayState* play, Actor* srcActor, Actor* destActor) {
|
||||
ArmsHook* hookshot = (ArmsHook*)Actor_Find(&play->actorCtx, ACTOR_ARMS_HOOK, ACTORCAT_ITEMACTION);
|
||||
|
||||
hookshot->grabbed = actorB;
|
||||
hookshot->grabbedDistDiff.x = 0.0f;
|
||||
hookshot->grabbedDistDiff.y = 0.0f;
|
||||
hookshot->grabbedDistDiff.z = 0.0f;
|
||||
actorB->flags |= ACTOR_FLAG_13;
|
||||
actorA->flags &= ~ACTOR_FLAG_13;
|
||||
hookshot->attachedActor = destActor;
|
||||
|
||||
// The hookshot will attach at exactly the actors world position with 0 offset
|
||||
hookshot->attachPointOffset.x = 0.0f;
|
||||
hookshot->attachPointOffset.y = 0.0f;
|
||||
hookshot->attachPointOffset.z = 0.0f;
|
||||
|
||||
destActor->flags |= ACTOR_FLAG_HOOKSHOT_ATTACHED;
|
||||
srcActor->flags &= ~ACTOR_FLAG_HOOKSHOT_ATTACHED;
|
||||
}
|
||||
|
||||
void func_8002DE74(PlayState* play, Player* player) {
|
||||
|
|
|
@ -74,9 +74,10 @@ void ArmsHook_Init(Actor* thisx, PlayState* play) {
|
|||
void ArmsHook_Destroy(Actor* thisx, PlayState* play) {
|
||||
ArmsHook* this = (ArmsHook*)thisx;
|
||||
|
||||
if (this->grabbed != NULL) {
|
||||
this->grabbed->flags &= ~ACTOR_FLAG_13;
|
||||
if (this->attachedActor != NULL) {
|
||||
this->attachedActor->flags &= ~ACTOR_FLAG_HOOKSHOT_ATTACHED;
|
||||
}
|
||||
|
||||
Collider_DestroyQuad(play, &this->collider);
|
||||
}
|
||||
|
||||
|
@ -109,10 +110,10 @@ s32 ArmsHook_AttachToPlayer(ArmsHook* this, Player* player) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void ArmsHook_DetachHookFromActor(ArmsHook* this) {
|
||||
if (this->grabbed != NULL) {
|
||||
this->grabbed->flags &= ~ACTOR_FLAG_13;
|
||||
this->grabbed = NULL;
|
||||
void ArmsHook_DetachFromActor(ArmsHook* this) {
|
||||
if (this->attachedActor != NULL) {
|
||||
this->attachedActor->flags &= ~ACTOR_FLAG_HOOKSHOT_ATTACHED;
|
||||
this->attachedActor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +124,7 @@ s32 ArmsHook_CheckForCancel(ArmsHook* this) {
|
|||
if ((player->itemAction != player->heldItemAction) || (player->actor.flags & ACTOR_FLAG_TALK) ||
|
||||
((player->stateFlags1 & (PLAYER_STATE1_DEAD | PLAYER_STATE1_26)))) {
|
||||
this->timer = 0;
|
||||
ArmsHook_DetachHookFromActor(this);
|
||||
ArmsHook_DetachFromActor(this);
|
||||
Math_Vec3f_Copy(&this->actor.world.pos, &player->unk_3C8);
|
||||
return 1;
|
||||
}
|
||||
|
@ -131,17 +132,17 @@ s32 ArmsHook_CheckForCancel(ArmsHook* this) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void ArmsHook_AttachHookToActor(ArmsHook* this, Actor* actor) {
|
||||
actor->flags |= ACTOR_FLAG_13;
|
||||
this->grabbed = actor;
|
||||
Math_Vec3f_Diff(&actor->world.pos, &this->actor.world.pos, &this->grabbedDistDiff);
|
||||
void ArmsHook_AttachToActor(ArmsHook* this, Actor* actor) {
|
||||
actor->flags |= ACTOR_FLAG_HOOKSHOT_ATTACHED;
|
||||
this->attachedActor = actor;
|
||||
Math_Vec3f_Diff(&actor->world.pos, &this->actor.world.pos, &this->attachPointOffset);
|
||||
}
|
||||
|
||||
void ArmsHook_Shoot(ArmsHook* this, PlayState* play) {
|
||||
Player* player = GET_PLAYER(play);
|
||||
|
||||
if ((this->actor.parent == NULL) || (!Player_HoldsHookshot(player))) {
|
||||
ArmsHook_DetachHookFromActor(this);
|
||||
ArmsHook_DetachFromActor(this);
|
||||
Actor_Kill(&this->actor);
|
||||
return;
|
||||
}
|
||||
|
@ -155,7 +156,8 @@ void ArmsHook_Shoot(ArmsHook* this, PlayState* play) {
|
|||
|
||||
if ((touchedActor->update != NULL) && (touchedActor->flags & (ACTOR_FLAG_9 | ACTOR_FLAG_10))) {
|
||||
if (this->collider.elem.atHitElem->acElemFlags & ACELEM_HOOKABLE) {
|
||||
ArmsHook_AttachHookToActor(this, touchedActor);
|
||||
ArmsHook_AttachToActor(this, touchedActor);
|
||||
|
||||
if (CHECK_FLAG_ALL(touchedActor->flags, ACTOR_FLAG_10)) {
|
||||
func_80865044(this);
|
||||
}
|
||||
|
@ -168,41 +170,50 @@ void ArmsHook_Shoot(ArmsHook* this, PlayState* play) {
|
|||
}
|
||||
|
||||
if (DECR(this->timer) == 0) {
|
||||
Actor* grabbed;
|
||||
Actor* attachedActor;
|
||||
Vec3f bodyDistDiffVec;
|
||||
Vec3f newPos;
|
||||
f32 bodyDistDiff;
|
||||
f32 phi_f16;
|
||||
s32 pad1;
|
||||
f32 curGrabbedDist;
|
||||
f32 grabbedDist;
|
||||
f32 curActorOffsetXYZ;
|
||||
f32 attachPointOffsetXYZ;
|
||||
f32 velocity;
|
||||
|
||||
grabbed = this->grabbed;
|
||||
if (grabbed != NULL) {
|
||||
if ((grabbed->update == NULL) || !CHECK_FLAG_ALL(grabbed->flags, ACTOR_FLAG_13)) {
|
||||
grabbed = NULL;
|
||||
this->grabbed = NULL;
|
||||
attachedActor = this->attachedActor;
|
||||
|
||||
if (attachedActor != NULL) {
|
||||
if ((attachedActor->update == NULL) ||
|
||||
!CHECK_FLAG_ALL(attachedActor->flags, ACTOR_FLAG_HOOKSHOT_ATTACHED)) {
|
||||
attachedActor = NULL;
|
||||
this->attachedActor = NULL;
|
||||
} else if (this->actor.child != NULL) {
|
||||
curGrabbedDist = Actor_WorldDistXYZToActor(&this->actor, grabbed);
|
||||
grabbedDist =
|
||||
sqrtf(SQ(this->grabbedDistDiff.x) + SQ(this->grabbedDistDiff.y) + SQ(this->grabbedDistDiff.z));
|
||||
Math_Vec3f_Diff(&grabbed->world.pos, &this->grabbedDistDiff, &this->actor.world.pos);
|
||||
if ((curGrabbedDist - grabbedDist) > 50.0f) {
|
||||
ArmsHook_DetachHookFromActor(this);
|
||||
grabbed = NULL;
|
||||
curActorOffsetXYZ = Actor_WorldDistXYZToActor(&this->actor, attachedActor);
|
||||
attachPointOffsetXYZ = sqrtf(SQ(this->attachPointOffset.x) + SQ(this->attachPointOffset.y) +
|
||||
SQ(this->attachPointOffset.z));
|
||||
|
||||
// Keep the hookshot actor at the same relative offset as the initial attachment even if the actor moves
|
||||
Math_Vec3f_Diff(&attachedActor->world.pos, &this->attachPointOffset, &this->actor.world.pos);
|
||||
|
||||
// If the actor the hookshot is attached to is moving, the hookshot's current relative
|
||||
// position will be different than the initial attachment position.
|
||||
// If the distance between those two points is larger than 50 units, detach the hookshot.
|
||||
if ((curActorOffsetXYZ - attachPointOffsetXYZ) > 50.0f) {
|
||||
ArmsHook_DetachFromActor(this);
|
||||
attachedActor = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bodyDistDiff = Math_Vec3f_DistXYZAndStoreDiff(&player->unk_3C8, &this->actor.world.pos, &bodyDistDiffVec);
|
||||
|
||||
if (bodyDistDiff < 30.0f) {
|
||||
velocity = 0.0f;
|
||||
phi_f16 = 0.0f;
|
||||
} else {
|
||||
if (this->actor.child != NULL) {
|
||||
velocity = 30.0f;
|
||||
} else if (grabbed != NULL) {
|
||||
} else if (attachedActor != NULL) {
|
||||
velocity = 50.0f;
|
||||
} else {
|
||||
velocity = 200.0f;
|
||||
|
@ -219,13 +230,13 @@ void ArmsHook_Shoot(ArmsHook* this, PlayState* play) {
|
|||
newPos.z = bodyDistDiffVec.z * velocity;
|
||||
|
||||
if (this->actor.child == NULL) {
|
||||
if ((grabbed != NULL) && (grabbed->id == ACTOR_BG_SPOT06_OBJECTS)) {
|
||||
Math_Vec3f_Diff(&grabbed->world.pos, &this->grabbedDistDiff, &this->actor.world.pos);
|
||||
if ((attachedActor != NULL) && (attachedActor->id == ACTOR_BG_SPOT06_OBJECTS)) {
|
||||
Math_Vec3f_Diff(&attachedActor->world.pos, &this->attachPointOffset, &this->actor.world.pos);
|
||||
phi_f16 = 1.0f;
|
||||
} else {
|
||||
Math_Vec3f_Sum(&player->unk_3C8, &newPos, &this->actor.world.pos);
|
||||
if (grabbed != NULL) {
|
||||
Math_Vec3f_Sum(&this->actor.world.pos, &this->grabbedDistDiff, &grabbed->world.pos);
|
||||
if (attachedActor != NULL) {
|
||||
Math_Vec3f_Sum(&this->actor.world.pos, &this->attachPointOffset, &attachedActor->world.pos);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -235,7 +246,7 @@ void ArmsHook_Shoot(ArmsHook* this, PlayState* play) {
|
|||
}
|
||||
|
||||
if (phi_f16 < 50.0f) {
|
||||
ArmsHook_DetachHookFromActor(this);
|
||||
ArmsHook_DetachFromActor(this);
|
||||
if (phi_f16 == 0.0f) {
|
||||
ArmsHook_SetupAction(this, ArmsHook_Wait);
|
||||
if (ArmsHook_AttachToPlayer(this, player)) {
|
||||
|
@ -274,8 +285,9 @@ void ArmsHook_Shoot(ArmsHook* this, PlayState* play) {
|
|||
|
||||
if (bgId != BGCHECK_SCENE) {
|
||||
dynaPolyActor = DynaPoly_GetActor(&play->colCtx, bgId);
|
||||
|
||||
if (dynaPolyActor != NULL) {
|
||||
ArmsHook_AttachHookToActor(this, &dynaPolyActor->actor);
|
||||
ArmsHook_AttachToActor(this, &dynaPolyActor->actor);
|
||||
}
|
||||
}
|
||||
func_80865044(this);
|
||||
|
|
|
@ -14,8 +14,8 @@ typedef struct ArmsHook {
|
|||
/* 0x01CC */ WeaponInfo hookInfo;
|
||||
/* 0x01E8 */ Vec3f unk_1E8;
|
||||
/* 0x01F4 */ Vec3f unk_1F4;
|
||||
/* 0x0200 */ Actor* grabbed;
|
||||
/* 0x0204 */ Vec3f grabbedDistDiff;
|
||||
/* 0x0200 */ Actor* attachedActor;
|
||||
/* 0x0204 */ Vec3f attachPointOffset; // Distance from the hookshot attach point to world pos of `attachedActor`
|
||||
/* 0x0210 */ s16 timer;
|
||||
/* 0x0214 */ ArmsHookActionFunc actionFunc;
|
||||
} ArmsHook; // size = 0x0218
|
||||
|
|
|
@ -335,7 +335,7 @@ void BgSpot06Objects_LockPullOutward(BgSpot06Objects* this, PlayState* play) {
|
|||
|
||||
if (this->timer == 0) {
|
||||
this->dyna.actor.velocity.y = 0.5f;
|
||||
this->dyna.actor.flags &= ~ACTOR_FLAG_13;
|
||||
this->dyna.actor.flags &= ~ACTOR_FLAG_HOOKSHOT_ATTACHED;
|
||||
|
||||
this->actionFunc = BgSpot06Objects_LockSwimToSurface;
|
||||
}
|
||||
|
|
|
@ -894,7 +894,7 @@ void BossSst_HeadVulnerable(BossSst* this, PlayState* play) {
|
|||
Math_StepToF(&sHandOffsets[RIGHT].z, 600.0f, 20.0f);
|
||||
Math_StepToF(&sHandOffsets[LEFT].x, 200.0f, 20.0f);
|
||||
Math_StepToF(&sHandOffsets[RIGHT].x, -200.0f, 20.0f);
|
||||
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_13)) {
|
||||
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_HOOKSHOT_ATTACHED)) {
|
||||
this->timer += 2;
|
||||
this->timer = CLAMP_MAX(this->timer, 50);
|
||||
} else {
|
||||
|
|
|
@ -160,7 +160,7 @@ void EnBoom_Fly(EnBoom* this, PlayState* play) {
|
|||
if (((this->collider.base.at->id == ACTOR_EN_ITEM00) || (this->collider.base.at->id == ACTOR_EN_SI))) {
|
||||
this->grabbed = this->collider.base.at;
|
||||
if (this->collider.base.at->id == ACTOR_EN_SI) {
|
||||
this->collider.base.at->flags |= ACTOR_FLAG_13;
|
||||
this->collider.base.at->flags |= ACTOR_FLAG_HOOKSHOT_ATTACHED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ void EnBoom_Fly(EnBoom* this, PlayState* play) {
|
|||
target->gravity = -0.9f;
|
||||
target->bgCheckFlags &= ~(BGCHECKFLAG_GROUND | BGCHECKFLAG_GROUND_TOUCH);
|
||||
} else {
|
||||
target->flags &= ~ACTOR_FLAG_13;
|
||||
target->flags &= ~ACTOR_FLAG_HOOKSHOT_ATTACHED;
|
||||
}
|
||||
}
|
||||
// Set player flags and kill the boomerang beacause Link caught it.
|
||||
|
|
|
@ -228,8 +228,8 @@ s32 EnFd_SpawnCore(EnFd* this, PlayState* play) {
|
|||
this->actor.child->colChkInfo.health = 8;
|
||||
}
|
||||
|
||||
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_13)) {
|
||||
func_8002DE04(play, &this->actor, this->actor.child);
|
||||
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_HOOKSHOT_ATTACHED)) {
|
||||
Actor_SwapHookshotAttachment(play, &this->actor, this->actor.child);
|
||||
}
|
||||
|
||||
this->coreActive = true;
|
||||
|
@ -668,15 +668,14 @@ void EnFd_Update(Actor* thisx, PlayState* play) {
|
|||
EnFd_SpawnDot(this, play);
|
||||
}
|
||||
|
||||
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_13)) {
|
||||
// has been hookshoted
|
||||
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_HOOKSHOT_ATTACHED)) {
|
||||
if (EnFd_SpawnCore(this, play)) {
|
||||
this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
|
||||
this->invincibilityTimer = 30;
|
||||
Actor_PlaySfx(&this->actor, NA_SE_EN_FLAME_DAMAGE);
|
||||
Enemy_StartFinishingBlow(play, &this->actor);
|
||||
} else {
|
||||
this->actor.flags &= ~ACTOR_FLAG_13;
|
||||
this->actor.flags &= ~ACTOR_FLAG_HOOKSHOT_ATTACHED;
|
||||
}
|
||||
} else if (this->actionFunc != EnFd_WaitForCore) {
|
||||
EnFd_ColliderCheck(this, play);
|
||||
|
|
|
@ -361,8 +361,7 @@ void EnFw_Update(Actor* thisx, PlayState* play) {
|
|||
EnFw* this = (EnFw*)thisx;
|
||||
|
||||
SkelAnime_Update(&this->skelAnime);
|
||||
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_13)) {
|
||||
// not attached to hookshot.
|
||||
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_HOOKSHOT_ATTACHED)) {
|
||||
Actor_MoveXZGravity(&this->actor);
|
||||
Actor_UpdateBgCheckInfo(play, &this->actor, 10.0f, 20.0f, 0.0f, UPDBGCHECKINFO_FLAG_0 | UPDBGCHECKINFO_FLAG_2);
|
||||
this->actionFunc(this, play);
|
||||
|
|
|
@ -80,7 +80,7 @@ s32 func_80AFB748(EnSi* this, PlayState* play) {
|
|||
void func_80AFB768(EnSi* this, PlayState* play) {
|
||||
Player* player = GET_PLAYER(play);
|
||||
|
||||
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_13)) {
|
||||
if (CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_HOOKSHOT_ATTACHED)) {
|
||||
this->actionFunc = func_80AFB89C;
|
||||
} else {
|
||||
Math_SmoothStepToF(&this->actor.scale.x, 0.25f, 0.4f, 1.0f, 0.0f);
|
||||
|
@ -113,7 +113,7 @@ void func_80AFB89C(EnSi* this, PlayState* play) {
|
|||
Actor_SetScale(&this->actor, this->actor.scale.x);
|
||||
this->actor.shape.rot.y += 0x400;
|
||||
|
||||
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_13)) {
|
||||
if (!CHECK_FLAG_ALL(this->actor.flags, ACTOR_FLAG_HOOKSHOT_ATTACHED)) {
|
||||
Item_Give(play, ITEM_SKULL_TOKEN);
|
||||
player->actor.freezeTimer = 10;
|
||||
Message_StartTextbox(play, 0xB4, NULL);
|
||||
|
|
Loading…
Reference in a new issue