diff --git a/spec b/spec index 0e811e7e51..3afcf6b974 100644 --- a/spec +++ b/spec @@ -1189,8 +1189,7 @@ beginseg name "ovl_Obj_Mure" compress include "build/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.o" - include "build/data/ovl_Obj_Mure/ovl_Obj_Mure.data.o" - include "build/data/ovl_Obj_Mure/ovl_Obj_Mure.reloc.o" + include "build/src/overlays/actors/ovl_Obj_Mure/ovl_Obj_Mure_reloc.o" endseg beginseg diff --git a/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.c b/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.c index 7191ca259d..1519f92eba 100644 --- a/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.c +++ b/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.c @@ -14,11 +14,12 @@ void ObjMure_Init(Actor* thisx, GlobalContext* globalCtx); void ObjMure_Destroy(Actor* thisx, GlobalContext* globalCtx); void ObjMure_Update(Actor* thisx, GlobalContext* globalCtx); -void func_808D7FFC(ObjMure* this, GlobalContext* globalCtx); -void func_808D8014(ObjMure* this, GlobalContext* globalCtx); -void func_808D8678(ObjMure* this, GlobalContext* globalCtx); +void ObjMure_InitialAction(ObjMure* this, GlobalContext* globalCtx); +void ObjMure_CulledState(ObjMure* this, GlobalContext* globalCtx); +void ObjMure_ActiveState(ObjMure* this, GlobalContext* globalCtx); +void ObjMure_KillActors(ObjMure* this, GlobalContext* globalCtx); +void ObjMure_CheckChildren(ObjMure* this, GlobalContext* globalCtx); -#if 0 const ActorInit Obj_Mure_InitVars = { ACTOR_OBJ_MURE, ACTORCAT_ITEMACTION, @@ -31,53 +32,368 @@ const ActorInit Obj_Mure_InitVars = { (ActorFunc)NULL, }; -// static InitChainEntry sInitChain[] = { -static InitChainEntry D_808D87BC[] = { +static f32 sZClip[] = { + 1600.0f, 1600.0f, 1000.0f, 1000.0f, 1000.0f, +}; + +static s32 sMaxChildSpawns[] = { + 12, + 9, + 8, + 0, +}; + +static s16 sSpawnActorIds[] = { + ACTOR_EN_KUSA, 0, ACTOR_EN_FISH, ACTOR_EN_INSECT, ACTOR_EN_BUTTE, +}; + +static s16 sSpawnParams[] = { + 0, 2, -1, 0, -1, +}; + +static InitChainEntry sInitChain[] = { ICHAIN_F32(uncullZoneForward, 1200, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneScale, 200, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneDownward, 1200, ICHAIN_STOP), }; -#endif +typedef enum { + /* 0 */ OBJMURE_TYPE_GRASS, + /* 1 */ OBJMURE_TYPE_UNDEFINED, + /* 2 */ OBJMURE_TYPE_FISH, + /* 3 */ OBJMURE_TYPE_BUGS, + /* 4 */ OBJMURE_TYPE_BUTTERFLY, + /* 5 */ OBJMURE_TYPE_MAX +} ObjMureType; -extern InitChainEntry D_808D87BC[]; +typedef enum { + /* 0 */ OBJMURE_CHILD_STATE_0, + /* 1 */ OBJMURE_CHILD_STATE_DEAD, + /* 2 */ OBJMURE_CHILD_STATE_2 +} ObjMureChildState; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D78D0.s") +s32 func_808D78D0(ObjMure* this, GlobalContext* globalCtx) { + if (this->type == OBJMURE_TYPE_FISH || this->type == OBJMURE_TYPE_BUGS || this->type == OBJMURE_TYPE_BUTTERFLY) { + Actor_ProcessInitChain(&this->actor, sInitChain); + } else { + return false; + } + return true; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D7928.s") +s32 func_808D7928(ObjMure* this, GlobalContext* globalCtx) { + if (!func_808D78D0(this, globalCtx)) { + return false; + } + return true; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/ObjMure_Init.s") +void ObjMure_Init(Actor* thisx, GlobalContext* globalCtx) { + ObjMure* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/ObjMure_Destroy.s") + this->chNum = OBJ_MURE_GET_CHNUM(this->actor.params); + this->ptn = OBJ_MURE_GET_PTN(this->actor.params); + this->svNum = OBJ_MURE_GET_SVNUM(this->actor.params); + this->type = OBJ_MURE_GET_TYPE(this->actor.params); + if (this->ptn >= 4) { + Actor_MarkForDeath(&this->actor); + return; + } + if (this->type >= OBJMURE_TYPE_MAX) { + Actor_MarkForDeath(&this->actor); + return; + } + if (!func_808D7928(this, globalCtx)) { + Actor_MarkForDeath(&this->actor); + return; + } + this->actionFunc = ObjMure_InitialAction; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D7A14.s") +void ObjMure_Destroy(Actor* thisx, GlobalContext* globalCtx) { +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D7A40.s") +s32 ObjMure_GetMaxChildSpawns(ObjMure* this) { + if (this->chNum == 0) { + return sMaxChildSpawns[this->ptn]; + } + return this->chNum; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D7A68.s") +void ObjMure_GetSpawnPos(Vec3f* outPos, Vec3f* inPos, s32 ptn, s32 idx) { + *outPos = *inPos; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D7C64.s") +void ObjMure_SpawnActors0(Actor* thisx, GlobalContext* globalCtx) { + ObjMure* this = THIS; + s32 i; + Vec3f pos; + s32 pad; + s32 maxChildren = ObjMure_GetMaxChildSpawns(this); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D7DC4.s") + for (i = 0; i < maxChildren; i++) { + switch (this->childrenStates[i]) { + case OBJMURE_CHILD_STATE_DEAD: + break; + case OBJMURE_CHILD_STATE_2: + ObjMure_GetSpawnPos(&pos, &this->actor.world.pos, this->ptn, i); + this->children[i] = Actor_SpawnAsChildAndCutscene( + &globalCtx->actorCtx, globalCtx, sSpawnActorIds[this->type], pos.x, pos.y, pos.z, + this->actor.world.rot.x, this->actor.world.rot.y, this->actor.world.rot.z, sSpawnParams[this->type], + this->actor.cutscene, this->actor.unk20, NULL); + if (this->children[i] != NULL) { + if (this->type == 0x90) { + ((ObjMureChild*)this->children[i])->unk_197 = 1; + } + this->children[i]->room = this->actor.room; + } + break; + default: + ObjMure_GetSpawnPos(&pos, &this->actor.world.pos, this->ptn, i); + this->children[i] = Actor_SpawnAsChildAndCutscene( + &globalCtx->actorCtx, globalCtx, sSpawnActorIds[this->type], pos.x, pos.y, pos.z, + this->actor.world.rot.x, this->actor.world.rot.y, this->actor.world.rot.z, sSpawnParams[this->type], + this->actor.cutscene, this->actor.unk20, NULL); + if (this->children[i] != NULL) { + this->children[i]->room = this->actor.room; + } + break; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D7E14.s") +void ObjMure_SpawnActors1(ObjMure* this, GlobalContext* globalCtx) { + GlobalContext* globalCtx2 = globalCtx; + Actor* actor = &this->actor; + Vec3f spawnPos; + s32 maxChildren = ObjMure_GetMaxChildSpawns(this); + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D7F0C.s") + for (i = 0; i < maxChildren; i++) { + ObjMure_GetSpawnPos(&spawnPos, &actor->world.pos, this->ptn, i); + this->children[i] = Actor_SpawnAsChildAndCutscene( + &globalCtx->actorCtx, globalCtx, sSpawnActorIds[this->type], spawnPos.x, spawnPos.y, spawnPos.z, + actor->world.rot.x, actor->world.rot.y, actor->world.rot.z, + (this->type == OBJMURE_TYPE_BUTTERFLY && i == 0) ? 1 : sSpawnParams[this->type], this->actor.cutscene, + this->actor.unk20, NULL); + if (this->children[i] != NULL) { + this->childrenStates[i] = OBJMURE_CHILD_STATE_0; + this->children[i]->room = actor->room; + } else { + this->childrenStates[i] = OBJMURE_CHILD_STATE_DEAD; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D7F2C.s") +void ObjMure_SpawnActors(ObjMure* this, GlobalContext* globalCtx) { + switch (this->svNum) { + case 0: + ObjMure_SpawnActors0(&this->actor, globalCtx); + break; + case 1: + ObjMure_SpawnActors1(this, globalCtx); + break; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D7FFC.s") +void ObjMure_KillActorsImpl(ObjMure* this, GlobalContext* globalCtx) { + s32 maxChildren = ObjMure_GetMaxChildSpawns(this); + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D8014.s") + for (i = 0; i < maxChildren; i++) { + switch (this->childrenStates[i]) { + case OBJMURE_CHILD_STATE_DEAD: + this->children[i] = NULL; + break; + case OBJMURE_CHILD_STATE_2: + if (this->children[i] != NULL) { + Actor_MarkForDeath(this->children[i]); + this->children[i] = NULL; + } + break; + default: + if (this->children[i] != NULL) { + if (Actor_HasParent(this->children[i], globalCtx)) { + this->children[i] = NULL; + } else { + Actor_MarkForDeath(this->children[i]); + this->children[i] = NULL; + } + } + break; + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D8074.s") +void ObjMure_KillActors(ObjMure* this, GlobalContext* globalCtx) { + ObjMure_KillActorsImpl(this, globalCtx); +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D814C.s") +void ObjMure_CheckChildren(ObjMure* this, GlobalContext* globalCtx) { + s32 maxChildren = ObjMure_GetMaxChildSpawns(this); + s32 i; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D82CC.s") + for (i = 0; i < maxChildren; i++) { + if (this->children[i] != NULL) { + if (this->childrenStates[i] == OBJMURE_CHILD_STATE_0) { + if (this->children[i]->update != NULL) { + if ((this->type == 0x90) && (((ObjMureChild*)this->children[i])->unk_197 != 0)) { + this->childrenStates[i] = OBJMURE_CHILD_STATE_2; + } + } else { + this->childrenStates[i] = OBJMURE_CHILD_STATE_DEAD; + this->children[i] = NULL; + } + } else if (this->childrenStates[i] == OBJMURE_CHILD_STATE_2 && this->children[i]->update == NULL) { + this->childrenStates[i] = OBJMURE_CHILD_STATE_DEAD; + this->children[i] = NULL; + } + } + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D84F4.s") +void ObjMure_InitialAction(ObjMure* this, GlobalContext* globalCtx) { + this->actionFunc = ObjMure_CulledState; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/func_808D8678.s") +void ObjMure_CulledState(ObjMure* this, GlobalContext* globalCtx) { + if (fabsf(this->actor.projectedPos.z) < sZClip[this->type]) { + this->actionFunc = ObjMure_ActiveState; + this->actor.flags |= 0x10; + ObjMure_SpawnActors(this, globalCtx); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Mure/ObjMure_Update.s") +void ObjMure_SetFollowTargets(ObjMure* this, f32 randMax) { + s32 index; + s32 maxChildren = ObjMure_GetMaxChildSpawns(this); + s32 i; + + for (i = 0; i < maxChildren; i++) { + if (this->children[i] != NULL) { + this->children[i]->child = NULL; + if (Rand_ZeroOne() <= randMax) { + index = Rand_ZeroOne() * (maxChildren - 0.5f); + if (i != index) { + this->children[i]->child = this->children[index]; + } + } + } + } +} + +/** + * Selects a child that will follow after the player + * `idx1` is the index + 1 of the child that will follow the player. If `idx1` is zero, no actor will follow the player + */ +void ObjMure_SetChildToFollowPlayer(ObjMure* this, s32 idx1) { + s32 maxChildren = ObjMure_GetMaxChildSpawns(this); + s32 i; + s32 i2; + s32 j; + + for (i = 0, i2 = 0; i < maxChildren; i++) { + if (this->children[i] != NULL) { + if (i2 < idx1) { + i2++; + this->children[i]->child = this->children[i]; + for (j = 0; j < maxChildren; j++) { + if (i != j && this->children[j]->child == this->children[i]) { + this->children[j]->child = NULL; + } + } + } else if (this->children[i]->child == this->children[i]) { + this->children[i]->child = NULL; + } + } + } +} + +// Fish, Bugs +void ObjMure_GroupBehavior0(ObjMure* this, GlobalContext* globalCtx) { + if (this->unk_19C <= 0) { + if (this->unk_19E) { + this->unk_19E = false; + ObjMure_SetFollowTargets(this, (Rand_ZeroOne() * 0.5f) + 0.1f); + if (this->actor.xzDistToPlayer < 60.0f) { + this->unk_19C = (s32)(Rand_ZeroOne() * 5.5f) + 4; + } else { + this->unk_19C = (s32)(Rand_ZeroOne() * 40.5f) + 4; + } + } else { + this->unk_19E = true; + if (this->actor.xzDistToPlayer < 60.0f) { + this->unk_19C = (s32)(Rand_ZeroOne() * 10.5f) + 4; + ObjMure_SetFollowTargets(this, (Rand_ZeroOne() * 0.2f) + 0.8f); + } else { + this->unk_19C = (s32)(Rand_ZeroOne() * 10.5f) + 4; + ObjMure_SetFollowTargets(this, (Rand_ZeroOne() * 0.2f) + 0.6f); + } + } + } + if (this->actor.xzDistToPlayer < 120.0f) { + this->unk_1A0++; + } else { + this->unk_1A0 = 0; + } + if (this->unk_1A0 >= 80) { + ObjMure_SetChildToFollowPlayer(this, 1); + } else { + ObjMure_SetChildToFollowPlayer(this, 0); + } +} + +// Butterflies +void ObjMure_GroupBehavior1(ObjMure* this, GlobalContext* globalCtx) { + s32 maxChildren; + s32 i; + + if (this->unk_19C <= 0) { + if (this->unk_19E) { + this->unk_19E = false; + ObjMure_SetFollowTargets(this, Rand_ZeroOne() * 0.2f); + if (this->actor.xzDistToPlayer < 60.0f) { + this->unk_19C = (s32)(Rand_ZeroOne() * 5.5f) + 4; + } else { + this->unk_19C = (s32)(Rand_ZeroOne() * 40.5f) + 4; + } + } else { + this->unk_19E = true; + ObjMure_SetFollowTargets(this, Rand_ZeroOne() * 0.7f); + this->unk_19C = (s32)(Rand_ZeroOne() * 10.5f) + 4; + } + } + + maxChildren = ObjMure_GetMaxChildSpawns(this); + for (i = 0; i < maxChildren; i++) { + if (this->children[i] != NULL) { + if (this->children[i]->child != NULL && this->children[i]->child->update == NULL) { + this->children[i]->child = NULL; + } + } + } +} + +static ObjMureActionFunc sTypeGroupBehaviorFunc[] = { + NULL, NULL, ObjMure_GroupBehavior0, ObjMure_GroupBehavior0, ObjMure_GroupBehavior1, +}; + +void ObjMure_ActiveState(ObjMure* this, GlobalContext* globalCtx) { + ObjMure_CheckChildren(this, globalCtx); + if (sZClip[this->type] + 40.0f <= fabsf(this->actor.projectedPos.z)) { + this->actionFunc = ObjMure_CulledState; + this->actor.flags &= ~0x10; + ObjMure_KillActors(this, globalCtx); + } else if (sTypeGroupBehaviorFunc[this->type] != NULL) { + sTypeGroupBehaviorFunc[this->type](this, globalCtx); + } +} + +void ObjMure_Update(Actor* thisx, GlobalContext* globalCtx) { + ObjMure* this = THIS; + + if (this->unk_19C > 0) { + this->unk_19C--; + } + this->actionFunc(this, globalCtx); +} diff --git a/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.h b/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.h index dfb6e10c7c..1cb9a653a1 100644 --- a/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.h +++ b/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.h @@ -7,12 +7,33 @@ struct ObjMure; typedef void (*ObjMureActionFunc)(struct ObjMure*, GlobalContext*); +#define OBJMURE_MAX_SPAWNS 15 + +typedef struct { + Actor actor; + /* 0x144 */ char unk_144[0x53]; + /* 0x197 */ u8 unk_197; +} ObjMureChild; + typedef struct ObjMure { /* 0x0000 */ Actor actor; /* 0x0144 */ ObjMureActionFunc actionFunc; - /* 0x0148 */ char unk_144[0x5C]; + /* 0x0148 */ s16 chNum; + /* 0x014A */ s16 ptn; + /* 0x014C */ s16 svNum; + /* 0x014E */ s16 type; + /* 0x0150 */ Actor* children[OBJMURE_MAX_SPAWNS]; + /* 0x018C */ u8 childrenStates[OBJMURE_MAX_SPAWNS]; + /* 0x019C */ s16 unk_19C; + /* 0x019E */ s16 unk_19E; + /* 0x01A0 */ s16 unk_1A0; } ObjMure; // size = 0x1A4 extern const ActorInit Obj_Mure_InitVars; +#define OBJ_MURE_GET_CHNUM(params) ((params >> 12) & 0xF) +#define OBJ_MURE_GET_PTN(params) ((params >> 8) & 0x7) +#define OBJ_MURE_GET_SVNUM(params) ((params >> 5) & 0x3) +#define OBJ_MURE_GET_TYPE(params) (params & 0x1F) + #endif // Z_OBJ_MURE_H diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 8f3aa72489..f3780d6a6e 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -6401,21 +6401,21 @@ 0x808D7928:("func_808D7928",), 0x808D7954:("ObjMure_Init",), 0x808D7A04:("ObjMure_Destroy",), - 0x808D7A14:("func_808D7A14",), - 0x808D7A40:("func_808D7A40",), - 0x808D7A68:("func_808D7A68",), - 0x808D7C64:("func_808D7C64",), - 0x808D7DC4:("func_808D7DC4",), - 0x808D7E14:("func_808D7E14",), - 0x808D7F0C:("func_808D7F0C",), - 0x808D7F2C:("func_808D7F2C",), - 0x808D7FFC:("func_808D7FFC",), - 0x808D8014:("func_808D8014",), - 0x808D8074:("func_808D8074",), - 0x808D814C:("func_808D814C",), - 0x808D82CC:("func_808D82CC",), - 0x808D84F4:("func_808D84F4",), - 0x808D8678:("func_808D8678",), + 0x808D7A14:("ObjMure_GetMaxChildSpawns",), + 0x808D7A40:("ObjMure_GetSpawnPos",), + 0x808D7A68:("ObjMure_SpawnActors0",), + 0x808D7C64:("ObjMure_SpawnActors1",), + 0x808D7DC4:("ObjMure_SpawnActors",), + 0x808D7E14:("ObjMure_KillActorsImpl",), + 0x808D7F0C:("ObjMure_KillActors",), + 0x808D7F2C:("ObjMure_CheckChildren",), + 0x808D7FFC:("ObjMure_InitialAction",), + 0x808D8014:("ObjMure_CulledState",), + 0x808D8074:("ObjMure_SetFollowTargets",), + 0x808D814C:("ObjMure_SetChildToFollowPlayer",), + 0x808D82CC:("ObjMure_GroupBehavior0",), + 0x808D84F4:("ObjMure_GroupBehavior1",), + 0x808D8678:("ObjMure_ActiveState",), 0x808D8720:("ObjMure_Update",), 0x808D8940:("func_808D8940",), 0x808D8B58:("func_808D8B58",), diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt index 66e7166c98..64c4310c08 100644 --- a/tools/disasm/variables.txt +++ b/tools/disasm/variables.txt @@ -7130,7 +7130,6 @@ 0x808D784C:("D_808D784C","f32","",0x4), 0x808D7850:("D_808D7850","f32","",0x4), 0x808D8760:("Obj_Mure_InitVars","UNK_TYPE1","",0x1), - 0x808D8780:("D_808D8780","UNK_TYPE1","",0x1), 0x808DB9C0:("En_Sw_InitVars","UNK_TYPE1","",0x1), 0x808DB9E0:("D_808DB9E0","UNK_TYPE1","",0x1), 0x808DBA0C:("D_808DBA0C","UNK_PTR","",0x4),