From 6a7d503c77b3e80f9ab6cbf594cc98630d2bad81 Mon Sep 17 00:00:00 2001 From: Ryan Conrad Date: Tue, 12 Apr 2022 23:51:31 -0500 Subject: [PATCH] Add audio cues to assist with ranged aiming --- soh/include/z64collision_check.h | 3 +- soh/src/code/z_collision_check.c | 36 ++-- soh/src/code/z_player_lib.c | 193 ++++++++++++++++++ .../actors/ovl_player_actor/z_player.c | 8 + 4 files changed, 222 insertions(+), 18 deletions(-) diff --git a/soh/include/z64collision_check.h b/soh/include/z64collision_check.h index 4dad0acc7..426b05f05 100644 --- a/soh/include/z64collision_check.h +++ b/soh/include/z64collision_check.h @@ -269,7 +269,8 @@ typedef enum { /* 4 */ ELEMTYPE_UNK4, /* 5 */ ELEMTYPE_UNK5, /* 6 */ ELEMTYPE_UNK6, - /* 7 */ ELEMTYPE_UNK7 + /* 7 */ ELEMTYPE_UNK7, + /* 8 */ ELEMTYPE_SENSING } ElementType; #define AT_NONE 0 // No flags set. Cannot have AT collisions when set as AT diff --git a/soh/src/code/z_collision_check.c b/soh/src/code/z_collision_check.c index 3170eb87a..5c8f4e17a 100644 --- a/soh/src/code/z_collision_check.c +++ b/soh/src/code/z_collision_check.c @@ -1702,23 +1702,25 @@ s32 CollisionCheck_SetATvsAC(GlobalContext* globalCtx, Collider* at, ColliderInf at->actor->colChkInfo.atHitEffect = acInfo->bumper.effect; } } - ac->acFlags |= AC_HIT; - ac->ac = at->actor; - acInfo->acHit = at; - acInfo->acHitInfo = atInfo; - acInfo->bumperFlags |= BUMP_HIT; - if (ac->actor != NULL) { - ac->actor->colChkInfo.acHitEffect = atInfo->toucher.effect; - } - acInfo->bumper.hitPos.x = hitPos->x; - acInfo->bumper.hitPos.y = hitPos->y; - acInfo->bumper.hitPos.z = hitPos->z; - if (!(atInfo->toucherFlags & TOUCH_AT_HITMARK) && ac->colType != COLTYPE_METAL && ac->colType != COLTYPE_WOOD && - ac->colType != COLTYPE_HARD) { - acInfo->bumperFlags |= BUMP_DRAW_HITMARK; - } else { - CollisionCheck_HitEffects(globalCtx, at, atInfo, ac, acInfo, hitPos); - atInfo->toucherFlags |= TOUCH_DREW_HITMARK; + if (atInfo->elemType != ELEMTYPE_SENSING) { + ac->acFlags |= AC_HIT; + ac->ac = at->actor; + acInfo->acHit = at; + acInfo->acHitInfo = atInfo; + acInfo->bumperFlags |= BUMP_HIT; + if (ac->actor != NULL) { + ac->actor->colChkInfo.acHitEffect = atInfo->toucher.effect; + } + acInfo->bumper.hitPos.x = hitPos->x; + acInfo->bumper.hitPos.y = hitPos->y; + acInfo->bumper.hitPos.z = hitPos->z; + if (!(atInfo->toucherFlags & TOUCH_AT_HITMARK) && ac->colType != COLTYPE_METAL && ac->colType != COLTYPE_WOOD && + ac->colType != COLTYPE_HARD) { + acInfo->bumperFlags |= BUMP_DRAW_HITMARK; + } else { + CollisionCheck_HitEffects(globalCtx, at, atInfo, ac, acInfo, hitPos); + atInfo->toucherFlags |= TOUCH_DREW_HITMARK; + } } return 1; } diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index e15cc81eb..1b6413408 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -1260,6 +1260,193 @@ Vec3f D_801261E0[] = { { 200.0f, 200.0f, 0.0f }, }; + +#define AIMCUE_COLLIDER_COUNT 5 +static ColliderQuad sAimCueCollider[AIMCUE_COLLIDER_COUNT]; +static s32 sAimSurfaceHookshotable; +static s32 sAimLastHookshotableState; + +static ColliderQuadInit sSensingColliderInit = { + { + COLTYPE_NONE, + AT_ON | AT_TYPE_PLAYER, + AC_NONE, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_2 | OC2_TYPE_1, + COLSHAPE_QUAD, + }, + { + ELEMTYPE_SENSING, + { 0xFFFFFFFF, 0x00, 0x00 }, + { 0xFFFFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_NEAREST | TOUCH_SFX_NONE, + BUMP_NONE, + OCELEM_NONE, + }, + { { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } } }, +}; + +void Player_InitAimCueCollision(Player* this, GlobalContext* globalCtx) { + for (int i = 0; i < AIMCUE_COLLIDER_COUNT; i++) { + Collider_InitQuad(globalCtx, &sAimCueCollider[i]); + Collider_SetQuad(globalCtx, &sAimCueCollider[i], NULL, &sSensingColliderInit); + } +} + +void Player_UpdateAimCue(Player* this, GlobalContext* globalCtx) { + Actor* hitActor = NULL; + + for (int i = 0; i < AIMCUE_COLLIDER_COUNT; i++) { + if (sAimCueCollider[i].base.atFlags & AT_HIT) { + sAimCueCollider[i].base.atFlags &= ~AC_HIT; + + if (hitActor == NULL && sAimCueCollider[i].base.at != NULL) { + hitActor = sAimCueCollider[i].base.at; + } else { + continue; + } + + if (i != 0 && (globalCtx->gameplayFrames % 1) != 0) { + continue; + } + + u16 soundEffect = (i == 0) ? NA_SE_SY_HITPOINT_ALARM : NA_SE_SY_FSEL_CURSOR; + + if (hitActor->category == ACTORCAT_ENEMY || hitActor->category == ACTORCAT_BOSS) { + Audio_PlaySoundGeneral(soundEffect, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + } else if (hitActor->category == ACTORCAT_SWITCH) { + Audio_PlaySoundGeneral(soundEffect, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + } else if (hitActor->category == ACTORCAT_NPC) { + Audio_PlaySoundGeneral(soundEffect, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + } else if (hitActor->category == ACTORCAT_PROP && + (hitActor->id == ACTOR_EN_DNT_NOMAL && hitActor->params == 0) || + hitActor->id == ACTOR_EN_G_SWITCH) { + // lost woods slingshot target, shooting gallery rupees + Audio_PlaySoundGeneral(soundEffect, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + } + } + } + + if (sAimSurfaceHookshotable != sAimLastHookshotableState) { + if (sAimSurfaceHookshotable) { + Audio_PlaySoundGeneral(NA_SE_SY_LOCK_ON_HUMAN, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + } else { + Audio_PlaySoundGeneral(NA_SE_SY_LOCK_OFF, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); + } + sAimLastHookshotableState = sAimSurfaceHookshotable; + } +} + +void Player_ComputeAimCue(Player* this, GlobalContext* globalCtx, s32 limbIndex) { + if (this->heldItemId == 0) { + return; + } + + bool isHoldingHookshotType = Player_HoldsHookshot(this); + + if (!isHoldingHookshotType && limbIndex != PLAYER_LIMB_L_HAND || + isHoldingHookshotType && limbIndex != PLAYER_LIMB_R_HAND) { + return; + } + + sAimSurfaceHookshotable = 0; + + bool isCharged = (this->stateFlags1 & 0x200) && (this->unk_834 <= 10) && (this->unk_860 >= 0); + bool isAiming = !!func_8002DD78(this); + if (!isAiming || !(isCharged || isHoldingHookshotType)) { + return; + } + + CollisionPoly* polyResult; + s32 bgId; + + Matrix_Push(); + + f32 distance; + Vec3f vecCenter; + Vec3f vecCenterFar; + Vec3f vecA; + Vec3f vecB; + Vec3f vecC; + Vec3f vecD; + Vec3f vecResult; + Vec3f vecZero = { 0.0f, 0.0f, 0.0f }; + Vec3f vecLeft = { 0.0f, 50.0f, 0.0f }; + Vec3f vecRight = { 0.0f, -50.0f, 0.0f }; + + if (isHoldingHookshotType) { + if (this->heldItemActionParam == PLAYER_AP_HOOKSHOT) { + distance = 38600.0f; + } else { + distance = 77600.0f; + } + Matrix_Translate(0.0f, 150.0f, -100.0f, MTXMODE_APPLY); + } else { + distance = 200000.0f; + Matrix_Translate(-550.0f, -50.0f, -100.0f, MTXMODE_APPLY); + } + + Matrix_MultVec3f(&vecZero, &vecCenter); + vecZero.z = distance; + Matrix_MultVec3f(&vecZero, &vecCenterFar); + + if (BgCheck_AnyLineTest3(&globalCtx->colCtx, &vecCenter, &vecCenterFar, &vecResult, &polyResult, 1, 1, 1, 1, + &bgId)) { + sAimSurfaceHookshotable = + isHoldingHookshotType && SurfaceType_IsHookshotSurface(&globalCtx->colCtx, polyResult, bgId); + distance *= Math_Vec3f_DistXYZ(&vecCenter, &vecResult) / Math_Vec3f_DistXYZ(&vecCenter, &vecCenterFar); + } + + if (!isCharged) { + Matrix_Pop(); + return; + } + + Matrix_MultVec3f(&vecLeft, &vecA); + Matrix_MultVec3f(&vecRight, &vecB); + + vecLeft.z = distance; + vecRight.z = distance; + + Matrix_MultVec3f(&vecLeft, &vecC); + Matrix_MultVec3f(&vecRight, &vecD); + + Collider_SetQuadVertices(&sAimCueCollider[0], &vecA, &vecB, &vecC, &vecD); + CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &sAimCueCollider[0].base); + + Matrix_Scale(500.0f, 500.0f, 1.0f, MTXMODE_APPLY); + + f32 rotateOffset = (globalCtx->gameplayFrames % 4) * M_PI / 16; + Matrix_RotateZ(rotateOffset, MTXMODE_APPLY); + + for (int i = 1; i < AIMCUE_COLLIDER_COUNT; i++) { + if (i > 1) { + Matrix_RotateZ(M_PI / 4, MTXMODE_APPLY); + } + + vecLeft.z = 0; + vecLeft.y = 0.5; + vecRight.z = 0; + vecRight.y = -0.5; + + Matrix_MultVec3f(&vecLeft, &vecA); + Matrix_MultVec3f(&vecRight, &vecB); + + vecLeft.z = distance * 1.2; + vecLeft.y = sqrtf(distance) * 0.2f; + vecRight.z = distance * 1.2; + vecRight.y = sqrtf(distance) * -0.2f; + + Matrix_MultVec3f(&vecLeft, &vecC); + Matrix_MultVec3f(&vecRight, &vecD); + + Collider_SetQuadVertices(&sAimCueCollider[i], &vecA, &vecB, &vecC, &vecD); + CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &sAimCueCollider[i].base); + } + + Matrix_Pop(); +} + void func_80090D20(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) { Player* this = (Player*)thisx; @@ -1413,9 +1600,11 @@ void func_80090D20(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* heldActor->shape.rot = heldActor->world.rot; if (func_8002DD78(this) != 0) { + Matrix_Push(); Matrix_Translate(500.0f, 300.0f, 0.0f, MTXMODE_APPLY); Player_DrawHookshotReticle( globalCtx, this, (this->heldItemActionParam == PLAYER_AP_HOOKSHOT) ? 38600.0f : 77600.0f); + Matrix_Pop(); } } } @@ -1452,6 +1641,10 @@ void func_80090D20(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* Actor_SetFeetPos(&this->actor, limbIndex, PLAYER_LIMB_L_FOOT, vec, PLAYER_LIMB_R_FOOT, vec); } } + + if (CVar_GetS32("gAimAudioCues", 0)) { + Player_ComputeAimCue(this, globalCtx, limbIndex); + } } u32 func_80091738(GlobalContext* globalCtx, u8* segment, SkelAnime* skelAnime) { diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 094fcdd2d..ebdc7e91c 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -9363,6 +9363,10 @@ void Player_InitCommon(Player* this, GlobalContext* globalCtx, FlexSkeletonHeade Collider_SetQuad(globalCtx, &this->swordQuads[1], &this->actor, &D_80854650); Collider_InitQuad(globalCtx, &this->shieldQuad); Collider_SetQuad(globalCtx, &this->shieldQuad, &this->actor, &D_808546A0); + + if (CVar_GetS32("gAimAudioCues", 0)) { + Player_InitAimCueCollision(this, globalCtx); + } } static void (*D_80854738[])(GlobalContext* globalCtx, Player* this) = { @@ -10723,6 +10727,10 @@ void Player_UpdateCommon(Player* this, GlobalContext* globalCtx, Input* input) { Collider_ResetQuadAC(globalCtx, &this->shieldQuad.base); Collider_ResetQuadAT(globalCtx, &this->shieldQuad.base); + + if (CVar_GetS32("gAimAudioCues", 0)) { + Player_UpdateAimCue(this, globalCtx); + } } static Vec3f D_80854838 = { 0.0f, 0.0f, -30.0f };