diff --git a/include/functions.h b/include/functions.h index 806c7e65bf..832399af65 100644 --- a/include/functions.h +++ b/include/functions.h @@ -533,7 +533,7 @@ void func_800AE5E4(GlobalContext* globalCtx, Color_RGBA8* arg1, s16 arg2, s16 ar void func_800AE778(GlobalContext* globalCtx, Color_RGBA8* color, s16 param_3, s16 param_4); void func_800AE8EC(GlobalContext* globalCtx); void func_800AE930(CollisionContext* colCtx, s32 param_2, Vec3f* param_3, f32 param_4, s16 param_5, CollisionPoly* param_6, s32 param_7); -void func_800AEF44(s32 arg0); +void func_800AEF44(s32 arg0); void EffectTireMark_InitParticle(EffTireMarkParticle* particle); void EffectTireMark_Init(EffTireMarkParams* params, EffTireMarkInit* init); void EffectTireMark_Destroy(EffTireMarkParams* params); @@ -2754,11 +2754,11 @@ void func_801420C0(void* arg0); void func_801420F4(void* arg0); void func_80142100(void* arg0, Gfx** gfx, u32 arg2); s32 func_80142440(SkyboxContext* skyboxCtx, Vtx* vtx, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6, s32 arg7, - s32 arg8); -void func_80143148(SkyboxContext* skyboxCtx, s32 arg1); -void func_801431E8(GameState* gameState, SkyboxContext* skyboxCtx, s16 skyType); + s32 arg8); +void func_80143148(SkyboxContext* skyboxCtx, s32 arg1); +void func_801431E8(GameState* gameState, SkyboxContext* skyboxCtx, s16 skyType); void func_80143324(GlobalContext* globalCtx, SkyboxContext* skyboxCtx, s16 skyType); -void func_801434E4(GameState* gameState, SkyboxContext* skyboxCtx, s16 skyType); +void func_801434E4(GameState* gameState, SkyboxContext* skyboxCtx, s16 skyType); // void func_801435A0(void); // void func_80143624(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE1 param_5, UNK_TYPE1 param_6, UNK_TYPE1 param_7); // void func_80143668(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6, UNK_TYPE4 param_7); @@ -3192,7 +3192,7 @@ void Sched_Init(SchedContext* sched, void* stack, OSPri pri, UNK_TYPE arg3, UNK_ void func_801773A0(void* arg0); void func_801773C4(void* arg0); void SpeedMeter_DrawTimeEntries(void* displayList, GraphicsContext* gfxCtx); -// void func_80177A84(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE2 param_5, UNK_TYPE4 param_6, UNK_TYPE4 param_7, UNK_TYPE4 param_8, UNK_TYPE4 param_9); +// void func_80177A84(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE2 param_5, UNK_TYPE4 param_6, UNK_TYPE4 param_7, UNK_TYPE4 param_8, UNK_TYPE4 param_9); //void func_80177AC8(void); void SpeedMeter_DrawAllocEntries(void* displayList, GraphicsContext* gfxCtx, GameState* gameState); void func_801780F0(Mtx* param_1, f32 param_2, f32 param_3, f32 param_4, f32 param_5, f32 param_6, f32 param_7); @@ -3932,8 +3932,8 @@ void func_801A4D00(void); // void func_801A4EB0(void); // void func_801A4EB8(void); // void func_801A4FD8(void); -// void func_801A5080(void); -// void func_801A5100(void); +void func_801A5080(u16 arg0); +u16 func_801A5100(void); // void func_801A5118(void); UNK_TYPE func_801A51F0(UNK_TYPE arg0); // void func_801A5228(void); diff --git a/include/variables.h b/include/variables.h index 29ab452863..86f4fd6a01 100644 --- a/include/variables.h +++ b/include/variables.h @@ -912,7 +912,7 @@ extern s32 graphNumGameStates; // extern UNK_TYPE2 D_801BDA7C; extern s32 D_801BDA9C; extern UNK_TYPE4 D_801BDAA0; -// extern UNK_TYPE4 D_801BDAA4; +extern UNK_TYPE4 D_801BDAA4; // extern UNK_TYPE2 D_801BDAA8; // extern UNK_TYPE2 D_801BDAAA; // extern UNK_TYPE2 D_801BDAAC; diff --git a/include/z64item.h b/include/z64item.h index a312e69619..82dc6e352f 100644 --- a/include/z64item.h +++ b/include/z64item.h @@ -327,6 +327,7 @@ typedef enum { /* 0x8D */ GI_MASK_BLAST, /* 0x8E */ GI_MASK_SCENTS, /* 0x8F */ GI_MASK_GIANT, + /* 0x92 */ GI_MILK = 0x92, /* 0x96 */ GI_MOON_TEAR = 0x96, /* 0x97 */ GI_DEED_LAND, /* 0x98 */ GI_DEED_SWAMP, diff --git a/spec b/spec index 3afcf6b974..7a608029bb 100644 --- a/spec +++ b/spec @@ -2229,8 +2229,7 @@ beginseg name "ovl_En_Cow" compress include "build/src/overlays/actors/ovl_En_Cow/z_en_cow.o" - include "build/data/ovl_En_Cow/ovl_En_Cow.data.o" - include "build/data/ovl_En_Cow/ovl_En_Cow.reloc.o" + include "build/src/overlays/actors/ovl_En_Cow/ovl_En_Cow_reloc.o" endseg beginseg diff --git a/src/overlays/actors/ovl_En_Cow/z_en_cow.c b/src/overlays/actors/ovl_En_Cow/z_en_cow.c index 84f6928a73..9e7b66dd7a 100644 --- a/src/overlays/actors/ovl_En_Cow/z_en_cow.c +++ b/src/overlays/actors/ovl_En_Cow/z_en_cow.c @@ -15,16 +15,18 @@ void EnCow_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnCow_Update(Actor* thisx, GlobalContext* globalCtx); void EnCow_Draw(Actor* thisx, GlobalContext* globalCtx); -void func_8099CAA8(EnCow* this, GlobalContext* globalCtx); -void func_8099CB20(EnCow* this, GlobalContext* globalCtx); -void func_8099CB68(EnCow* this, GlobalContext* globalCtx); -void func_8099CBCC(EnCow* this, GlobalContext* globalCtx); -void func_8099CC68(EnCow* this, GlobalContext* globalCtx); -void func_8099CCF8(EnCow* this, GlobalContext* globalCtx); -void func_8099CDA0(EnCow* this, GlobalContext* globalCtx); -void func_8099CFAC(EnCow* this, GlobalContext* globalCtx); +void EnCow_TalkEnd(EnCow* this, GlobalContext* globalCtx); +void EnCow_GiveMilkEnd(EnCow* this, GlobalContext* globalCtx); +void EnCow_GiveMilkWait(EnCow* this, GlobalContext* globalCtx); +void EnCow_GiveMilk(EnCow* this, GlobalContext* globalCtx); +void EnCow_CheckForEmptyBottle(EnCow* this, GlobalContext* globalCtx); +void EnCow_Talk(EnCow* this, GlobalContext* globalCtx); +void EnCow_Idle(EnCow* this, GlobalContext* globalCtx); + +void EnCow_DoTail(EnCow* this, GlobalContext* globalCtx); +void EnCow_UpdateTail(Actor* this, GlobalContext* globalCtx); +void EnCow_DrawTail(Actor* this, GlobalContext* globalCtx); -#if 0 const ActorInit En_Cow_InitVars = { ACTOR_EN_COW, ACTORCAT_NPC, @@ -37,57 +39,404 @@ const ActorInit En_Cow_InitVars = { (ActorFunc)EnCow_Draw, }; -// static ColliderCylinderInit sCylinderInit = { -static ColliderCylinderInit D_8099D610 = { - { COLTYPE_NONE, AT_NONE, AC_ON | AC_TYPE_ENEMY, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1, COLSHAPE_CYLINDER, }, - { ELEMTYPE_UNK0, { 0x00000000, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_ON, }, +static ColliderCylinderInit sCylinderInit = { + { + COLTYPE_NONE, + AT_NONE, + AC_ON | AC_TYPE_ENEMY, + OC1_ON | OC1_TYPE_ALL, + OC2_TYPE_1, + COLSHAPE_CYLINDER, + }, + { + ELEMTYPE_UNK0, + { 0x00000000, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_NONE | TOUCH_SFX_NORMAL, + BUMP_ON, + OCELEM_ON, + }, { 30, 40, 0, { 0, 0, 0 } }, }; -#endif +Vec3f D_8099D63C = { 0.0f, -1300.0f, 1100.0f }; -extern ColliderCylinderInit D_8099D610; +extern AnimationHeader D_060001CC; // gCowBodyChewAnim +extern FlexSkeletonHeader D_06004010; // gCowBodySkel +extern AnimationHeader D_06004264; // gCowBodyMoveHeadAnim +extern AnimationHeader D_06004348; // gCowTailIdleAnim +extern FlexSkeletonHeader D_06004C30; // gCowTailSkel +extern AnimationHeader D_06004E98; // gCowTailSwishAnim -extern UNK_TYPE D_060001CC; -extern UNK_TYPE D_06004010; -extern UNK_TYPE D_06004348; +void EnCow_RotatePoint(Vec3f* vec, s16 angle) { + f32 x = (Math_CosS(angle) * vec->x) + (Math_SinS(angle) * vec->z); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099C290.s") + vec->z = (-Math_SinS(angle) * vec->x) + (Math_CosS(angle) * vec->z); + vec->x = x; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099C328.s") +void EnCow_SetColliderPos(EnCow* this) { + Vec3f vec; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099C41C.s") + vec.x = vec.y = 0.0f; + vec.z = 30.0f; + EnCow_RotatePoint(&vec, this->actor.shape.rot.y); + this->colliders[0].dim.pos.x = this->actor.world.pos.x + vec.x; + this->colliders[0].dim.pos.y = this->actor.world.pos.y; + this->colliders[0].dim.pos.z = this->actor.world.pos.z + vec.z; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/EnCow_Init.s") + vec.x = vec.y = 0.0f; + vec.z = -20.0f; + EnCow_RotatePoint(&vec, this->actor.shape.rot.y); + this->colliders[1].dim.pos.x = this->actor.world.pos.x + vec.x; + this->colliders[1].dim.pos.y = this->actor.world.pos.y; + this->colliders[1].dim.pos.z = this->actor.world.pos.z + vec.z; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/EnCow_Destroy.s") +void EnCow_SetTailPos(EnCow* this) { + Vec3f vec; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099C880.s") + VEC_SET(vec, 0.0f, 57.0f, -36.0f); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099CAA8.s") + EnCow_RotatePoint(&vec, this->actor.shape.rot.y); + this->actor.world.pos.x += vec.x; + this->actor.world.pos.y += vec.y; + this->actor.world.pos.z += vec.z; +} -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099CB20.s") +void EnCow_Init(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnCow* this = THIS; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099CB68.s") + ActorShape_Init(&this->actor.shape, 0.0f, func_800B3FC0, 72.0f); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099CBCC.s") + switch (EN_COW_TYPE(thisx)) { + case EN_COW_TYPE_DEFAULT: + case EN_COW_TYPE_ABDUCTED: + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_06004010, NULL, this->jointTable, this->morphTable, + COW_LIMB_MAX); + Animation_PlayLoop(&this->skelAnime, &D_060001CC); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099CC68.s") + Collider_InitAndSetCylinder(globalCtx, &this->colliders[0], &this->actor, &sCylinderInit); + Collider_InitAndSetCylinder(globalCtx, &this->colliders[1], &this->actor, &sCylinderInit); + EnCow_SetColliderPos(this); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099CCF8.s") + this->actionFunc = EnCow_Idle; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099CDA0.s") + if (!(gSaveContext.weekEventReg[22] & 1) && (CURRENT_DAY != 1) && + (EN_COW_TYPE(thisx) == EN_COW_TYPE_ABDUCTED)) { + Actor_MarkForDeath(&this->actor); + return; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099CFAC.s") + Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_EN_COW, this->actor.world.pos.x, + this->actor.world.pos.y, this->actor.world.pos.z, 0, this->actor.shape.rot.y, 0, + EN_COW_TYPE_TAIL); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/EnCow_Update.s") + this->animationTimer = Rand_ZeroFloat(1000.0f) + 40.0f; + this->animationCycle = 0; + this->actor.targetMode = 6; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099D3C0.s") + D_801BDAA4 = 0; + func_801A5080(4); + break; + case EN_COW_TYPE_TAIL: + SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_06004C30, NULL, this->jointTable, this->morphTable, + COW_LIMB_MAX); + Animation_PlayLoop(&this->skelAnime, &D_06004348); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099D4AC.s") + this->actor.update = EnCow_UpdateTail; + this->actor.draw = EnCow_DrawTail; + this->actionFunc = EnCow_DoTail; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099D4FC.s") + EnCow_SetTailPos(this); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/EnCow_Draw.s") + this->actor.flags &= ~EN_COW_FLAG_IS_TAIL; + this->animationTimer = Rand_ZeroFloat(1000.0f) + 40.0f; + break; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Cow/func_8099D59C.s") + this->actor.colChkInfo.mass = MASS_IMMOVABLE; + Actor_SetScale(&this->actor, 0.01f); + this->flags = 0; + + gSaveContext.weekEventReg[87] &= (u8)~1; +} + +void EnCow_Destroy(Actor* thisx, GlobalContext* globalCtx) { + EnCow* this = THIS; + + if (this->actor.params == EN_COW_TYPE_DEFAULT) { //! @bug EN_COW_TYPE_ABDUCTED do not destroy their cylinders + Collider_DestroyCylinder(globalCtx, &this->colliders[0]); + Collider_DestroyCylinder(globalCtx, &this->colliders[1]); + } +} + +void EnCow_UpdateAnimation(EnCow* this, GlobalContext* globalCtx) { + if (this->animationTimer > 0) { + this->animationTimer--; + } else { + this->animationTimer = Rand_ZeroFloat(500.0f) + 40.0f; + Animation_Change(&this->skelAnime, &D_060001CC, 1.0f, this->skelAnime.curFrame, + Animation_GetLastFrame(&D_060001CC), ANIMMODE_ONCE, 1.0f); + } + if (this->actor.xzDistToPlayer < 150.0f) { + if (!(this->flags & EN_COW_FLAG_PLAYER_HAS_APPROACHED)) { + this->flags |= EN_COW_FLAG_PLAYER_HAS_APPROACHED; + if (this->skelAnime.animation == &D_060001CC) { + this->animationTimer = 0; + } + } + } + this->animationCycle++; + if (this->animationCycle > 0x30) { + this->animationCycle = 0; + } + + if (this->animationCycle < 0x20) { + this->actor.scale.x = ((Math_SinS(this->animationCycle * 0x400) * (1.0f / 100.0f)) + 1.0f) * 0.01f; + } else { + this->actor.scale.x = 0.01f; + } + + if (this->animationCycle > 0x10) { + this->actor.scale.y = ((Math_SinS((this->animationCycle * 0x400) - 0x4000) * (1.0f / 100.0f)) + 1.0f) * 0.01f; + } else { + this->actor.scale.y = 0.01f; + } +} + +void EnCow_TalkEnd(EnCow* this, GlobalContext* globalCtx) { + if ((func_80152498(&globalCtx->msgCtx) == 5) && func_80147624(globalCtx)) { + this->actor.flags &= ~0x10000; + func_801477B4(globalCtx); + this->actionFunc = EnCow_Idle; + } +} + +void EnCow_GiveMilkEnd(EnCow* this, GlobalContext* globalCtx) { + if (func_800B867C(&this->actor, globalCtx)) { + this->actor.flags &= ~0x10000; + this->actionFunc = EnCow_Idle; + } +} + +void EnCow_GiveMilkWait(EnCow* this, GlobalContext* globalCtx) { + if (Actor_HasParent(&this->actor, globalCtx)) { + this->actor.parent = NULL; + this->actionFunc = EnCow_GiveMilkEnd; + } else { + func_800B8A1C(&this->actor, globalCtx, GI_MILK, 10000.0f, 100.0f); + } +} + +void EnCow_GiveMilk(EnCow* this, GlobalContext* globalCtx) { + if ((func_80152498(&globalCtx->msgCtx) == 5) && func_80147624(globalCtx)) { + this->actor.flags &= ~0x10000; + func_801477B4(globalCtx); + this->actionFunc = EnCow_GiveMilkWait; + func_800B8A1C(&this->actor, globalCtx, GI_MILK, 10000.0f, 100.0f); + } +} + +void EnCow_CheckForEmptyBottle(EnCow* this, GlobalContext* globalCtx) { + if ((func_80152498(&globalCtx->msgCtx) == 5) && func_80147624(globalCtx)) { + if (func_80114E90()) { + func_80151938(globalCtx, 0x32C9); // Text to give milk. + this->actionFunc = EnCow_GiveMilk; + } else { + func_80151938(globalCtx, 0x32CA); // Text if you don't have an empty bottle. + this->actionFunc = EnCow_TalkEnd; + } + } +} + +void EnCow_Talk(EnCow* this, GlobalContext* globalCtx) { + if (func_800B84D0(&this->actor, globalCtx)) { + if (this->actor.textId == 0x32C8) { // Text to give milk after playing Epona's Song. + this->actionFunc = EnCow_CheckForEmptyBottle; + } else if (this->actor.textId == 0x32C9) { // Text to give milk. + this->actionFunc = EnCow_GiveMilk; + } else { + this->actionFunc = EnCow_TalkEnd; + } + } else { + this->actor.flags |= 0x10000; + func_800B8614(&this->actor, globalCtx, 170.0f); + this->actor.textId = 0x32C8; //! @bug textId is reset to this no matter the intial value + } + + EnCow_UpdateAnimation(this, globalCtx); +} + +void EnCow_Idle(EnCow* this, GlobalContext* globalCtx) { + if ((globalCtx->msgCtx.unk1202A == 0) || (globalCtx->msgCtx.unk1202A == 4)) { + if (D_801BDAA4 != 0) { + if (this->flags & EN_COW_FLAG_WONT_GIVE_MILK) { + this->flags &= ~EN_COW_FLAG_WONT_GIVE_MILK; + D_801BDAA4 = 0; + } else if ((this->actor.xzDistToPlayer < 150.0f) && + ABS_ALT((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) < 25000) { + D_801BDAA4 = 0; + this->actionFunc = EnCow_Talk; + this->actor.flags |= 0x10000; + func_800B8614(&this->actor, globalCtx, 170.0f); + this->actor.textId = 0x32C8; // Text to give milk after playing Epona's Song. + + EnCow_UpdateAnimation(this, globalCtx); + return; + } else { + this->flags |= EN_COW_FLAG_WONT_GIVE_MILK; + } + } else { + this->flags &= ~EN_COW_FLAG_WONT_GIVE_MILK; + } + } + + if (this->actor.xzDistToPlayer < 150.0f && + ABS_ALT((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) < 25000) { + if (func_801A5100() == 4) { + if (!(gSaveContext.weekEventReg[87] & 1)) { + gSaveContext.weekEventReg[87] |= 1; + if (func_80114E90()) { + this->actor.textId = 0x32C9; // Text to give milk. + } else { + this->actor.textId = 0x32CA; // Text if you don't have an empty bottle. + } + this->actor.flags |= 0x10000; + func_800B8614(&this->actor, globalCtx, 170.0f); + this->actionFunc = EnCow_Talk; + } + } else { + gSaveContext.weekEventReg[87] &= (u8)~1; + } + } + + EnCow_UpdateAnimation(this, globalCtx); +} + +void EnCow_DoTail(EnCow* this, GlobalContext* globalCtx) { + if (this->animationTimer > 0) { + this->animationTimer--; + } else { + this->animationTimer = Rand_ZeroFloat(200.0f) + 40.0f; + Animation_Change(&this->skelAnime, &D_06004348, 1.0f, this->skelAnime.curFrame, + Animation_GetLastFrame(&D_06004348), ANIMMODE_ONCE, 1.0f); + } + + if (this->actor.xzDistToPlayer < 150.0f && + ABS_ALT((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) > 25000) { + if (!(this->flags & EN_COW_FLAG_PLAYER_HAS_APPROACHED)) { + this->flags |= EN_COW_FLAG_PLAYER_HAS_APPROACHED; + if (this->skelAnime.animation == &D_06004348) { + this->animationTimer = 0; + } + } + } +} + +void EnCow_Update(Actor* thisx, GlobalContext* globalCtx2) { + GlobalContext* globalCtx = globalCtx2; + EnCow* this = THIS; + s16 targetX; + s16 targetY; + Player* player = GET_PLAYER(globalCtx); + + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colliders[0].base); + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colliders[1].base); + + Actor_SetVelocityAndMoveYRotationAndGravity(&this->actor); + + Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 0.0f, 0.0f, 0.0f, 4); + + if (SkelAnime_Update(&this->skelAnime)) { + if (this->skelAnime.animation == &D_060001CC) { + Audio_PlayActorSound2(&this->actor, NA_SE_EV_COW_CRY); + Animation_Change(&this->skelAnime, &D_06004264, 1.0f, 0.0f, Animation_GetLastFrame(&D_06004264), + ANIMMODE_ONCE, 1.0f); + } else { + Animation_Change(&this->skelAnime, &D_060001CC, 1.0f, 0.0f, Animation_GetLastFrame(&D_060001CC), + ANIMMODE_LOOP, 1.0f); + } + } + + this->actionFunc(this, globalCtx); + + if (this->actor.xzDistToPlayer < 150.0f && + ABS_ALT(Math_Vec3f_Yaw(&thisx->world.pos, &player->actor.world.pos)) < 0xC000) { + targetX = Math_Vec3f_Pitch(&thisx->focus.pos, &player->actor.focus.pos); + targetY = Math_Vec3f_Yaw(&thisx->focus.pos, &player->actor.focus.pos) - this->actor.shape.rot.y; + + if (targetX > 0x1000) { + targetX = 0x1000; + } else if (targetX < -0x1000) { + targetX = -0x1000; + } + + if (targetY > 0x2500) { + targetY = 0x2500; + } else if (targetY < -0x2500) { + targetY = -0x2500; + } + } else { + targetX = targetY = 0; + } + + Math_SmoothStepToS(&this->headTilt.x, targetX, 10, 200, 10); + Math_SmoothStepToS(&this->headTilt.y, targetY, 10, 200, 10); +} + +void EnCow_UpdateTail(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + EnCow* this = THIS; + + if (SkelAnime_Update(&this->skelAnime)) { + if (this->skelAnime.animation == &D_06004348) { + Animation_Change(&this->skelAnime, &D_06004E98, 1.0f, 0.0f, Animation_GetLastFrame(&D_06004E98), + ANIMMODE_ONCE, 1.0f); + } else { + Animation_Change(&this->skelAnime, &D_06004348, 1.0f, 0.0f, Animation_GetLastFrame(&D_06004348), + ANIMMODE_LOOP, 1.0f); + } + } + + this->actionFunc(this, globalCtx); +} + +s32 EnCow_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) { + EnCow* this = THIS; + + if (limbIndex == COW_LIMB_HEAD) { + rot->y += this->headTilt.y; + rot->x += this->headTilt.x; + } + if (limbIndex == COW_LIMB_NOSE_RING) { + *dList = NULL; + } + + return false; +} + +void EnCow_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) { + EnCow* this = THIS; + + if (limbIndex == COW_LIMB_HEAD) { + Matrix_MultiplyVector3fByState(&D_8099D63C, &this->actor.focus.pos); + } +} + +void EnCow_Draw(Actor* thisx, GlobalContext* globalCtx) { + EnCow* this = THIS; + + func_8012C5B0(globalCtx->state.gfxCtx); + SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, + EnCow_OverrideLimbDraw, EnCow_PostLimbDraw, &this->actor); +} + +void EnCow_DrawTail(Actor* thisx, GlobalContext* globalCtx) { + EnCow* this = THIS; + + func_8012C5B0(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_Cow/z_en_cow.h b/src/overlays/actors/ovl_En_Cow/z_en_cow.h index ecbd3a9e11..fd865cecbe 100644 --- a/src/overlays/actors/ovl_En_Cow/z_en_cow.h +++ b/src/overlays/actors/ovl_En_Cow/z_en_cow.h @@ -3,13 +3,42 @@ #include "global.h" +#define EN_COW_TYPE(thisx) ((thisx)->params & 0xF) + +#define EN_COW_FLAG_IS_TAIL (1 << 0) // This is never set but it is cleared for tail types +#define EN_COW_FLAG_PLAYER_HAS_APPROACHED (1 << 1) +#define EN_COW_FLAG_WONT_GIVE_MILK (1 << 2) + +typedef enum { + /* 0 */ EN_COW_TYPE_DEFAULT, + /* 1 */ EN_COW_TYPE_TAIL, + /* 2 */ EN_COW_TYPE_ABDUCTED, +} EnCowType; + struct EnCow; typedef void (*EnCowActionFunc)(struct EnCow*, GlobalContext*); +typedef enum { + /* 0 */ COW_LIMB_NONE, + /* 1 */ COW_LIMB_ROOT, + /* 2 */ COW_LIMB_HEAD, + /* 3 */ COW_LIMB_JAW, + /* 4 */ COW_LIMB_NOSE, + /* 5 */ COW_LIMB_NOSE_RING, + /* 6 */ COW_LIMB_MAX, +} ObjectCowLimbs; + typedef struct EnCow { /* 0x0000 */ Actor actor; - /* 0x0144 */ char unk_144[0x130]; + /* 0x0144 */ ColliderCylinder colliders[2]; + /* 0x01DC */ SkelAnime skelAnime; + /* 0x0220 */ Vec3s jointTable[COW_LIMB_MAX]; + /* 0x0244 */ Vec3s morphTable[COW_LIMB_MAX]; + /* 0x0268 */ Vec3s headTilt; + /* 0x026E */ u16 flags; + /* 0x0270 */ u16 animationTimer; + /* 0x0272 */ u16 animationCycle; /* 0x0274 */ EnCowActionFunc actionFunc; } EnCow; // size = 0x278 diff --git a/undefined_syms.txt b/undefined_syms.txt index d544823377..47b495b847 100644 --- a/undefined_syms.txt +++ b/undefined_syms.txt @@ -4,8 +4,8 @@ D_80000000 = 0x80000000; // __osExceptionPreamble D_80000004 = 0x80000004; // __osExceptionPreamble D_80000008 = 0x80000008; // __osExceptionPreamble D_8000000C = 0x8000000C; // __osExceptionPreamble -D_80000010 = 0x80000010; // -D_80000020 = 0x80000020; // +D_80000010 = 0x80000010; // +D_80000020 = 0x80000020; // osTvType = 0x80000300; osRomType = 0x80000304;