diff --git a/assets/xml/objects/object_ru2.xml b/assets/xml/objects/object_ru2.xml index 08f182bb9e..72510149c0 100644 --- a/assets/xml/objects/object_ru2.xml +++ b/assets/xml/objects/object_ru2.xml @@ -1,78 +1,98 @@  + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spec b/spec index c894dabefc..48b1695ac5 100644 --- a/spec +++ b/spec @@ -2638,8 +2638,7 @@ beginseg name "ovl_En_Ru" compress include "build/src/overlays/actors/ovl_En_Ru/z_en_ru.o" - include "build/data/ovl_En_Ru/ovl_En_Ru.data.o" - include "build/data/ovl_En_Ru/ovl_En_Ru.reloc.o" + include "build/src/overlays/actors/ovl_En_Ru/ovl_En_Ru_reloc.o" endseg beginseg diff --git a/src/overlays/actors/ovl_En_Ru/z_en_ru.c b/src/overlays/actors/ovl_En_Ru/z_en_ru.c index 0333cb011c..1a57cba7bc 100644 --- a/src/overlays/actors/ovl_En_Ru/z_en_ru.c +++ b/src/overlays/actors/ovl_En_Ru/z_en_ru.c @@ -15,9 +15,8 @@ void EnRu_Destroy(Actor* thisx, PlayState* play); void EnRu_Update(Actor* thisx, PlayState* play); void EnRu_Draw(Actor* thisx, PlayState* play); -void func_80A38DF4(EnRu* this, PlayState* play); +void EnRu_DoNothing(EnRu* this, PlayState* play); -#if 0 const ActorInit En_Ru_InitVars = { ACTOR_EN_RU, ACTORCAT_NPC, @@ -30,18 +29,29 @@ const ActorInit En_Ru_InitVars = { (ActorFunc)EnRu_Draw, }; -// static ColliderCylinderInit sCylinderInit = { -static ColliderCylinderInit D_80A39450 = { - { COLTYPE_HIT0, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, }, - { ELEMTYPE_UNK1, { 0x00000000, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, +static ColliderCylinderInit sCylinderInit = { + { + COLTYPE_HIT0, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK1, + { 0x00000000, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, { 18, 64, 0, { 0, 0, 0 } }, }; -// sColChkInfoInit -static CollisionCheckInfoInit2 D_80A3947C = { 0, 0, 0, 0, MASS_IMMOVABLE }; +static CollisionCheckInfoInit2 sColChkInfoInit = { 0, 0, 0, 0, MASS_IMMOVABLE }; -// static DamageTable sDamageTable = { -static DamageTable D_80A39488 = { +static DamageTable sDamageTable = { /* Deku Nut */ DMG_ENTRY(0, 0x0), /* Deku Stick */ DMG_ENTRY(0, 0x0), /* Horse trample */ DMG_ENTRY(0, 0x0), @@ -76,34 +86,268 @@ static DamageTable D_80A39488 = { /* Powder Keg */ DMG_ENTRY(0, 0x0), }; -#endif +static AnimationInfoS sAnimationInfo[] = { + { &gAdultRutoIdleAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, + { &gAdultRutoIdleAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &gAdultRutoRaisingArmsUpAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &gAdultRutoCrossingArmsAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &gAdultRutoLookingDownLeftAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &gAdultRutoIdleHandsOnHipsAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &gAdultRutoHeadTurnDownLeftAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, + { &gAdultRutoSwimmingUpAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -4 }, +}; -extern ColliderCylinderInit D_80A39450; -extern CollisionCheckInfoInit2 D_80A3947C; -extern DamageTable D_80A39488; +// in PostLimbdraw, converts limbIndex to bodyPartsPos index +static s8 sBodyPartPosIndices[] = { + -1, -1, 12, 13, 14, -1, 9, 10, 11, -1, 0, 6, -1, -1, 7, 8, 2, -1, -1, 3, 4, 2, 1, +}; -extern UNK_TYPE D_0600C700; +static s8 sRuBodyParts[RU_BODYPARTSPOS_COUNT] = { + 0, 0, 0, 0, 3, 4, 0, 6, 7, 0, 9, 10, 0, 12, 13, +}; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/func_80A389A0.s") +static u8 sRuShadowSizes[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/func_80A38A68.s") +static TrackOptionsSet sTrackOptions = { + { 0xFA0, 4, 1, 3 }, { 0x1770, 4, 1, 6 }, { 0xFA0, 4, 1, 3 }, { 0x1770, 4, 1, 6 } +}; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/func_80A38B7C.s") +s32 EnRu_ChangeAnim(SkelAnime* skelAnime, s16 animIndex) { + s16 lastFrame; + s32 ret = false; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/func_80A38BF0.s") + if ((animIndex >= 0) && (animIndex < ARRAY_COUNT(sAnimationInfo))) { + lastFrame = sAnimationInfo[animIndex].frameCount; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/func_80A38C70.s") + ret = true; + if (lastFrame < 0) { + lastFrame = Animation_GetLastFrame(sAnimationInfo[animIndex].animation); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/func_80A38DF4.s") + Animation_Change(skelAnime, sAnimationInfo[animIndex].animation, sAnimationInfo[animIndex].playSpeed, + sAnimationInfo[animIndex].startFrame, lastFrame, sAnimationInfo[animIndex].mode, + sAnimationInfo[animIndex].morphFrames); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/EnRu_Init.s") + return ret; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/EnRu_Destroy.s") +// En_Zo has a copy of this function +s32 EnRu_PlayWalkingSound(EnRu* this, PlayState* play) { + u8 leftWasGrounded; + u8 rightWasGrounded; + s32 waterSfxId; + s16 sfxId; + u8 isFootGrounded; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/EnRu_Update.s") + leftWasGrounded = this->isLeftFootGrounded; + rightWasGrounded = this->isRightFootGrounded; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/func_80A38FB4.s") + if (this->actor.bgCheckFlags & 0x20) { + if (this->actor.depthInWater < 20.0f) { + waterSfxId = NA_SE_PL_WALK_WATER0 - SFX_FLAG; + } else { + waterSfxId = NA_SE_PL_WALK_WATER1 - SFX_FLAG; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/func_80A390F8.s") + sfxId = waterSfxId + SFX_FLAG; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ru/EnRu_Draw.s") + } else { + sfxId = SurfaceType_GetSfx(&play->colCtx, this->actor.floorPoly, this->actor.floorBgId) + SFX_FLAG; + } + + this->isLeftFootGrounded = isFootGrounded = SubS_IsFloorAbove(play, &this->leftFootPos, -6.0f); + + if (this->isLeftFootGrounded && !leftWasGrounded && isFootGrounded) { + Actor_PlaySfxAtPos(&this->actor, sfxId); + } + + this->isRightFootGrounded = isFootGrounded = SubS_IsFloorAbove(play, &this->rightFootPos, -6.0f); + if (this->isRightFootGrounded && !rightWasGrounded && isFootGrounded) { + Actor_PlaySfxAtPos(&this->actor, sfxId); + } + + return false; +} + +// This function is only ever called with eyeStateMax == 3 +void EnRu_UpdateEyes(EnRu* this, s32 eyeStateMax) { + if (DECR(this->blinkTimer) == 0) { + this->eyeState++; + if (this->eyeState >= eyeStateMax) { + this->eyeState = 0; + this->blinkTimer = Rand_S16Offset(30, 30); + } + } +} + +void EnRu_UpdateCollider(EnRu* this, PlayState* play) { + this->collider.dim.pos.x = this->actor.world.pos.x; + this->collider.dim.pos.y = this->actor.world.pos.y; + this->collider.dim.pos.z = this->actor.world.pos.z; + CollisionCheck_SetAC(play, &play->colChkCtx, &this->collider.base); + CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base); +} + +void EnRu_UpdateModel(EnRu* this, PlayState* play) { + Player* player = GET_PLAYER(play); + + SkelAnime_Update(&this->skelAnime); + + // Head and Torso tracking to Player if in front of Ru. + if (SubS_AngleDiffLessEqual(this->actor.shape.rot.y, 0x2710, this->actor.yawTowardsPlayer)) { + Vec3f playerPos; + + playerPos.x = player->actor.world.pos.x; + playerPos.y = player->bodyPartsPos[7].y + 3.0f; + playerPos.z = player->actor.world.pos.z; + SubS_TrackPoint(&playerPos, &this->actor.focus.pos, &this->actor.shape.rot, &this->trackTarget, &this->headRot, + &this->torsoRot, &sTrackOptions); + + } else { // smooth her back to facing forward + Math_SmoothStepToS(&this->trackTarget.x, 0, 4, 0x3E8, 1); + Math_SmoothStepToS(&this->trackTarget.y, 0, 4, 0x3E8, 1); + Math_SmoothStepToS(&this->headRot.x, 0, 4, 0x3E8, 1); + Math_SmoothStepToS(&this->headRot.y, 0, 4, 0x3E8, 1); + Math_SmoothStepToS(&this->torsoRot.x, 0, 4, 0x3E8, 1); + Math_SmoothStepToS(&this->torsoRot.y, 0, 4, 0x3E8, 1); + } + + EnRu_UpdateEyes(this, 3); + EnRu_PlayWalkingSound(this, play); + SubS_FillLimbRotTables(play, this->limbRotTableY, this->limbRotTableZ, RU2_LIMB_MAX); +} + +void EnRu_DoNothing(EnRu* this, PlayState* play) { +} + +void EnRu_Init(Actor* thisx, PlayState* play) { + s32 pad; + EnRu* this = THIS; + + ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f); + SkelAnime_InitFlex(play, &this->skelAnime, &gAdultRutoSkel, NULL, this->jointTable, this->morphTable, RU2_LIMB_MAX); + EnRu_ChangeAnim(&this->skelAnime, 0); + Collider_InitCylinder(play, &this->collider); + Collider_SetCylinder(play, &this->collider, &this->actor, &sCylinderInit); + CollisionCheck_SetInfo2(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit); + + this->path = SubS_GetPathByIndex(play, RU_GET_PATH(thisx), 0x3F); + Actor_SetScale(&this->actor, 0.01f); + this->actionFunc = EnRu_DoNothing; + this->actor.gravity = -4.0f; +} + +void EnRu_Destroy(Actor* thisx, PlayState* play) { + EnRu* this = THIS; + + Collider_DestroyCylinder(play, &this->collider); +} + +void EnRu_Update(Actor* thisx, PlayState* play) { + EnRu* this = THIS; + + this->actionFunc(this, play); + Actor_UpdateBgCheckInfo(play, &this->actor, 0.0f, 0.0f, 0.0f, 4); + EnRu_UpdateModel(this, play); + EnRu_UpdateCollider(this, play); +} + +s32 EnRu_OverrideLimbdraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx, + Gfx** gfx) { + EnRu* this = THIS; + + if (limbIndex == RU2_LIMB_HEAD) { + Matrix_Translate(1500.0f, 0.0f, 0.0f, MTXMODE_APPLY); + Matrix_RotateXS(this->headRot.y, MTXMODE_APPLY); + Matrix_RotateZS(this->headRot.x, MTXMODE_APPLY); + Matrix_Translate(-1500.0f, 0.0f, 0.0f, MTXMODE_APPLY); + } + + if (limbIndex == RU2_LIMB_TORSO) { + Matrix_RotateYS(this->torsoRot.y, MTXMODE_APPLY); + Matrix_RotateXS(this->torsoRot.x, MTXMODE_APPLY); + } + + if ((limbIndex == RU2_LIMB_TORSO) || (limbIndex == RU2_LIMB_LEFT_UPPER_ARM) || + (limbIndex == RU2_LIMB_RIGHT_UPPER_ARM)) { + rot->y += (s16)(Math_SinS(this->limbRotTableY[limbIndex]) * 200.0f); + rot->z += (s16)(Math_CosS(this->limbRotTableZ[limbIndex]) * 200.0f); + } + + return false; +} + +void EnRu_PostLimbdraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx, Gfx** gfx) { + EnRu* this = THIS; + Vec3f headFocus = { 800.0f, 0, 0 }; + Vec3f bodyPartPos = { 0, 0, 0 }; + + if (sBodyPartPosIndices[limbIndex] >= 0) { + Matrix_MultVec3f(&bodyPartPos, &this->bodyPartsPos[sBodyPartPosIndices[limbIndex]]); + } + if (limbIndex == RU2_LIMB_HEAD) { + Matrix_MultVec3f(&headFocus, &thisx->focus.pos); + } + + if (limbIndex == RU2_LIMB_LEFT_FOOT) { + Matrix_MultVec3f(&bodyPartPos, &this->leftFootPos); + } + if (limbIndex == RU2_LIMB_RIGHT_FOOT) { + Matrix_MultVec3f(&bodyPartPos, &this->rightFootPos); + } +} + +// This is a copy of displaylist found in En_Zo +static Gfx sTransparencyDlist[] = { + gsDPSetRenderMode(AA_EN | Z_CMP | Z_UPD | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | ZMODE_XLU | FORCE_BL | + G_RM_FOG_SHADE_A, + AA_EN | Z_CMP | Z_UPD | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | ZMODE_XLU | FORCE_BL | + GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)), + gsDPSetAlphaCompare(G_AC_THRESHOLD), + gsSPEndDisplayList(), +}; + +void EnRu_Draw(Actor* thisx, PlayState* play) { + EnRu* this = THIS; + u8* shadowTex = GRAPH_ALLOC(play->state.gfxCtx, SUBS_SHADOW_TEX_SIZE); + u8* shadowTexIter; + s32 i; + TexturePtr eyeTextures[] = { gAdultRutoEyeOpenTex, gAdultRutoEyeHalfTex, gAdultRutoEyeClosedTex }; + + OPEN_DISPS(play->state.gfxCtx); + + func_8012C28C(play->state.gfxCtx); + + gDPPipeSync(POLY_OPA_DISP++); + + gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); + + gDPPipeSync(POLY_OPA_DISP++); + + gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(eyeTextures[this->eyeState])); + + // only runs the last command of the display list, which is gsSPEndDisplayList + gSPSegment(POLY_OPA_DISP++, 0x0C, &sTransparencyDlist[2]); + + POLY_OPA_DISP = + SkelAnime_DrawFlex(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, + EnRu_OverrideLimbdraw, EnRu_PostLimbdraw, &this->actor, POLY_OPA_DISP); + + Matrix_RotateXS(0, MTXMODE_NEW); + + for (i = 0, shadowTexIter = shadowTex; i < SUBS_SHADOW_TEX_SIZE; i++) { + *shadowTexIter++ = 0; + } + + for (i = 0; i < 5; i++) { + SubS_GenShadowTex(&this->bodyPartsPos[0], &this->actor.world.pos, shadowTex, (i / 5.0f), + (ARRAY_COUNT(sRuBodyParts)), sRuShadowSizes, sRuBodyParts); + } + + SubS_DrawShadowTex(&this->actor, &play->state, shadowTex); + + CLOSE_DISPS(play->state.gfxCtx); +} diff --git a/src/overlays/actors/ovl_En_Ru/z_en_ru.h b/src/overlays/actors/ovl_En_Ru/z_en_ru.h index 29c903aff2..b1144f88d7 100644 --- a/src/overlays/actors/ovl_En_Ru/z_en_ru.h +++ b/src/overlays/actors/ovl_En_Ru/z_en_ru.h @@ -2,15 +2,40 @@ #define Z_EN_RU_H #include "global.h" +#include "objects/object_ru2/object_ru2.h" + +#define RU_GET_PATH(thisx) ((thisx->params & 0x7E00) >> 9) struct EnRu; typedef void (*EnRuActionFunc)(struct EnRu*, PlayState*); +#define RU_BODYPARTSPOS_COUNT 15 + typedef struct EnRu { /* 0x000 */ Actor actor; /* 0x144 */ EnRuActionFunc actionFunc; - /* 0x148 */ char unk_148[0x30C]; + /* 0x148 */ SkelAnime skelAnime; + /* 0x18C */ ColliderCylinder collider; + /* 0x1D8 */ UNK_TYPE1 pad1D8[0x4]; + /* 0x1DC */ Path* path; // path is prepared in EnRu_Init, but unused after + /* 0x1E0 */ UNK_TYPE1 pad1E0[0x4]; + /* 0x1E4 */ Vec3f leftFootPos; + /* 0x1F0 */ Vec3f rightFootPos; + /* 0x1FC */ u8 isLeftFootGrounded; + /* 0x1FD */ u8 isRightFootGrounded; + /* 0x1FE */ Vec3s jointTable[RU2_LIMB_MAX]; + /* 0x288 */ Vec3s morphTable[RU2_LIMB_MAX]; + /* 0x312 */ Vec3s trackTarget; + /* 0x318 */ Vec3s headRot; + /* 0x31E */ Vec3s torsoRot; + /* 0x324 */ UNK_TYPE1 pad324[0x12]; + /* 0x336 */ s16 limbRotTableY[RU2_LIMB_MAX]; + /* 0x364 */ s16 limbRotTableZ[RU2_LIMB_MAX]; + /* 0x394 */ Vec3f bodyPartsPos[RU_BODYPARTSPOS_COUNT]; + /* 0x348 */ UNK_TYPE1 padUNK[6]; + /* 0x44E */ s16 eyeState; + /* 0x450 */ s16 blinkTimer; } EnRu; // size = 0x454 extern const ActorInit En_Ru_InitVars; diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 331f5c1934..3984924be4 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -10254,17 +10254,17 @@ 0x80A3862C:("DmZl_OverrideLimbDraw",), 0x80A38648:("DmZl_PostLimbDraw",), 0x80A3869C:("DmZl_Draw",), - 0x80A389A0:("func_80A389A0",), - 0x80A38A68:("func_80A38A68",), - 0x80A38B7C:("func_80A38B7C",), - 0x80A38BF0:("func_80A38BF0",), - 0x80A38C70:("func_80A38C70",), - 0x80A38DF4:("func_80A38DF4",), + 0x80A389A0:("EnRu_ChangeAnim",), + 0x80A38A68:("EnRu_PlayWalkingSound",), + 0x80A38B7C:("EnRu_UpdateEyes",), + 0x80A38BF0:("EnRu_UpdateCollider",), + 0x80A38C70:("EnRu_UpdateModel",), + 0x80A38DF4:("EnRu_DoNothing",), 0x80A38E04:("EnRu_Init",), 0x80A38F10:("EnRu_Destroy",), 0x80A38F3C:("EnRu_Update",), - 0x80A38FB4:("func_80A38FB4",), - 0x80A390F8:("func_80A390F8",), + 0x80A38FB4:("EnRu_OverrideLimbdraw",), + 0x80A390F8:("EnRu_PostLimbdraw",), 0x80A39204:("EnRu_Draw",), 0x80A396B0:("func_80A396B0",), 0x80A3970C:("EnElfgrp_Init",),