From 78cb55ce97721147594f69218d9fb19436b292a9 Mon Sep 17 00:00:00 2001 From: Nick Sturgeon Date: Tue, 4 Jan 2022 00:02:53 -0500 Subject: [PATCH] ovl_En_Ruppecrow OK with documentation (#502) * Implement EnRuppecrow_Init * Implement EnRuppecrow_Destroy * Implement EnRuppecrow_Update * Implement EnRuppecrow_Draw * Implement func_80BE2260, func_80BE2808 * Implement func_80BE30F4 * Implement func_80BE2F6C * Implement func_80BE35A4 * Implement func_80BE2728 * Initial work on func_80BE2B80 * Implement func_80BE2B80 * Implement func_80BE2794 * Implement func_80BE3354 * Implement func_80BE348C * Implement func_80BE2E18 * Implement func_80BE2D4C * Run format script for cleanup * Implement func_80BE2668 * Implement func_80BE3178 * Implement func_80BE32DC * Initial work on func_80BE2874 * Implement func_80BE2874 * Implement func_80BE2330 * Implement func_80BE24CC * Move static data into C file * Rename D_WORDs to static names * Format and document EnRuppecrow * Update documentation * Apply feedback * Remove unecessary struct padding * Implement review suggestions * Run actorfixer * Use object header --- spec | 3 +- .../actors/ovl_En_Ruppecrow/z_en_ruppecrow.c | 617 ++++++++++++++++-- .../actors/ovl_En_Ruppecrow/z_en_ruppecrow.h | 31 +- undefined_syms.txt | 5 - 4 files changed, 602 insertions(+), 54 deletions(-) diff --git a/spec b/spec index eff5209fd..63775dadf 100644 --- a/spec +++ b/spec @@ -4919,8 +4919,7 @@ beginseg name "ovl_En_Ruppecrow" compress include "build/src/overlays/actors/ovl_En_Ruppecrow/z_en_ruppecrow.o" - include "build/data/ovl_En_Ruppecrow/ovl_En_Ruppecrow.data.o" - include "build/data/ovl_En_Ruppecrow/ovl_En_Ruppecrow.reloc.o" + include "build/src/overlays/actors/ovl_En_Ruppecrow/ovl_En_Ruppecrow_reloc.o" endseg beginseg diff --git a/src/overlays/actors/ovl_En_Ruppecrow/z_en_ruppecrow.c b/src/overlays/actors/ovl_En_Ruppecrow/z_en_ruppecrow.c index ba851d64d..a255b0b80 100644 --- a/src/overlays/actors/ovl_En_Ruppecrow/z_en_ruppecrow.c +++ b/src/overlays/actors/ovl_En_Ruppecrow/z_en_ruppecrow.c @@ -5,17 +5,41 @@ */ #include "z_en_ruppecrow.h" +#include "objects/object_crow/object_crow.h" #define FLAGS 0x00004030 #define THIS ((EnRuppecrow*)thisx) +enum { + ENRUPPECROW_EFFECT_NONE = 0, + ENRUPPECROW_EFFECT_ICE = 10, + ENRUPPECROW_EFFECT_LIGHT = 20, +}; + void EnRuppecrow_Init(Actor* thisx, GlobalContext* globalCtx); void EnRuppecrow_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnRuppecrow_Update(Actor* thisx, GlobalContext* globalCtx); void EnRuppecrow_Draw(Actor* thisx, GlobalContext* globalCtx); +void EnRuppecrow_HandleSong(EnRuppecrow*, GlobalContext*); +s32 EnRuppecrow_UpdateCollision(EnRuppecrow*, GlobalContext*); +void EnRuppecrow_UpdateRupees(EnRuppecrow*); +void EnRuppecrow_UpdateDamage(EnRuppecrow*, GlobalContext*); +void EnRuppecrow_HandleDeath(EnRuppecrow*); +void EnRuppecrow_FallToDespawn(EnRuppecrow*, GlobalContext*); +void EnRuppecrow_ShatterIce(EnRuppecrow*, GlobalContext*); +void EnRuppecrow_UpdatePosition(EnRuppecrow*, GlobalContext*); +s32 EnRuppecrow_CheckPlayedMatchingSong(GlobalContext*); +void EnRuppecrow_HandleSongCutscene(EnRuppecrow*, GlobalContext*); +s32 EnRuppecrow_ReachedPointClockwise(EnRuppecrow*, Path*, s32); +s32 EnRuppecrow_ReachedPointCounterClockwise(EnRuppecrow*, Path*, s32); +f32 EnRuppecrow_GetPointDirection(Path*, s32, PosRot*, Vec3s*); +s32 EnRuppecrow_CanSpawnBlueRupees(GlobalContext*); +void EnRuppecrow_SpawnRupee(EnRuppecrow*, GlobalContext*); +void EnRuppecrow_FlyWhileDroppingRupees(EnRuppecrow*, GlobalContext*); +void EnRuppecrow_UpdateSpeed(EnRuppecrow*, GlobalContext*); +void EnRuppecrow_FlyToDespawn(EnRuppecrow*, GlobalContext*); -#if 0 const ActorInit En_Ruppecrow_InitVars = { ACTOR_EN_RUPPECROW, ACTORCAT_ENEMY, @@ -28,25 +52,36 @@ const ActorInit En_Ruppecrow_InitVars = { (ActorFunc)EnRuppecrow_Draw, }; -// static ColliderJntSphElementInit sJntSphElementsInit[1] = { -static ColliderJntSphElementInit D_80BE39B0[1] = { +static ColliderJntSphElementInit sJntSphElementsInit[1] = { { - { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, + { + ELEMTYPE_UNK0, + { 0xF7CFFFFF, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, { 1, { { 0, 0, 0 }, 20 }, 100 }, }, }; -// static ColliderJntSphInit sJntSphInit = { -static ColliderJntSphInit D_80BE39D4 = { - { COLTYPE_HIT3, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_JNTSPH, }, - 1, D_80BE39B0, // sJntSphElementsInit, +static ColliderJntSphInit sJntSphInit = { + { + COLTYPE_HIT3, + AT_NONE, + AC_ON | AC_TYPE_PLAYER, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_JNTSPH, + }, + 1, + sJntSphElementsInit, }; -// sColChkInfoInit -static CollisionCheckInfoInit D_80BE39E4 = { 1, 15, 30, 30 }; +static CollisionCheckInfoInit sColChkInfoInit = { 1, 15, 30, 30 }; -// static DamageTable sDamageTable = { -static DamageTable D_80BE39EC = { +static DamageTable sDamageTable = { /* Deku Nut */ DMG_ENTRY(0, 0x1), /* Deku Stick */ DMG_ENTRY(1, 0x0), /* Horse trample */ DMG_ENTRY(1, 0x0), @@ -81,62 +116,558 @@ static DamageTable D_80BE39EC = { /* Powder Keg */ DMG_ENTRY(1, 0x0), }; -// static InitChainEntry sInitChain[] = { -static InitChainEntry D_80BE3A0C[] = { +static InitChainEntry sInitChain[] = { ICHAIN_F32_DIV1000(gravity, -500, ICHAIN_CONTINUE), ICHAIN_F32(targetArrowOffset, 2000, ICHAIN_STOP), }; -#endif +s32 EnRuppecrow_UpdateCollision(EnRuppecrow* this, GlobalContext* globalCtx) { + s32 pad; -extern ColliderJntSphElementInit D_80BE39B0[1]; -extern ColliderJntSphInit D_80BE39D4; -extern CollisionCheckInfoInit D_80BE39E4; -extern DamageTable D_80BE39EC; -extern InitChainEntry D_80BE3A0C[]; + this->collider.elements->dim.worldSphere.center.x = this->actor.world.pos.x; + this->collider.elements->dim.worldSphere.center.y = + sJntSphInit.elements->dim.modelSphere.center.y + this->actor.world.pos.y; + this->collider.elements->dim.worldSphere.center.z = this->actor.world.pos.z; -extern UNK_TYPE D_060000F0; + CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->collider.base); + Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 12.0f, 25.0f, 50.0f, 0x07); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE2260.s") + return true; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE2330.s") +s32 EnRuppecrow_ReachedPointClockwise(EnRuppecrow* this, Path* path, s32 pointIndex) { + Vec3s* points = Lib_SegmentedToVirtual(path->points); + s32 pathCount = path->count; + s32 currentPoint = pointIndex; + s32 reached = false; + f32 diffX; + f32 diffZ; + f32 px; + f32 pz; + f32 d; + Vec3f point; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE24CC.s") + Math_Vec3s_ToVec3f(&point, &points[currentPoint]); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE2668.s") + if (currentPoint == 0) { + diffX = points[1].x - points[0].x; + diffZ = points[1].z - points[0].z; + } else { + if (currentPoint == (pathCount - 1)) { + diffX = points[pathCount - 1].x - points[pathCount - 2].x; + diffZ = points[pathCount - 1].z - points[pathCount - 2].z; + } else { + diffX = points[currentPoint + 1].x - points[currentPoint - 1].x; + diffZ = points[currentPoint + 1].z - points[currentPoint - 1].z; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE2728.s") + func_8017B7F8(&point, RADF_TO_BINANG(func_80086B30(diffX, diffZ)), &px, &pz, &d); + if (((this->actor.world.pos.x * px) + (pz * this->actor.world.pos.z) + d) > 0.0f) { + reached = true; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE2794.s") + return reached; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE2808.s") +s32 EnRuppecrow_ReachedPointCounterClockwise(EnRuppecrow* this, Path* path, s32 pointIndex) { + Vec3s* points = Lib_SegmentedToVirtual(path->points); + s32 pathCount = path->count; + s32 currentPoint = pointIndex; + s32 reached = false; + f32 diffX; + f32 diffZ; + f32 px; + f32 pz; + f32 d; + Vec3f point; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE2874.s") + Math_Vec3s_ToVec3f(&point, &points[currentPoint]); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE2B80.s") + if (currentPoint == 0) { + diffX = points[0].x - points[1].x; + diffZ = points[0].z - points[1].z; + } else { + if (currentPoint == (pathCount - 1)) { + diffX = points[pathCount - 2].x - points[pathCount - 1].x; + diffZ = points[pathCount - 2].z - points[pathCount - 1].z; + } else { + diffX = points[currentPoint - 1].x - points[currentPoint + 1].x; + diffZ = points[currentPoint - 1].z - points[currentPoint + 1].z; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE2D4C.s") + func_8017B7F8(&point, RADF_TO_BINANG(func_80086B30(diffX, diffZ)), &px, &pz, &d); + if (((this->actor.world.pos.x * px) + (pz * this->actor.world.pos.z) + d) > 0.0f) { + reached = true; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE2E18.s") + return reached; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE2F6C.s") +f32 EnRuppecrow_GetPointDirection(Path* path, s32 pointIndex, PosRot* world, Vec3s* direction) { + Vec3s* points; + Vec3f point; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE30F4.s") + if (path != NULL) { + points = Lib_SegmentedToVirtual(path->points); + points = &points[pointIndex]; + VEC_SET(point, points->x, points->y, points->z); + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE3178.s") + direction->y = Math_Vec3f_Yaw(&world->pos, &point); + direction->x = Math_Vec3f_Pitch(&world->pos, &point); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE32DC.s") + return point.y - world->pos.y; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE3354.s") +void EnRuppecrow_ShatterIce(EnRuppecrow* this, GlobalContext* globalCtx) { + if (this->currentEffect == ENRUPPECROW_EFFECT_ICE) { + this->currentEffect = ENRUPPECROW_EFFECT_NONE; + this->unk_2C8 = 0.0f; + func_800BF7CC(globalCtx, &this->actor, this->limbPos, ENRUPPECROW_LIMB_POS_COUNT, 0x2, 0.2f, 0.2f); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE348C.s") +s32 EnRuppecrow_CanSpawnBlueRupees(GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/func_80BE35A4.s") + switch (player->transformation) { + case PLAYER_FORM_DEKU: + return false; + case PLAYER_FORM_GORON: + return true; + case PLAYER_FORM_ZORA: + return false; + case PLAYER_FORM_HUMAN: + if (player->stateFlags1 & 0x800000) { + return true; + } else { + return false; + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/EnRuppecrow_Init.s") + return false; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/EnRuppecrow_Destroy.s") +void EnRuppecrow_UpdateRupees(EnRuppecrow* this) { + EnItem00* rupee; + s16 rupeeIndex; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/EnRuppecrow_Update.s") + for (rupeeIndex = 0; rupeeIndex < ENRUPPECROW_RUPEE_COUNT; rupeeIndex++) { + rupee = this->rupees[rupeeIndex]; + if (rupee != NULL && rupee->unk152 == 0) { + Actor_MarkForDeath(&rupee->actor); + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Ruppecrow/EnRuppecrow_Draw.s") +void EnRuppecrow_SpawnRupee(EnRuppecrow* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + f32 xOffset; + EnItem00* rupee; + s16 rupeeIndex = this->rupeeIndex; + + if (!(player->stateFlags3 & 0x1000)) { + xOffset = (this->rupeeIndex & 1) ? 10.0f : -10.0f; + } else { + xOffset = 0.0f; + } + + if (EnRuppecrow_CanSpawnBlueRupees(globalCtx) && (this->rupeeIndex % 5) == 4) { + if (this->rupeeIndex == 19) { + rupee = (EnItem00*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_ITEM00, + this->actor.world.pos.x + xOffset, this->actor.world.pos.y, + this->actor.world.pos.z, 0x0, 0x0, 0x0, ITEM00_RUPEE_RED); + this->rupees[rupeeIndex] = rupee; + this->rupees[rupeeIndex]->actor.gravity = -5.0f; + this->rupees[rupeeIndex]->actor.velocity.y = 0.0f; + Audio_PlayActorSound2(&this->actor, NA_SE_EV_RUPY_FALL); + rupee = this->rupees[rupeeIndex]; + rupee->unk152 = 60; + this->rupees[rupeeIndex]->actor.flags |= 0x10; + } else { + rupee = (EnItem00*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_ITEM00, + this->actor.world.pos.x + xOffset, this->actor.world.pos.y, + this->actor.world.pos.z, 0x0, 0x0, 0x0, ITEM00_RUPEE_BLUE); + this->rupees[rupeeIndex] = rupee; + this->rupees[rupeeIndex]->actor.gravity = -5.0f; + this->rupees[rupeeIndex]->actor.velocity.y = 0.0f; + Audio_PlayActorSound2(&this->actor, NA_SE_EV_RUPY_FALL); + rupee = this->rupees[rupeeIndex]; + rupee->unk152 = 60; + this->rupees[rupeeIndex]->actor.flags |= 0x10; + } + } else if (this->rupeeIndex == 19) { + rupee = + (EnItem00*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_ITEM00, this->actor.world.pos.x + xOffset, + this->actor.world.pos.y, this->actor.world.pos.z, 0x0, 0x0, 0x0, ITEM00_RUPEE_RED); + this->rupees[rupeeIndex] = rupee; + this->rupees[rupeeIndex]->actor.gravity = -5.0f; + this->rupees[rupeeIndex]->actor.velocity.y = 0.0f; + Audio_PlayActorSound2(&this->actor, NA_SE_EV_RUPY_FALL); + rupee = this->rupees[rupeeIndex]; + rupee->unk152 = 60; + this->rupees[rupeeIndex]->actor.flags |= 0x10; + } else { + rupee = + (EnItem00*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_ITEM00, this->actor.world.pos.x + xOffset, + this->actor.world.pos.y, this->actor.world.pos.z, 0x0, 0x0, 0x0, ITEM00_RUPEE_GREEN); + this->rupees[rupeeIndex] = rupee; + this->rupees[rupeeIndex]->actor.gravity = -5.0f; + this->rupees[rupeeIndex]->actor.velocity.y = 0.0f; + Audio_PlayActorSound2(&this->actor, NA_SE_EV_RUPY_FALL); + rupee = this->rupees[rupeeIndex]; + rupee->unk152 = 60; + this->rupees[rupeeIndex]->actor.flags |= 0x10; + } + + this->rupeeIndex++; +} + +void EnRuppecrow_UpdatePosition(EnRuppecrow* this, GlobalContext* globalCtx) { + Vec3s nextPointDirection; + + EnRuppecrow_GetPointDirection(this->path, this->currentPoint, &this->actor.world, &nextPointDirection); + if (this->actor.bgCheckFlags & 0x8) { + nextPointDirection.y = this->actor.wallYaw; + } + + Math_SmoothStepToS(&this->actor.world.rot.y, nextPointDirection.y, 0x4, 0x3E8, 0x1); + this->actor.shape.rot.y = this->actor.world.rot.y; + Math_SmoothStepToS(&this->actor.world.rot.x, -nextPointDirection.x, 0x4, 0x3E8, 0x1); + + if (this->isGoingCounterClockwise & 1) { + if (EnRuppecrow_ReachedPointCounterClockwise(this, this->path, this->currentPoint)) { + if (this->currentPoint <= 0) { + this->currentPoint = this->path->count - 1; + } else { + this->currentPoint--; + } + + if (this->actionFunc == EnRuppecrow_FlyWhileDroppingRupees && + (!EnRuppecrow_CanSpawnBlueRupees(globalCtx) || (this->currentPoint % -2) == 0)) { + EnRuppecrow_SpawnRupee(this, globalCtx); + } + } + } else if (EnRuppecrow_ReachedPointClockwise(this, this->path, this->currentPoint)) { + if (this->currentPoint >= this->path->count - 1) { + this->currentPoint = 0; + } else { + this->currentPoint++; + } + + if (this->actionFunc == EnRuppecrow_FlyWhileDroppingRupees && + (!EnRuppecrow_CanSpawnBlueRupees(globalCtx) || (this->currentPoint % -2) == 0)) { + EnRuppecrow_SpawnRupee(this, globalCtx); + } + } +} + +s32 EnRuppecrow_CheckPlayedMatchingSong(GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + if (globalCtx->msgCtx.unk1202A == 0x3) { + switch (player->transformation) { + case PLAYER_FORM_DEKU: + if (globalCtx->msgCtx.unk1202E == OCARINA_SONG_SONATA) { + return true; + } + break; + case PLAYER_FORM_GORON: + if (globalCtx->msgCtx.unk1202E == OCARINA_SONG_GORON_LULLABY) { + return true; + } + break; + case PLAYER_FORM_ZORA: + if (globalCtx->msgCtx.unk1202E == OCARINA_SONG_NEW_WAVE) { + return true; + } + break; + case PLAYER_FORM_HUMAN: + if (globalCtx->msgCtx.unk1202E == OCARINA_SONG_SONATA) { + return true; + } else if (globalCtx->msgCtx.unk1202E == OCARINA_SONG_GORON_LULLABY) { + return true; + } else if (globalCtx->msgCtx.unk1202E == OCARINA_SONG_NEW_WAVE) { + return true; + } + break; + } + } + + return false; +} + +void EnRuppecrow_UpdateSpeed(EnRuppecrow* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + switch (player->transformation) { + case PLAYER_FORM_DEKU: + this->speedModifier = 7.0f; + break; + case PLAYER_FORM_GORON: + if (player->stateFlags3 & 0x1000) { // Goron Link is curled + this->speedModifier = 19.0f; + } else { + this->speedModifier = 7.0f; + } + break; + case PLAYER_FORM_ZORA: + this->speedModifier = 7.0f; + break; + case PLAYER_FORM_HUMAN: + if (player->stateFlags1 & 0x800000) { + this->speedModifier = 16.0f; + } else { + this->speedModifier = 7.0f; + } + break; + } + + this->skelAnime.playSpeed = this->speedModifier / 6.0f; + if (this->actor.xzDistToPlayer > 800.0f) { + this->speedModifier *= 0.5f; + } else if (this->actor.xzDistToPlayer > 500.0f) { + this->speedModifier *= 0.8f; + } else if (this->actor.xzDistToPlayer < 150.0f) { + this->speedModifier *= 1.2f; + } +} + +void EnRuppecrow_HandleDeath(EnRuppecrow* this) { + f32 scale; + + this->actor.speedXZ *= Math_CosS(this->actor.world.rot.x); + this->actor.velocity.y = 0.0f; + Animation_Change(&this->skelAnime, &object_crow_Anim_0000F0, 0.4f, 0.0f, 0.0f, 0x1, -3.0f); + + this->actor.shape.yOffset = 0.0f; + this->actor.targetArrowOffset = 0.0f; + this->actor.bgCheckFlags &= ~0x1; + + scale = this->actor.scale.x * 100.0f; + this->actor.world.pos.y += 20.0f * scale; + + Audio_PlayActorSound2(&this->actor, NA_SE_EN_KAICHO_DEAD); + + this->unk_2CC = 0.5f; + if (this->actor.colChkInfo.damageEffect == 0x3) { + this->currentEffect = ENRUPPECROW_EFFECT_ICE; + this->unk_2C8 = 1.0f; + this->iceSfxTimer = 0.75f; + } else if (this->actor.colChkInfo.damageEffect == 0x4) { + this->currentEffect = ENRUPPECROW_EFFECT_LIGHT; + this->unk_2C8 = 5.0f; + } else if (this->actor.colChkInfo.damageEffect == 0x2) { + this->currentEffect = ENRUPPECROW_EFFECT_NONE; + this->unk_2C8 = 5.0f; + } + + func_800BCB70(&this->actor, 0x4000, 0xFF, 0x0, 0x28); + if (this->actor.flags & 0x8000) { + this->actor.speedXZ = 0.0f; + } + + this->collider.base.acFlags &= ~AC_ON; + this->actor.flags |= 0x10; + this->actionFunc = EnRuppecrow_FallToDespawn; +} + +void EnRuppecrow_UpdateDamage(EnRuppecrow* this, GlobalContext* globalCtx) { + if (this->collider.base.acFlags & AC_HIT) { + this->collider.base.acFlags &= ~AC_HIT; + func_800BE258(&this->actor, this->collider.elements); + + if (this->actor.colChkInfo.damageEffect != 0x1) { + this->actor.colChkInfo.health = 0; + this->actor.flags &= ~0x1; + Enemy_StartFinishingBlow(globalCtx, &this->actor); + EnRuppecrow_HandleDeath(this); + } + } +} + +void EnRuppecrow_HandleSong(EnRuppecrow* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + + EnRuppecrow_UpdatePosition(this, globalCtx); + if (this->actor.xzDistToPlayer < 1000.0f && EnRuppecrow_CheckPlayedMatchingSong(globalCtx)) { + // If Link is in front, the guay will turn around and go the other way + if (Actor_IsActorFacingLink(&this->actor, 0x4000)) { + this->isGoingCounterClockwise |= 1; + if (this->currentPoint > 0) { + this->currentPoint--; + } else { + this->currentPoint = this->path->count - 1; + } + } + + ActorCutscene_SetIntentToPlay(this->actor.cutscene); + this->actionFunc = EnRuppecrow_HandleSongCutscene; + } + + if (player->stateFlags2 & 0x8000000) { + Math_ApproachF(&this->actor.speedXZ, 0.0f, 0.1f, 1.0f); + } else { + Math_ApproachF(&this->actor.speedXZ, 6.0f, 0.1f, 0.1f); + } + + Actor_SetVelocityAndMoveXYRotation(&this->actor); + this->yOffset += 0x1000; + this->actor.shape.yOffset = Math_SinS(this->yOffset) * 500.0f; + + if ((globalCtx->state.frames % 43) == 0) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_KAICHO_CRY); + } +} + +void EnRuppecrow_HandleSongCutscene(EnRuppecrow* this, GlobalContext* globalCtx) { + EnRuppecrow_UpdatePosition(this, globalCtx); + + if (ActorCutscene_GetCanPlayNext(this->actor.cutscene)) { + ActorCutscene_Start(this->actor.cutscene, &this->actor); + EnRuppecrow_UpdateSpeed(this, globalCtx); + this->actionFunc = EnRuppecrow_FlyWhileDroppingRupees; + } else { + ActorCutscene_SetIntentToPlay(this->actor.cutscene); + } + + Actor_SetVelocityAndMoveXYRotation(&this->actor); +} + +void EnRuppecrow_FlyWhileDroppingRupees(EnRuppecrow* this, GlobalContext* globalCtx) { + EnRuppecrow_UpdatePosition(this, globalCtx); + + if (this->rupeeIndex >= ENRUPPECROW_RUPEE_COUNT) { + // Finished spawning rupees; fly up and then despawn + this->speedModifier = 6.0f; + + // Source of the "Termina Field Guay Glitch"; guay will no longer fall if killed after this point + this->actor.gravity = 0.0f; + + Math_ApproachF(&this->actor.speedXZ, 6.0f, 0.2f, 0.5f); + Math_ApproachF(&this->actor.velocity.y, 3.0f, 0.2f, 0.5f); + + this->actionFunc = EnRuppecrow_FlyToDespawn; + this->skelAnime.playSpeed = 1.0f; + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + } else { + if (ActorCutscene_GetCurrentIndex() != this->actor.cutscene) { + EnRuppecrow_UpdateSpeed(this, globalCtx); + Math_ApproachF(&this->actor.speedXZ, this->speedModifier, 0.2f, 0.5f); + } + + Actor_SetVelocityAndMoveXYRotation(&this->actor); + this->yOffset += 0x1000; + this->actor.shape.yOffset = Math_SinS(this->yOffset) * 500.0f; + + if ((globalCtx->state.frames % 43) == 0) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_KAICHO_CRY); + } + } +} + +void EnRuppecrow_FlyToDespawn(EnRuppecrow* this, GlobalContext* globalCtx) { + if (this->actor.bgCheckFlags & 0x8) { + this->actor.world.rot.y *= -0x1; + } + + Math_ApproachF(&this->actor.speedXZ, this->speedModifier, 0.1f, 0.1f); + Math_ApproachF(&this->actor.velocity.y, 3.0f, 0.2f, 0.5f); + + if (this->actor.world.pos.y > 1000.0f || this->actor.xzDistToPlayer > 2000.0f) { + Actor_MarkForDeath(&this->actor); + } else { + this->yOffset += 0x800; + this->actor.shape.yOffset = Math_SinS(this->yOffset) * 500.0f; + + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + + if ((globalCtx->state.frames % 43) == 0) { + Audio_PlayActorSound2(&this->actor, NA_SE_EN_KAICHO_CRY); + } + } +} + +void EnRuppecrow_FallToDespawn(EnRuppecrow* this, GlobalContext* globalCtx) { + Math_StepToF(&this->actor.speedXZ, 0.0f, 0.5f); + + if (this->currentEffect != ENRUPPECROW_EFFECT_ICE) { + Math_StepToF(&this->unk_2C8, 0.0f, 0.05f); + this->unk_2CC = (this->unk_2C8 + 1.0f) * 0.25f; + this->unk_2CC = CLAMP_MAX(this->unk_2CC, 0.5f); + } else if (!Math_StepToF(&this->iceSfxTimer, 0.5f, 0.0125f)) { + func_800B9010(&this->actor, NA_SE_EV_ICE_FREEZE - SFX_FLAG); + } + + this->actor.colorFilterTimer = 40; + if (!(this->actor.flags & 0x8000)) { + if (this->currentEffect != ENRUPPECROW_EFFECT_ICE) { + Math_ScaledStepToS(&this->actor.shape.rot.x, 0x4000, 0x200); + this->actor.shape.rot.z += 0x1780; + } + + if (this->actor.bgCheckFlags & 0x1 || this->actor.floorHeight == BGCHECK_Y_MIN) { + EnRuppecrow_ShatterIce(this, globalCtx); + func_800B3030(globalCtx, &this->actor.world.pos, &gZeroVec3f, &gZeroVec3f, (this->actor.scale.x * 10000.0f), + 0x0, 0x0); + + Audio_PlaySoundAtPosition(globalCtx, &this->actor.world.pos, 0xB, NA_SE_EN_EXTINCT); + Actor_MarkForDeath(&this->actor); + return; + } + } + + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); +} + +void EnRuppecrow_Init(Actor* thisx, GlobalContext* globalCtx2) { + EnRuppecrow* this = THIS; + GlobalContext* globalCtx = globalCtx2; + + Actor_ProcessInitChain(&this->actor, sInitChain); + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &object_crow_Skel_0010C0, &object_crow_Anim_0000F0, this->joinTable, + this->morphTable, ENRUPPECROW_LIMB_COUNT); + ActorShape_Init(&this->actor.shape, 2000.0f, func_800B3FC0, 20.0f); + + Collider_InitJntSph(globalCtx, &this->collider); + Collider_InitAndSetJntSph(globalCtx, &this->collider, &this->actor, &sJntSphInit, &this->colliderElement); + this->collider.elements->dim.worldSphere.radius = sJntSphInit.elements->dim.modelSphere.radius; + CollisionCheck_SetInfo(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit); + + Actor_SetScale(&this->actor, 0.01f); + this->actor.flags |= 0x2000000; + + this->path = func_8013D648(globalCtx, ENRUPPECROW_GET_PATH(&this->actor), 0x3F); + if (this->path != NULL) { + this->actionFunc = EnRuppecrow_HandleSong; + } else { + Actor_MarkForDeath(&this->actor); + } +} + +void EnRuppecrow_Destroy(Actor* thisx, GlobalContext* globalCtx) { + EnRuppecrow* this = THIS; + + Collider_DestroyJntSph(globalCtx, &this->collider); +} + +void EnRuppecrow_Update(Actor* thisx, GlobalContext* globalCtx) { + EnRuppecrow* this = THIS; + + EnRuppecrow_UpdateDamage(this, globalCtx); + this->actionFunc(this, globalCtx); + EnRuppecrow_UpdateRupees(this); + this->actor.focus.pos = this->actor.world.pos; + SkelAnime_Update(&this->skelAnime); + EnRuppecrow_UpdateCollision(this, globalCtx); +} + +void EnRuppecrow_Draw(Actor* thisx, GlobalContext* globalCtx) { + EnRuppecrow* this = THIS; + + func_8012C28C(globalCtx->state.gfxCtx); + SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, + NULL, NULL, &this->actor); +} diff --git a/src/overlays/actors/ovl_En_Ruppecrow/z_en_ruppecrow.h b/src/overlays/actors/ovl_En_Ruppecrow/z_en_ruppecrow.h index eeba6774d..4c9cafa67 100644 --- a/src/overlays/actors/ovl_En_Ruppecrow/z_en_ruppecrow.h +++ b/src/overlays/actors/ovl_En_Ruppecrow/z_en_ruppecrow.h @@ -3,15 +3,38 @@ #include "global.h" +#define ENRUPPECROW_GET_PATH(thisx) (((thisx)->params & 0xFC00) >> 0xA) + +#define ENRUPPECROW_RUPEE_COUNT 20 +#define ENRUPPECROW_LIMB_COUNT 9 +#define ENRUPPECROW_LIMB_POS_COUNT 4 + struct EnRuppecrow; typedef void (*EnRuppecrowActionFunc)(struct EnRuppecrow*, GlobalContext*); typedef struct EnRuppecrow { - /* 0x0000 */ Actor actor; - /* 0x0144 */ char unk_144[0x94]; - /* 0x01D8 */ EnRuppecrowActionFunc actionFunc; - /* 0x01DC */ char unk_1DC[0x128]; + /* 0x000 */ Actor actor; + /* 0x144 */ EnItem00* rupees[ENRUPPECROW_RUPEE_COUNT]; + /* 0x194 */ SkelAnime skelAnime; + /* 0x1D8 */ EnRuppecrowActionFunc actionFunc; + /* 0x1DC */ UNK_TYPE4 unk_1DC; // unused + /* 0x1E0 */ Vec3s joinTable[ENRUPPECROW_LIMB_COUNT]; + /* 0x216 */ Vec3s morphTable[ENRUPPECROW_LIMB_COUNT]; + /* 0x24C */ Path* path; + /* 0x250 */ s32 currentPoint; + /* 0x254 */ ColliderJntSph collider; + /* 0x274 */ ColliderJntSphElement colliderElement; + /* 0x2B4 */ u16 isGoingCounterClockwise; + /* 0x2B8 */ f32 speedModifier; + /* 0x2BC */ s16 rupeeIndex; + /* 0x2BE */ s16 yOffset; + /* 0x2C0 */ UNK_TYPE4 unk_2C0; // unused + /* 0x2C4 */ u8 currentEffect; + /* 0x2C8 */ f32 unk_2C8; // set but not used + /* 0x2CC */ f32 unk_2CC; // set but not used + /* 0x2D0 */ f32 iceSfxTimer; + /* 0x2D4 */ Vec3f limbPos[ENRUPPECROW_LIMB_POS_COUNT]; } EnRuppecrow; // size = 0x304 extern const ActorInit En_Ruppecrow_InitVars; diff --git a/undefined_syms.txt b/undefined_syms.txt index e39fb6782..9a52cd69a 100644 --- a/undefined_syms.txt +++ b/undefined_syms.txt @@ -3311,11 +3311,6 @@ D_06009220 = 0x06009220; D_0600C700 = 0x0600C700; -// ovl_En_Ruppecrow - -D_060000F0 = 0x060000F0; -D_060010C0 = 0x060010C0; - // ovl_En_Rz D_06003A20 = 0x06003A20;