mirror of https://github.com/zeldaret/mm.git
330 lines
12 KiB
C
330 lines
12 KiB
C
/*
|
|
* File: z_en_hy.c
|
|
* Description: Unused System for NPCs (includes animation, door interaction, blinking, pathing, and collider helpers)
|
|
*/
|
|
|
|
#include "z_en_hy_code.h"
|
|
#include "overlays/actors/ovl_En_Door/z_en_door.h"
|
|
#include "objects/object_aob/object_aob.h"
|
|
#include "objects/object_bba/object_bba.h"
|
|
#include "objects/object_bji/object_bji.h"
|
|
#include "objects/object_boj/object_boj.h"
|
|
#include "objects/object_os_anime/object_os_anime.h"
|
|
|
|
static AnimationInfoS sAnimationInfo[ENHY_ANIM_MAX] = {
|
|
{ &gMamamuYanUnusedIdleAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_AOB_0
|
|
{ &object_boj_Anim_001494, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_BOJ_1
|
|
{ &object_boj_Anim_001494, 1.0f, 0, -1, ANIMMODE_LOOP, -8 }, // ENHY_ANIM_BOJ_2
|
|
{ &object_boj_Anim_001908, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_BOJ_3
|
|
{ &object_boj_Anim_001908, 1.0f, 0, -1, ANIMMODE_LOOP, -8 }, // ENHY_ANIM_BOJ_4
|
|
{ &object_boj_Anim_0008C0, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_BOJ_5
|
|
{ &gBbaIdleHoldingBagAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_BBA_6
|
|
{ &object_bji_Anim_000FDC, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_BJI_7
|
|
{ &object_bji_Anim_000AB0, 1.0f, 0, -1, ANIMMODE_LOOP, -8 }, // ENHY_ANIM_BJI_8
|
|
{ &object_bji_Anim_00066C, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_BJI_9
|
|
{ &object_boj_Anim_00071C, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_BOJ_10
|
|
{ &object_os_anime_Anim_001EE0, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_OS_ANIME_11
|
|
{ &object_boj_Anim_00DED8, 1.5f, 0, -1, ANIMMODE_ONCE, 0 }, // ENHY_ANIM_BOJ_12
|
|
{ &object_boj_Anim_00F920, 1.5f, 0, -1, ANIMMODE_ONCE, 0 }, // ENHY_ANIM_BOJ_13
|
|
{ &object_boj_Anim_00FC1C, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_BOJ_14
|
|
{ &object_boj_Anim_00FEE4, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_BOJ_15
|
|
{ &object_boj_Anim_010330, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, // ENHY_ANIM_BOJ_16
|
|
{ &object_boj_Anim_00FC1C, 1.0f, 0, -1, ANIMMODE_LOOP, -8 }, // ENHY_ANIM_BOJ_17
|
|
{ &object_boj_Anim_00FEE4, 1.0f, 0, -1, ANIMMODE_LOOP, -8 }, // ENHY_ANIM_BOJ_18
|
|
{ &object_boj_Anim_010330, 1.0f, 0, -1, ANIMMODE_LOOP, -8 }, // ENHY_ANIM_BOJ_19
|
|
{ &object_boj_Anim_005D9C, 1.0f, 0, -1, ANIMMODE_LOOP, -8 }, // ENHY_ANIM_BOJ_20
|
|
};
|
|
|
|
s8 gEnHyLimbToBodyParts[ENHY_LIMB_MAX] = {
|
|
BODYPART_NONE, // ENHY_LIMB_NONE
|
|
ENHY_BODYPART_1, // ENHY_LIMB_PELVIS
|
|
ENHY_BODYPART_12, // ENHY_LIMB_LEFT_THIGH
|
|
ENHY_BODYPART_13, // ENHY_LIMB_LEFT_SHIN
|
|
ENHY_BODYPART_14, // ENHY_LIMB_LEFT_FOOT
|
|
ENHY_BODYPART_9, // ENHY_LIMB_RIGHT_THIGH
|
|
ENHY_BODYPART_10, // ENHY_LIMB_RIGHT_SHIN
|
|
ENHY_BODYPART_11, // ENHY_LIMB_RIGHT_FOOT
|
|
ENHY_BODYPART_0, // ENHY_LIMB_TORSO
|
|
ENHY_BODYPART_6, // ENHY_LIMB_LEFT_UPPER_ARM
|
|
ENHY_BODYPART_7, // ENHY_LIMB_LEFT_FOREARM
|
|
ENHY_BODYPART_8, // ENHY_LIMB_LEFT_HAND
|
|
ENHY_BODYPART_3, // ENHY_LIMB_RIGHT_UPPER_ARM
|
|
ENHY_BODYPART_4, // ENHY_LIMB_RIGHT_FOREARM
|
|
ENHY_BODYPART_5, // ENHY_LIMB_RIGHT_HAND
|
|
ENHY_BODYPART_2, // ENHY_LIMB_HEAD
|
|
};
|
|
|
|
s8 gEnHyParentShadowBodyParts[ENHY_BODYPART_MAX] = {
|
|
ENHY_BODYPART_0, // ENHY_BODYPART_0
|
|
ENHY_BODYPART_0, // ENHY_BODYPART_1
|
|
ENHY_BODYPART_0, // ENHY_BODYPART_2
|
|
ENHY_BODYPART_0, // ENHY_BODYPART_3
|
|
ENHY_BODYPART_3, // ENHY_BODYPART_4
|
|
ENHY_BODYPART_4, // ENHY_BODYPART_5
|
|
ENHY_BODYPART_0, // ENHY_BODYPART_6
|
|
ENHY_BODYPART_6, // ENHY_BODYPART_7
|
|
ENHY_BODYPART_7, // ENHY_BODYPART_8
|
|
ENHY_BODYPART_0, // ENHY_BODYPART_9
|
|
ENHY_BODYPART_9, // ENHY_BODYPART_10
|
|
ENHY_BODYPART_10, // ENHY_BODYPART_11
|
|
ENHY_BODYPART_0, // ENHY_BODYPART_12
|
|
ENHY_BODYPART_12, // ENHY_BODYPART_13
|
|
ENHY_BODYPART_13, // ENHY_BODYPART_14
|
|
};
|
|
|
|
u8 gEnHyShadowSizes[ENHY_BODYPART_MAX] = {
|
|
0, // ENHY_BODYPART_0
|
|
0, // ENHY_BODYPART_1
|
|
0, // ENHY_BODYPART_2
|
|
0, // ENHY_BODYPART_3
|
|
0, // ENHY_BODYPART_4
|
|
0, // ENHY_BODYPART_5
|
|
0, // ENHY_BODYPART_6
|
|
0, // ENHY_BODYPART_7
|
|
0, // ENHY_BODYPART_8
|
|
0, // ENHY_BODYPART_9
|
|
0, // ENHY_BODYPART_10
|
|
0, // ENHY_BODYPART_11
|
|
0, // ENHY_BODYPART_12
|
|
0, // ENHY_BODYPART_13
|
|
0, // ENHY_BODYPART_14
|
|
};
|
|
|
|
s32 EnHy_ChangeAnim(SkelAnime* skelAnime, s16 animIndex) {
|
|
s16 endFrame;
|
|
s32 didAnimChange = false;
|
|
|
|
if ((animIndex > ENHY_ANIM_NONE) && (animIndex < ENHY_ANIM_MAX)) {
|
|
didAnimChange = true;
|
|
endFrame = sAnimationInfo[animIndex].frameCount;
|
|
if (endFrame < 0) {
|
|
endFrame = Animation_GetLastFrame(&sAnimationInfo[animIndex].animation->common);
|
|
}
|
|
Animation_Change(skelAnime, sAnimationInfo[animIndex].animation, sAnimationInfo[animIndex].playSpeed,
|
|
sAnimationInfo[animIndex].startFrame, endFrame, sAnimationInfo[animIndex].mode,
|
|
sAnimationInfo[animIndex].morphFrames);
|
|
}
|
|
return didAnimChange;
|
|
}
|
|
|
|
EnDoor* EnHy_FindNearestDoor(Actor* actor, PlayState* play) {
|
|
EnDoor* nearestDoor = NULL;
|
|
Actor* doorIter = NULL;
|
|
f32 dist;
|
|
EnDoor* door;
|
|
s32 isSetup = false;
|
|
f32 minDist = 0.0f;
|
|
|
|
do {
|
|
doorIter = SubS_FindActor(play, doorIter, ACTORCAT_DOOR, ACTOR_EN_DOOR);
|
|
door = (EnDoor*)doorIter;
|
|
dist = Actor_WorldDistXYZToActor(actor, &door->knobDoor.dyna.actor);
|
|
if (!isSetup || (dist < minDist)) {
|
|
nearestDoor = door;
|
|
minDist = dist;
|
|
isSetup = true;
|
|
}
|
|
doorIter = door->knobDoor.dyna.actor.next;
|
|
} while (doorIter != NULL);
|
|
|
|
if (1) {}
|
|
|
|
return nearestDoor;
|
|
}
|
|
|
|
void EnHy_ChangeObjectAndAnim(EnHy* enHy, PlayState* play, s16 animIndex) {
|
|
gSegments[0x06] = OS_K0_TO_PHYSICAL(play->objectCtx.slots[enHy->animObjectSlot].segment);
|
|
EnHy_ChangeAnim(&enHy->skelAnime, animIndex);
|
|
}
|
|
|
|
s32 EnHy_UpdateSkelAnime(EnHy* enHy, PlayState* play) {
|
|
s32 isUpdated = false;
|
|
|
|
if (enHy->actor.draw != NULL) {
|
|
gSegments[0x06] = OS_K0_TO_PHYSICAL(play->objectCtx.slots[enHy->animObjectSlot].segment);
|
|
SkelAnime_Update(&enHy->skelAnime);
|
|
isUpdated = true;
|
|
}
|
|
return isUpdated;
|
|
}
|
|
|
|
void EnHy_Blink(EnHy* enHy, s32 eyeTexMaxIndex) {
|
|
if (DECR(enHy->blinkTimer) == 0) {
|
|
enHy->eyeTexIndex++;
|
|
if (enHy->eyeTexIndex >= eyeTexMaxIndex) {
|
|
enHy->eyeTexIndex = 0;
|
|
enHy->blinkTimer = Rand_S16Offset(30, 30);
|
|
}
|
|
}
|
|
}
|
|
|
|
s32 EnHy_Init(EnHy* enHy, PlayState* play, FlexSkeletonHeader* skeletonHeaderSeg, s16 animIndex) {
|
|
s32 isInitialized = false;
|
|
|
|
if ((SubS_IsObjectLoaded(enHy->animObjectSlot, play) == true) &&
|
|
(SubS_IsObjectLoaded(enHy->headObjectSlot, play) == true) &&
|
|
(SubS_IsObjectLoaded(enHy->skelUpperObjectSlot, play) == true) &&
|
|
(SubS_IsObjectLoaded(enHy->skelLowerObjectSlot, play) == true)) {
|
|
enHy->actor.objectSlot = enHy->skelLowerObjectSlot;
|
|
isInitialized = true;
|
|
ActorShape_Init(&enHy->actor.shape, 0.0f, NULL, 0.0f);
|
|
gSegments[0x06] = OS_K0_TO_PHYSICAL(play->objectCtx.slots[enHy->actor.objectSlot].segment);
|
|
SkelAnime_InitFlex(play, &enHy->skelAnime, skeletonHeaderSeg, NULL, enHy->jointTable, enHy->morphTable,
|
|
ENHY_LIMB_MAX);
|
|
EnHy_ChangeObjectAndAnim(enHy, play, animIndex);
|
|
}
|
|
|
|
return isInitialized;
|
|
}
|
|
|
|
void func_800F0BB4(EnHy* enHy, PlayState* play, EnDoor* door, s16 arg3, s16 arg4) {
|
|
s32 pad;
|
|
s8 animIndex;
|
|
Vec3f offset;
|
|
f32 phi_f0;
|
|
|
|
Actor_OffsetOfPointInActorCoords(&door->knobDoor.dyna.actor, &offset, &enHy->actor.world.pos);
|
|
phi_f0 = (offset.z >= 0.0f) ? 1.0f : -1.0f;
|
|
animIndex = ((s8)phi_f0 < 0) ? 0 : 2;
|
|
EnHy_ChangeObjectAndAnim(enHy, play, (animIndex == 0) ? arg3 : arg4);
|
|
enHy->skelAnime.baseTransl = enHy->skelAnime.jointTable[LIMB_ROOT_POS];
|
|
enHy->skelAnime.prevTransl = enHy->skelAnime.jointTable[LIMB_ROOT_POS];
|
|
enHy->skelAnime.moveFlags |= (ANIM_FLAG_UPDATE_Y | ANIM_FLAG_1);
|
|
AnimationContext_SetMoveActor(play, &enHy->actor, &enHy->skelAnime, 1.0f);
|
|
door->knobDoor.playOpenAnim = true;
|
|
door->knobDoor.animIndex = animIndex;
|
|
}
|
|
|
|
s32 func_800F0CE4(EnHy* enHy, PlayState* play, ActorFunc draw, s16 arg3, s16 arg4, f32 arg5) {
|
|
s32 ret = false;
|
|
s16 yaw;
|
|
EnDoor* door;
|
|
s32 pad;
|
|
|
|
if (SubS_CopyPointFromPath(enHy->path, enHy->curPoint, &enHy->actor.world.pos)) {
|
|
door = EnHy_FindNearestDoor(&enHy->actor, play);
|
|
if (door != NULL) {
|
|
ret = true;
|
|
func_800F0BB4(enHy, play, door, arg3, arg4);
|
|
yaw = Math_Vec3f_Yaw(&enHy->actor.world.pos, &door->knobDoor.dyna.actor.world.pos);
|
|
enHy->actor.world.pos.x += arg5 * Math_SinS(yaw);
|
|
enHy->actor.world.pos.z += arg5 * Math_CosS(yaw);
|
|
enHy->actor.world.rot.y = -yaw;
|
|
enHy->actor.shape.rot.y = -yaw;
|
|
enHy->actor.draw = draw;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
s32 func_800F0DD4(EnHy* enHy, PlayState* play, s16 arg2, s16 arg3) {
|
|
s32 ret = false;
|
|
s32 pad;
|
|
EnDoor* door;
|
|
|
|
enHy->curPoint = 0;
|
|
if (SubS_CopyPointFromPath(enHy->path, enHy->curPoint, &enHy->actor.world.pos)) {
|
|
door = EnHy_FindNearestDoor(&enHy->actor, play);
|
|
if (door != NULL) {
|
|
ret = true;
|
|
func_800F0BB4(enHy, play, door, arg2, arg3);
|
|
enHy->actor.shape.rot.y = Math_Vec3f_Yaw(&enHy->actor.world.pos, &door->knobDoor.dyna.actor.world.pos);
|
|
enHy->actor.world.rot.y = enHy->actor.shape.rot.y;
|
|
enHy->actor.gravity = 0.0f;
|
|
enHy->actor.flags &= ~ACTOR_FLAG_TARGETABLE;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
s32 EnHy_SetPointFowards(EnHy* enHy, PlayState* play, f32 gravity, s16 animIndex) {
|
|
enHy->actor.gravity = gravity;
|
|
enHy->actor.flags |= ACTOR_FLAG_TARGETABLE;
|
|
EnHy_ChangeObjectAndAnim(enHy, play, animIndex);
|
|
enHy->curPoint++;
|
|
return false;
|
|
}
|
|
|
|
s32 EnHy_SetPointBackwards(EnHy* enHy, PlayState* play, s16 animIndex) {
|
|
EnHy_ChangeObjectAndAnim(enHy, play, animIndex);
|
|
enHy->curPoint--;
|
|
return false;
|
|
}
|
|
|
|
s32 EnHy_MoveForwards(EnHy* enHy, f32 speedTarget) {
|
|
s16 rotStep;
|
|
s32 reachedEnd = false;
|
|
Vec3f curPointPos;
|
|
|
|
Math_SmoothStepToF(&enHy->actor.speed, speedTarget, 0.4f, 1000.0f, 0.0f);
|
|
rotStep = enHy->actor.speed * 400.0f;
|
|
if (SubS_CopyPointFromPath(enHy->path, enHy->curPoint, &curPointPos) &&
|
|
SubS_MoveActorToPoint(&enHy->actor, &curPointPos, rotStep)) {
|
|
enHy->curPoint++;
|
|
if (enHy->curPoint >= enHy->path->count) {
|
|
reachedEnd = true;
|
|
}
|
|
}
|
|
|
|
return reachedEnd;
|
|
}
|
|
|
|
s32 EnHy_MoveBackwards(EnHy* enHy, f32 speedTarget) {
|
|
s16 rotStep;
|
|
s32 reachedEnd = false;
|
|
Vec3f curPointPos;
|
|
|
|
Math_SmoothStepToF(&enHy->actor.speed, speedTarget, 0.4f, 1000.0f, 0.0f);
|
|
rotStep = enHy->actor.speed * 400.0f;
|
|
if (SubS_CopyPointFromPath(enHy->path, enHy->curPoint, &curPointPos) &&
|
|
SubS_MoveActorToPoint(&enHy->actor, &curPointPos, rotStep)) {
|
|
enHy->curPoint--;
|
|
if (enHy->curPoint < 0) {
|
|
reachedEnd = true;
|
|
}
|
|
}
|
|
|
|
return reachedEnd;
|
|
}
|
|
|
|
void EnHy_UpdateCollider(EnHy* enHy, PlayState* play) {
|
|
enHy->collider.dim.pos.x = enHy->actor.world.pos.x;
|
|
enHy->collider.dim.pos.y = enHy->actor.world.pos.y;
|
|
enHy->collider.dim.pos.z = enHy->actor.world.pos.z;
|
|
|
|
CollisionCheck_SetAC(play, &play->colChkCtx, &enHy->collider.base);
|
|
CollisionCheck_SetOC(play, &play->colChkCtx, &enHy->collider.base);
|
|
}
|
|
|
|
s32 EnHy_PlayWalkingSound(EnHy* enHy, PlayState* play, f32 distAboveThreshold) {
|
|
u8 wasLeftFootOnGround = enHy->isLeftFootOnGround;
|
|
u8 wasRightFootOnGround = enHy->isRightFootOnGround;
|
|
SurfaceSfxOffset surfaceSfxOffset;
|
|
u16 sfxId;
|
|
u8 isFootOnGround;
|
|
|
|
if (enHy->actor.bgCheckFlags & BGCHECKFLAG_WATER) {
|
|
if (enHy->actor.depthInWater < 20.0f) {
|
|
surfaceSfxOffset = SURFACE_SFX_OFFSET_WATER_SHALLOW;
|
|
} else {
|
|
surfaceSfxOffset = SURFACE_SFX_OFFSET_WATER_DEEP;
|
|
}
|
|
sfxId = NA_SE_PL_WALK_GROUND + surfaceSfxOffset;
|
|
} else {
|
|
sfxId = NA_SE_PL_WALK_GROUND +
|
|
SurfaceType_GetSfxOffset(&play->colCtx, enHy->actor.floorPoly, enHy->actor.floorBgId);
|
|
}
|
|
|
|
enHy->isLeftFootOnGround = isFootOnGround = SubS_IsFloorAbove(play, &enHy->leftFootPos, distAboveThreshold);
|
|
if (enHy->isLeftFootOnGround && !wasLeftFootOnGround && isFootOnGround) {
|
|
Actor_PlaySfx(&enHy->actor, sfxId);
|
|
}
|
|
|
|
enHy->isRightFootOnGround = isFootOnGround = SubS_IsFloorAbove(play, &enHy->rightFootPos, distAboveThreshold);
|
|
if (enHy->isRightFootOnGround && !wasRightFootOnGround && isFootOnGround) {
|
|
Actor_PlaySfx(&enHy->actor, sfxId);
|
|
}
|
|
|
|
return false;
|
|
}
|