mirror of
https://github.com/zeldaret/oot.git
synced 2024-11-28 19:25:27 +00:00
En_Cow Doc (#1492)
* Add Documentation for Cows * Better naming for cow unlock flag * Update with MM solutions and PR suggestions * Readable conditions * Decimal cycle counter * Replace params with cow type * Clean up type usage and function names * Clean up cylinders * Fix collider enum * Rename EnCow rear collider * Fix spacing * PR fixes: COLL -> COLLIDER enum static prefix Missed MM function naming Specific actor flags naming * Rename of healRot and breathTimer * Document Epona's song reset behavior * anon review * fig review * whitespace * rework milk interaction stuff * changes to milk comment --------- Co-authored-by: fig02 <fig02srl@gmail.com>
This commit is contained in:
parent
d6207b17c2
commit
fc3e0f080b
10 changed files with 206 additions and 147 deletions
|
@ -1,14 +1,14 @@
|
|||
<Root>
|
||||
<File Name="object_cow" Segment="6">
|
||||
<!-- Cow Body Skeleton -->
|
||||
<Skeleton Name="gCowBodySkel" Type="Flex" LimbType="Standard" Offset="0x4010"/>
|
||||
<Skeleton Name="gCowBodySkel" Type="Flex" LimbType="Standard" LimbNone="COW_LIMB_NONE" LimbMax="COW_LIMB_MAX" EnumName="CowLimb" Offset="0x4010"/>
|
||||
|
||||
<!-- Cow Body Limbs -->
|
||||
<Limb Name="gCowRootLimb" LimbType="Standard" Offset="0x3FC0"/>
|
||||
<Limb Name="gCowHeadLimb" LimbType="Standard" Offset="0x3FCC"/>
|
||||
<Limb Name="gCowJawLimb" LimbType="Standard" Offset="0x3FD8"/>
|
||||
<Limb Name="gCowNoseLimb" LimbType="Standard" Offset="0x3FE4"/>
|
||||
<Limb Name="gCowNoseRingLimb" LimbType="Standard" Offset="0x3FF0"/>
|
||||
<Limb Name="gCowRootLimb" LimbType="Standard" EnumName="COW_LIMB_ROOT" Offset="0x3FC0"/>
|
||||
<Limb Name="gCowHeadLimb" LimbType="Standard" EnumName="COW_LIMB_HEAD" Offset="0x3FCC"/>
|
||||
<Limb Name="gCowJawLimb" LimbType="Standard" EnumName="COW_LIMB_JAW" Offset="0x3FD8"/>
|
||||
<Limb Name="gCowNoseLimb" LimbType="Standard" EnumName="COW_LIMB_NOSE" Offset="0x3FE4"/>
|
||||
<Limb Name="gCowNoseRingLimb" LimbType="Standard" EnumName="COW_LIMB_NOSE_RING" Offset="0x3FF0"/>
|
||||
|
||||
<!-- Cow Body Limb DisplayLists -->
|
||||
<DList Name="gCowTorsoDL" Offset="0x1A80"/>
|
||||
|
@ -18,14 +18,14 @@
|
|||
<DList Name="gCowNoseRingDL" Offset="0x2628"/>
|
||||
|
||||
<!-- Cow Tail Skeleton -->
|
||||
<Skeleton Name="gCowTailSkel" Type="Flex" LimbType="Standard" Offset="0x4C30"/>
|
||||
<Skeleton Name="gCowTailSkel" Type="Flex" LimbType="Standard" LimbNone="COW_TAIL_LIMB_NONE" LimbMax="COW_TAIL_LIMB_MAX" EnumName="CowTailLimb" Offset="0x4C30"/>
|
||||
|
||||
<!-- Cow Tail Limbs -->
|
||||
<Limb Name="gCowTailRootLimb" LimbType="Standard" Offset="0x4BE0"/>
|
||||
<Limb Name="gCowTailUpperLimb" LimbType="Standard" Offset="0x4BEC"/>
|
||||
<Limb Name="gCowTailMiddleLimb" LimbType="Standard" Offset="0x4BF8"/>
|
||||
<Limb Name="gCowTailLowerLimb" LimbType="Standard" Offset="0x4C04"/>
|
||||
<Limb Name="gCowTailEndLimb" LimbType="Standard" Offset="0x4C10"/>
|
||||
<Limb Name="gCowTailRootLimb" LimbType="Standard" EnumName="COW_TAIL_LIMB_ROOT" Offset="0x4BE0"/>
|
||||
<Limb Name="gCowTailUpperLimb" LimbType="Standard" EnumName="COW_TAIL_LIMB_UPPER" Offset="0x4BEC"/>
|
||||
<Limb Name="gCowTailMiddleLimb" LimbType="Standard" EnumName="COW_TAIL_LIMB_MIDDLE" Offset="0x4BF8"/>
|
||||
<Limb Name="gCowTailLowerLimb" LimbType="Standard" EnumName="COW_TAIL_LIMB_LOWER" Offset="0x4C04"/>
|
||||
<Limb Name="gCowTailEndLimb" LimbType="Standard" EnumName="COW_TAIL_LIMB_END" Offset="0x4C10"/>
|
||||
|
||||
<!-- Cow Tail Limb DisplayLists -->
|
||||
<DList Name="gCowTailConnectionDL" Offset="0x46F0"/>
|
||||
|
|
|
@ -106,6 +106,7 @@
|
|||
#define R_MESSAGE_DEBUGGER_TEXTID YREG(79)
|
||||
#define R_C_UP_ICON_X YREG(88)
|
||||
#define R_C_UP_ICON_Y YREG(89)
|
||||
#define R_EPONAS_SONG_PLAYED DREG(53)
|
||||
#define R_MAGIC_FILL_COLOR(i) ZREG(0 + (i))
|
||||
#define R_C_BTN_COLOR(i) ZREG(39 + (i))
|
||||
#define R_B_BTN_COLOR(i) ZREG(43 + (i))
|
||||
|
|
|
@ -387,7 +387,7 @@ typedef enum {
|
|||
#define EVENTCHKINF_1B 0x1B
|
||||
#define EVENTCHKINF_1C 0x1C
|
||||
#define EVENTCHKINF_1D 0x1D
|
||||
#define EVENTCHKINF_1E 0x1E
|
||||
#define EVENTCHKINF_HORSE_RACE_COW_UNLOCK 0x1E
|
||||
#define EVENTCHKINF_20 0x20
|
||||
#define EVENTCHKINF_21 0x21
|
||||
#define EVENTCHKINF_22 0x22
|
||||
|
|
|
@ -2486,7 +2486,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) {
|
|||
} else {
|
||||
Message_CloseTextbox(play);
|
||||
if (msgCtx->lastPlayedSong == OCARINA_SONG_EPONAS) {
|
||||
DREG(53) = 1;
|
||||
R_EPONAS_SONG_PLAYED = true;
|
||||
}
|
||||
osSyncPrintf(VT_FGCOL(YELLOW));
|
||||
osSyncPrintf("☆☆☆ocarina=%d message->ocarina_no=%d ", msgCtx->lastPlayedSong,
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
#include "z_en_cow.h"
|
||||
#include "assets/objects/object_cow/object_cow.h"
|
||||
|
||||
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3)
|
||||
|
||||
|
@ -13,17 +12,19 @@ void EnCow_Init(Actor* thisx, PlayState* play);
|
|||
void EnCow_Destroy(Actor* thisx, PlayState* play);
|
||||
void EnCow_Update(Actor* thisx, PlayState* play2);
|
||||
void EnCow_Draw(Actor* thisx, PlayState* play);
|
||||
void func_809DFE98(Actor* thisx, PlayState* play);
|
||||
void func_809E0070(Actor* thisx, PlayState* play);
|
||||
|
||||
void func_809DF494(EnCow* this, PlayState* play);
|
||||
void func_809DF6BC(EnCow* this, PlayState* play);
|
||||
void func_809DF778(EnCow* this, PlayState* play);
|
||||
void func_809DF7D8(EnCow* this, PlayState* play);
|
||||
void func_809DF870(EnCow* this, PlayState* play);
|
||||
void func_809DF8FC(EnCow* this, PlayState* play);
|
||||
void func_809DF96C(EnCow* this, PlayState* play);
|
||||
void func_809DFA84(EnCow* this, PlayState* play);
|
||||
void EnCow_TalkEnd(EnCow* this, PlayState* play);
|
||||
void EnCow_GiveMilkEnd(EnCow* this, PlayState* play);
|
||||
void EnCow_GiveMilkWait(EnCow* this, PlayState* play);
|
||||
void EnCow_GiveMilk(EnCow* this, PlayState* play);
|
||||
void EnCow_CheckForEmptyBottle(EnCow* this, PlayState* play);
|
||||
void EnCow_UpdateAnimation(EnCow* this, PlayState* play);
|
||||
void EnCow_Talk(EnCow* this, PlayState* play);
|
||||
void EnCow_Idle(EnCow* this, PlayState* play);
|
||||
|
||||
void EnCow_DrawTail(Actor* thisx, PlayState* play);
|
||||
void EnCow_UpdateTail(Actor* thisx, PlayState* play);
|
||||
void EnCow_IdleTail(EnCow* this, PlayState* play);
|
||||
|
||||
ActorInit En_Cow_InitVars = {
|
||||
ACTOR_EN_COW,
|
||||
|
@ -57,45 +58,50 @@ static ColliderCylinderInit sCylinderInit = {
|
|||
{ 30, 40, 0, { 0, 0, 0 } },
|
||||
};
|
||||
|
||||
static Vec3f D_809E010C = { 0.0f, -1300.0f, 1100.0f };
|
||||
static Vec3f sHeadFocusOffset = { 0.0f, -1300.0f, 1100.0f };
|
||||
|
||||
void func_809DEE00(Vec3f* vec, s16 rotY) {
|
||||
void EnCow_RotateY(Vec3f* vec, s16 rotY) {
|
||||
f32 xCalc;
|
||||
f32 rotCalcTemp;
|
||||
|
||||
rotCalcTemp = Math_CosS(rotY);
|
||||
xCalc = (Math_SinS(rotY) * vec->z) + (rotCalcTemp * vec->x);
|
||||
rotCalcTemp = Math_SinS(rotY);
|
||||
|
||||
vec->z = (Math_CosS(rotY) * vec->z) + (-rotCalcTemp * vec->x);
|
||||
vec->x = xCalc;
|
||||
}
|
||||
|
||||
void func_809DEE9C(EnCow* this) {
|
||||
void EnCow_SetColliderPos(EnCow* this) {
|
||||
Vec3f vec;
|
||||
|
||||
vec.y = 0.0f;
|
||||
vec.x = 0.0f;
|
||||
vec.z = 30.0f;
|
||||
func_809DEE00(&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;
|
||||
|
||||
EnCow_RotateY(&vec, this->actor.shape.rot.y);
|
||||
|
||||
this->colliders[COW_COLLIDER_FRONT].dim.pos.x = this->actor.world.pos.x + vec.x;
|
||||
this->colliders[COW_COLLIDER_FRONT].dim.pos.y = this->actor.world.pos.y;
|
||||
this->colliders[COW_COLLIDER_FRONT].dim.pos.z = this->actor.world.pos.z + vec.z;
|
||||
|
||||
vec.x = 0.0f;
|
||||
vec.y = 0.0f;
|
||||
vec.z = -20.0f;
|
||||
func_809DEE00(&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;
|
||||
|
||||
EnCow_RotateY(&vec, this->actor.shape.rot.y);
|
||||
|
||||
this->colliders[COW_COLLIDER_REAR].dim.pos.x = this->actor.world.pos.x + vec.x;
|
||||
this->colliders[COW_COLLIDER_REAR].dim.pos.y = this->actor.world.pos.y;
|
||||
this->colliders[COW_COLLIDER_REAR].dim.pos.z = this->actor.world.pos.z + vec.z;
|
||||
}
|
||||
|
||||
void func_809DEF94(EnCow* this) {
|
||||
void EnCow_SetTailPos(EnCow* this) {
|
||||
Vec3f vec;
|
||||
|
||||
VEC_SET(vec, 0.0f, 57.0f, -36.0f);
|
||||
EnCow_RotateY(&vec, this->actor.shape.rot.y);
|
||||
|
||||
func_809DEE00(&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;
|
||||
|
@ -106,188 +112,216 @@ void EnCow_Init(Actor* thisx, PlayState* play) {
|
|||
s32 pad;
|
||||
|
||||
ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 72.0f);
|
||||
switch (this->actor.params) {
|
||||
case 0:
|
||||
SkelAnime_InitFlex(play, &this->skelAnime, &gCowBodySkel, NULL, this->jointTable, this->morphTable, 6);
|
||||
|
||||
switch (COW_GET_TYPE(this)) {
|
||||
case COW_TYPE_BODY:
|
||||
SkelAnime_InitFlex(play, &this->skelAnime, &gCowBodySkel, NULL, this->jointTable, this->morphTable,
|
||||
COW_LIMB_MAX);
|
||||
Animation_PlayLoop(&this->skelAnime, &gCowBodyChewAnim);
|
||||
Collider_InitCylinder(play, &this->colliders[0]);
|
||||
Collider_SetCylinder(play, &this->colliders[0], &this->actor, &sCylinderInit);
|
||||
Collider_InitCylinder(play, &this->colliders[1]);
|
||||
Collider_SetCylinder(play, &this->colliders[1], &this->actor, &sCylinderInit);
|
||||
func_809DEE9C(this);
|
||||
this->actionFunc = func_809DF96C;
|
||||
|
||||
Collider_InitCylinder(play, &this->colliders[COW_COLLIDER_FRONT]);
|
||||
Collider_SetCylinder(play, &this->colliders[COW_COLLIDER_FRONT], &this->actor, &sCylinderInit);
|
||||
|
||||
Collider_InitCylinder(play, &this->colliders[COW_COLLIDER_REAR]);
|
||||
Collider_SetCylinder(play, &this->colliders[COW_COLLIDER_REAR], &this->actor, &sCylinderInit);
|
||||
|
||||
EnCow_SetColliderPos(this);
|
||||
|
||||
this->actionFunc = EnCow_Idle;
|
||||
|
||||
if (play->sceneId == SCENE_LINKS_HOUSE) {
|
||||
if (!LINK_IS_ADULT) {
|
||||
Actor_Kill(&this->actor);
|
||||
return;
|
||||
}
|
||||
if (!GET_EVENTCHKINF(EVENTCHKINF_1E)) {
|
||||
|
||||
if (!GET_EVENTCHKINF(EVENTCHKINF_HORSE_RACE_COW_UNLOCK)) {
|
||||
Actor_Kill(&this->actor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, 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, 1);
|
||||
this->unk_278 = Rand_ZeroFloat(1000.0f) + 40.0f;
|
||||
this->unk_27A = 0;
|
||||
this->actor.world.pos.y, this->actor.world.pos.z, 0, this->actor.shape.rot.y, 0,
|
||||
COW_TYPE_TAIL);
|
||||
this->animationTimer = Rand_ZeroFloat(1000.0f) + 40.0f;
|
||||
this->breathTimer = 0;
|
||||
this->actor.targetMode = 6;
|
||||
DREG(53) = 0;
|
||||
R_EPONAS_SONG_PLAYED = false;
|
||||
break;
|
||||
case 1:
|
||||
SkelAnime_InitFlex(play, &this->skelAnime, &gCowTailSkel, NULL, this->jointTable, this->morphTable, 6);
|
||||
|
||||
case COW_TYPE_TAIL:
|
||||
SkelAnime_InitFlex(play, &this->skelAnime, &gCowTailSkel, NULL, this->jointTable, this->morphTable,
|
||||
COW_TAIL_LIMB_MAX);
|
||||
Animation_PlayLoop(&this->skelAnime, &gCowTailIdleAnim);
|
||||
this->actor.update = func_809DFE98;
|
||||
this->actor.draw = func_809E0070;
|
||||
this->actionFunc = func_809DFA84;
|
||||
func_809DEF94(this);
|
||||
this->actor.update = EnCow_UpdateTail;
|
||||
this->actor.draw = EnCow_DrawTail;
|
||||
this->actionFunc = EnCow_IdleTail;
|
||||
EnCow_SetTailPos(this);
|
||||
this->actor.flags &= ~ACTOR_FLAG_0;
|
||||
this->unk_278 = ((u32)(Rand_ZeroFloat(1000.0f)) & 0xFFFF) + 40.0f;
|
||||
this->animationTimer = (u16)Rand_ZeroFloat(1000.0f) + 40.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
this->actor.colChkInfo.mass = MASS_IMMOVABLE;
|
||||
Actor_SetScale(&this->actor, 0.01f);
|
||||
this->unk_276 = 0;
|
||||
this->cowFlags = 0;
|
||||
}
|
||||
|
||||
void EnCow_Destroy(Actor* thisx, PlayState* play) {
|
||||
EnCow* this = (EnCow*)thisx;
|
||||
|
||||
if (this->actor.params == 0) {
|
||||
Collider_DestroyCylinder(play, &this->colliders[0]);
|
||||
Collider_DestroyCylinder(play, &this->colliders[1]);
|
||||
if (COW_GET_TYPE(this) == COW_TYPE_BODY) {
|
||||
Collider_DestroyCylinder(play, &this->colliders[COW_COLLIDER_FRONT]);
|
||||
Collider_DestroyCylinder(play, &this->colliders[COW_COLLIDER_REAR]);
|
||||
}
|
||||
}
|
||||
|
||||
void func_809DF494(EnCow* this, PlayState* play) {
|
||||
if (this->unk_278 > 0) {
|
||||
this->unk_278--;
|
||||
void EnCow_UpdateAnimation(EnCow* this, PlayState* play) {
|
||||
if (this->animationTimer > 0) {
|
||||
this->animationTimer--;
|
||||
} else {
|
||||
this->unk_278 = Rand_ZeroFloat(500.0f) + 40.0f;
|
||||
this->animationTimer = Rand_ZeroFloat(500.0f) + 40.0f;
|
||||
Animation_Change(&this->skelAnime, &gCowBodyChewAnim, 1.0f, this->skelAnime.curFrame,
|
||||
Animation_GetLastFrame(&gCowBodyChewAnim), ANIMMODE_ONCE, 1.0f);
|
||||
}
|
||||
|
||||
if ((this->actor.xzDistToPlayer < 150.0f) && !(this->unk_276 & 2)) {
|
||||
this->unk_276 |= 2;
|
||||
if (this->actor.xzDistToPlayer < 150.0f) {
|
||||
if (!(this->cowFlags & COW_FLAG_PLAYER_NEARBY)) {
|
||||
this->cowFlags |= COW_FLAG_PLAYER_NEARBY;
|
||||
|
||||
if (this->skelAnime.animation == &gCowBodyChewAnim) {
|
||||
this->unk_278 = 0;
|
||||
this->animationTimer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->unk_27A++;
|
||||
if (this->unk_27A > 48) {
|
||||
this->unk_27A = 0;
|
||||
this->breathTimer++;
|
||||
|
||||
if (this->breathTimer > 48) {
|
||||
this->breathTimer = 0;
|
||||
}
|
||||
|
||||
// (1.0f / 100.0f) instead of 0.01f below is necessary so 0.01f doesn't get reused mistakenly
|
||||
if (this->unk_27A < 0x20) {
|
||||
this->actor.scale.x = ((Math_SinS(this->unk_27A << 0xA) * (1.0f / 100.0f)) + 1.0f) * 0.01f;
|
||||
if (this->breathTimer < 32) {
|
||||
this->actor.scale.x = ((Math_SinS(this->breathTimer * 0x0400) * (1.0f / 100.0f)) + 1.0f) * 0.01f;
|
||||
} else {
|
||||
this->actor.scale.x = 0.01f;
|
||||
}
|
||||
|
||||
if (this->unk_27A >= 0x11) {
|
||||
this->actor.scale.y = ((Math_SinS((this->unk_27A << 0xA) - 0x4000) * (1.0f / 100.0f)) + 1.0f) * 0.01f;
|
||||
if (this->breathTimer > 16) {
|
||||
this->actor.scale.y = ((Math_SinS((this->breathTimer * 0x0400) - 0x4000) * (1.0f / 100.0f)) + 1.0f) * 0.01f;
|
||||
} else {
|
||||
this->actor.scale.y = 0.01f;
|
||||
}
|
||||
}
|
||||
|
||||
void func_809DF6BC(EnCow* this, PlayState* play) {
|
||||
void EnCow_TalkEnd(EnCow* this, PlayState* play) {
|
||||
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_EVENT) && Message_ShouldAdvance(play)) {
|
||||
this->actor.flags &= ~ACTOR_FLAG_16;
|
||||
Message_CloseTextbox(play);
|
||||
this->actionFunc = func_809DF96C;
|
||||
this->actionFunc = EnCow_Idle;
|
||||
}
|
||||
}
|
||||
|
||||
void func_809DF730(EnCow* this, PlayState* play) {
|
||||
void EnCow_GiveMilkEnd(EnCow* this, PlayState* play) {
|
||||
if (Actor_TextboxIsClosing(&this->actor, play)) {
|
||||
this->actor.flags &= ~ACTOR_FLAG_16;
|
||||
this->actionFunc = func_809DF96C;
|
||||
this->actionFunc = EnCow_Idle;
|
||||
}
|
||||
}
|
||||
|
||||
void func_809DF778(EnCow* this, PlayState* play) {
|
||||
void EnCow_GiveMilkWait(EnCow* this, PlayState* play) {
|
||||
if (Actor_HasParent(&this->actor, play)) {
|
||||
this->actor.parent = NULL;
|
||||
this->actionFunc = func_809DF730;
|
||||
this->actionFunc = EnCow_GiveMilkEnd;
|
||||
} else {
|
||||
Actor_OfferGetItem(&this->actor, play, GI_MILK, 10000.0f, 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void func_809DF7D8(EnCow* this, PlayState* play) {
|
||||
void EnCow_GiveMilk(EnCow* this, PlayState* play) {
|
||||
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_EVENT) && Message_ShouldAdvance(play)) {
|
||||
this->actor.flags &= ~ACTOR_FLAG_16;
|
||||
Message_CloseTextbox(play);
|
||||
this->actionFunc = func_809DF778;
|
||||
this->actionFunc = EnCow_GiveMilkWait;
|
||||
Actor_OfferGetItem(&this->actor, play, GI_MILK, 10000.0f, 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void func_809DF870(EnCow* this, PlayState* play) {
|
||||
void EnCow_CheckForEmptyBottle(EnCow* this, PlayState* play) {
|
||||
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_EVENT) && Message_ShouldAdvance(play)) {
|
||||
if (Inventory_HasEmptyBottle()) {
|
||||
Message_ContinueTextbox(play, 0x2007);
|
||||
this->actionFunc = func_809DF7D8;
|
||||
this->actionFunc = EnCow_GiveMilk;
|
||||
} else {
|
||||
Message_ContinueTextbox(play, 0x2013);
|
||||
this->actionFunc = func_809DF6BC;
|
||||
this->actionFunc = EnCow_TalkEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void func_809DF8FC(EnCow* this, PlayState* play) {
|
||||
void EnCow_Talk(EnCow* this, PlayState* play) {
|
||||
if (Actor_ProcessTalkRequest(&this->actor, play)) {
|
||||
this->actionFunc = func_809DF870;
|
||||
this->actionFunc = EnCow_CheckForEmptyBottle;
|
||||
} else {
|
||||
this->actor.flags |= ACTOR_FLAG_16;
|
||||
func_8002F2CC(&this->actor, play, 170.0f);
|
||||
this->actor.textId = 0x2006;
|
||||
}
|
||||
func_809DF494(this, play);
|
||||
|
||||
EnCow_UpdateAnimation(this, play);
|
||||
}
|
||||
|
||||
void func_809DF96C(EnCow* this, PlayState* play) {
|
||||
void EnCow_Idle(EnCow* this, PlayState* play) {
|
||||
if ((play->msgCtx.ocarinaMode == OCARINA_MODE_00) || (play->msgCtx.ocarinaMode == OCARINA_MODE_04)) {
|
||||
if (DREG(53) != 0) {
|
||||
if (this->unk_276 & 4) {
|
||||
this->unk_276 &= ~0x4;
|
||||
DREG(53) = 0;
|
||||
// There is a complex interaction between `R_EPONAS_SONG_PLAYED` and `COW_FLAG_FAILED_TO_GIVE_MILK` to allow
|
||||
// multiple cows to try and give milk on the same frame.
|
||||
// `COW_FLAG_FAILED_TO_GIVE_MILK` gets set if this cow is not in range with the player to interact.
|
||||
// In the case of a failure, `R_EPONAS_SONG_PLAYED` is not set to false in case another cow can succeed.
|
||||
// On the following frame, if both `R_EPONAS_SONG_PLAYED` and `COW_FLAG_FAILED_TO_GIVE_MILK` are set, the
|
||||
// first cow that updates can assume all other cows also failed and can safely unset `R_EPONAS_SONG_PLAYED`.
|
||||
// All cows also unset their own `COW_FLAG_FAILED_TO_GIVE_MILK` flag.
|
||||
if (R_EPONAS_SONG_PLAYED) {
|
||||
if (this->cowFlags & COW_FLAG_FAILED_TO_GIVE_MILK) {
|
||||
this->cowFlags &= ~COW_FLAG_FAILED_TO_GIVE_MILK;
|
||||
R_EPONAS_SONG_PLAYED = false;
|
||||
} else {
|
||||
if ((this->actor.xzDistToPlayer < 150.0f) &&
|
||||
(ABS((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) < 0x61A8)) {
|
||||
DREG(53) = 0;
|
||||
this->actionFunc = func_809DF8FC;
|
||||
(ABS((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) < 25000)) {
|
||||
R_EPONAS_SONG_PLAYED = false;
|
||||
this->actionFunc = EnCow_Talk;
|
||||
this->actor.flags |= ACTOR_FLAG_16;
|
||||
func_8002F2CC(&this->actor, play, 170.0f);
|
||||
this->actor.textId = 0x2006;
|
||||
} else {
|
||||
this->unk_276 |= 4;
|
||||
this->cowFlags |= COW_FLAG_FAILED_TO_GIVE_MILK;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->unk_276 &= ~0x4;
|
||||
this->cowFlags &= ~COW_FLAG_FAILED_TO_GIVE_MILK;
|
||||
}
|
||||
}
|
||||
func_809DF494(this, play);
|
||||
|
||||
EnCow_UpdateAnimation(this, play);
|
||||
}
|
||||
|
||||
void func_809DFA84(EnCow* this, PlayState* play) {
|
||||
if (this->unk_278 > 0) {
|
||||
this->unk_278--;
|
||||
void EnCow_IdleTail(EnCow* this, PlayState* play) {
|
||||
if (this->animationTimer > 0) {
|
||||
this->animationTimer--;
|
||||
} else {
|
||||
this->unk_278 = Rand_ZeroFloat(200.0f) + 40.0f;
|
||||
this->animationTimer = Rand_ZeroFloat(200.0f) + 40.0f;
|
||||
Animation_Change(&this->skelAnime, &gCowTailIdleAnim, 1.0f, this->skelAnime.curFrame,
|
||||
Animation_GetLastFrame(&gCowTailIdleAnim), ANIMMODE_ONCE, 1.0f);
|
||||
}
|
||||
|
||||
if ((this->actor.xzDistToPlayer < 150.0f) &&
|
||||
(ABS((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) >= 0x61A9) && !(this->unk_276 & 2)) {
|
||||
this->unk_276 |= 2;
|
||||
(ABS((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)) > 25000)) {
|
||||
if (!(this->cowFlags & COW_FLAG_PLAYER_NEARBY)) {
|
||||
this->cowFlags |= COW_FLAG_PLAYER_NEARBY;
|
||||
|
||||
if (this->skelAnime.animation == &gCowTailIdleAnim) {
|
||||
this->unk_278 = 0;
|
||||
this->animationTimer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -299,10 +333,12 @@ void EnCow_Update(Actor* thisx, PlayState* play2) {
|
|||
s16 targetY;
|
||||
Player* player = GET_PLAYER(play);
|
||||
|
||||
CollisionCheck_SetOC(play, &play->colChkCtx, &this->colliders[0].base);
|
||||
CollisionCheck_SetOC(play, &play->colChkCtx, &this->colliders[1].base);
|
||||
CollisionCheck_SetOC(play, &play->colChkCtx, &this->colliders[COW_COLLIDER_FRONT].base);
|
||||
CollisionCheck_SetOC(play, &play->colChkCtx, &this->colliders[COW_COLLIDER_REAR].base);
|
||||
|
||||
Actor_MoveXZGravity(thisx);
|
||||
Actor_UpdateBgCheckInfo(play, thisx, 0.0f, 0.0f, 0.0f, UPDBGCHECKINFO_FLAG_2);
|
||||
|
||||
if (SkelAnime_Update(&this->skelAnime)) {
|
||||
if (this->skelAnime.animation == &gCowBodyChewAnim) {
|
||||
Actor_PlaySfx(thisx, NA_SE_EV_COW_CRY);
|
||||
|
@ -313,7 +349,9 @@ void EnCow_Update(Actor* thisx, PlayState* play2) {
|
|||
ANIMMODE_LOOP, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
this->actionFunc(this, play);
|
||||
|
||||
if ((thisx->xzDistToPlayer < 150.0f) &&
|
||||
(ABS(Math_Vec3f_Yaw(&thisx->world.pos, &player->actor.world.pos)) < 0xC000)) {
|
||||
targetX = Math_Vec3f_Pitch(&thisx->focus.pos, &player->actor.focus.pos);
|
||||
|
@ -330,16 +368,16 @@ void EnCow_Update(Actor* thisx, PlayState* play2) {
|
|||
} else if (targetY < -0x2500) {
|
||||
targetY = -0x2500;
|
||||
}
|
||||
|
||||
} else {
|
||||
targetY = 0;
|
||||
targetX = 0;
|
||||
}
|
||||
Math_SmoothStepToS(&this->someRot.x, targetX, 0xA, 0xC8, 0xA);
|
||||
Math_SmoothStepToS(&this->someRot.y, targetY, 0xA, 0xC8, 0xA);
|
||||
|
||||
Math_SmoothStepToS(&this->headRot.x, targetX, 10, 200, 10);
|
||||
Math_SmoothStepToS(&this->headRot.y, targetY, 10, 200, 10);
|
||||
}
|
||||
|
||||
void func_809DFE98(Actor* thisx, PlayState* play) {
|
||||
void EnCow_UpdateTail(Actor* thisx, PlayState* play) {
|
||||
EnCow* this = (EnCow*)thisx;
|
||||
s32 pad;
|
||||
|
||||
|
@ -352,27 +390,30 @@ void func_809DFE98(Actor* thisx, PlayState* play) {
|
|||
ANIMMODE_LOOP, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
this->actionFunc(this, play);
|
||||
}
|
||||
|
||||
s32 EnCow_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx) {
|
||||
EnCow* this = (EnCow*)thisx;
|
||||
|
||||
if (limbIndex == 2) {
|
||||
rot->y += this->someRot.y;
|
||||
rot->x += this->someRot.x;
|
||||
if (limbIndex == COW_LIMB_HEAD) {
|
||||
rot->y += this->headRot.y;
|
||||
rot->x += this->headRot.x;
|
||||
}
|
||||
if (limbIndex == 5) {
|
||||
|
||||
if (limbIndex == COW_LIMB_NOSE_RING) {
|
||||
*dList = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void EnCow_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
|
||||
EnCow* this = (EnCow*)thisx;
|
||||
|
||||
if (limbIndex == 2) {
|
||||
Matrix_MultVec3f(&D_809E010C, &this->actor.focus.pos);
|
||||
if (limbIndex == COW_LIMB_HEAD) {
|
||||
Matrix_MultVec3f(&sHeadFocusOffset, &this->actor.focus.pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,7 +425,7 @@ void EnCow_Draw(Actor* thisx, PlayState* play) {
|
|||
EnCow_OverrideLimbDraw, EnCow_PostLimbDraw, this);
|
||||
}
|
||||
|
||||
void func_809E0070(Actor* thisx, PlayState* play) {
|
||||
void EnCow_DrawTail(Actor* thisx, PlayState* play) {
|
||||
EnCow* this = (EnCow*)thisx;
|
||||
|
||||
Gfx_SetupDL_37Opa(play->state.gfxCtx);
|
||||
|
|
|
@ -3,6 +3,23 @@
|
|||
|
||||
#include "ultra64.h"
|
||||
#include "global.h"
|
||||
#include "assets/objects/object_cow/object_cow.h"
|
||||
|
||||
#define COW_FLAG_PLAYER_NEARBY (1 << 1)
|
||||
#define COW_FLAG_FAILED_TO_GIVE_MILK (1 << 2)
|
||||
|
||||
#define COW_GET_TYPE(thisx) ((thisx)->actor.params)
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ COW_TYPE_BODY,
|
||||
/* 1 */ COW_TYPE_TAIL
|
||||
} CowType;
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ COW_COLLIDER_FRONT,
|
||||
/* 1 */ COW_COLLIDER_REAR,
|
||||
/* 2 */ COW_COLLIDER_MAX
|
||||
} CowCollider;
|
||||
|
||||
struct EnCow;
|
||||
|
||||
|
@ -10,14 +27,14 @@ typedef void (*EnCowActionFunc)(struct EnCow*, PlayState*);
|
|||
|
||||
typedef struct EnCow {
|
||||
/* 0x0000 */ Actor actor;
|
||||
/* 0x014C */ ColliderCylinder colliders[2];
|
||||
/* 0x014C */ ColliderCylinder colliders[COW_COLLIDER_MAX];
|
||||
/* 0x01E4 */ SkelAnime skelAnime;
|
||||
/* 0x0228 */ Vec3s jointTable[6];
|
||||
/* 0x024C */ Vec3s morphTable[6];
|
||||
/* 0x0270 */ Vec3s someRot;
|
||||
/* 0x0276 */ u16 unk_276;
|
||||
/* 0x0278 */ u16 unk_278;
|
||||
/* 0x027A */ u16 unk_27A;
|
||||
/* 0x0228 */ Vec3s jointTable[COW_LIMB_MAX];
|
||||
/* 0x024C */ Vec3s morphTable[COW_LIMB_MAX];
|
||||
/* 0x0270 */ Vec3s headRot;
|
||||
/* 0x0276 */ u16 cowFlags;
|
||||
/* 0x0278 */ u16 animationTimer;
|
||||
/* 0x027A */ u16 breathTimer;
|
||||
/* 0x027C */ EnCowActionFunc actionFunc;
|
||||
} EnCow; // size = 0x0280
|
||||
|
||||
|
|
|
@ -743,7 +743,7 @@ void EnHorse_Init(Actor* thisx, PlayState* play2) {
|
|||
AREG(6) = 0;
|
||||
Actor_ProcessInitChain(&this->actor, sInitChain);
|
||||
EnHorse_ClearDustFlags(&this->dustFlags);
|
||||
DREG(53) = 0;
|
||||
R_EPONAS_SONG_PLAYED = false;
|
||||
this->riderPos = this->actor.world.pos;
|
||||
this->noInputTimer = 0;
|
||||
this->noInputTimerMax = 0;
|
||||
|
@ -1735,8 +1735,8 @@ void EnHorse_SetFollowAnimation(EnHorse* this, PlayState* play);
|
|||
void EnHorse_Inactive(EnHorse* this, PlayState* play2) {
|
||||
PlayState* play = play2;
|
||||
|
||||
if (DREG(53) != 0 && this->type == HORSE_EPONA) {
|
||||
DREG(53) = 0;
|
||||
if (R_EPONAS_SONG_PLAYED && this->type == HORSE_EPONA) {
|
||||
R_EPONAS_SONG_PLAYED = false;
|
||||
if (EnHorse_Spawn(this, play) != 0) {
|
||||
Audio_PlaySfxGeneral(NA_SE_EV_HORSE_NEIGH, &this->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
|
||||
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
|
||||
|
@ -1810,8 +1810,8 @@ void EnHorse_Idle(EnHorse* this, PlayState* play) {
|
|||
this->actor.speed = 0.0f;
|
||||
EnHorse_IdleAnimSounds(this, play);
|
||||
|
||||
if (DREG(53) && this->type == HORSE_EPONA) {
|
||||
DREG(53) = 0;
|
||||
if (R_EPONAS_SONG_PLAYED && this->type == HORSE_EPONA) {
|
||||
R_EPONAS_SONG_PLAYED = false;
|
||||
if (!func_80A5BBBC(play, this, &this->actor.world.pos)) {
|
||||
if (EnHorse_Spawn(this, play)) {
|
||||
Audio_PlaySfxGeneral(NA_SE_EV_HORSE_NEIGH, &this->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
|
||||
|
@ -1905,7 +1905,7 @@ void EnHorse_FollowPlayer(EnHorse* this, PlayState* play) {
|
|||
f32 distToPlayer;
|
||||
f32 angleDiff;
|
||||
|
||||
DREG(53) = 0;
|
||||
R_EPONAS_SONG_PLAYED = false;
|
||||
distToPlayer = Actor_WorldDistXZToActor(&this->actor, &GET_PLAYER(play)->actor);
|
||||
|
||||
// First rotate if the player is behind
|
||||
|
@ -2597,7 +2597,7 @@ void EnHorse_FleePlayer(EnHorse* this, PlayState* play) {
|
|||
s32 animFinished;
|
||||
s16 yaw;
|
||||
|
||||
if (DREG(53) || this->type == HORSE_HNI) {
|
||||
if (R_EPONAS_SONG_PLAYED || this->type == HORSE_HNI) {
|
||||
EnHorse_StartIdleRidable(this);
|
||||
Audio_PlaySfxGeneral(NA_SE_EV_HORSE_NEIGH, &this->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
|
||||
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
|
||||
|
|
|
@ -358,7 +358,7 @@ void func_80A6A068(EnHorseLinkChild* this, PlayState* play) {
|
|||
return;
|
||||
}
|
||||
|
||||
if ((GET_EVENTCHKINF(EVENTCHKINF_16) && (DREG(53) != 0)) ||
|
||||
if ((GET_EVENTCHKINF(EVENTCHKINF_16) && R_EPONAS_SONG_PLAYED) ||
|
||||
((play->sceneId == SCENE_LON_LON_RANCH) && (gSaveContext.save.cutsceneIndex == 0xFFF1))) {
|
||||
func_80A6A4DC(this);
|
||||
} else {
|
||||
|
@ -434,7 +434,7 @@ void func_80A6A068(EnHorseLinkChild* this, PlayState* play) {
|
|||
void func_80A6A4DC(EnHorseLinkChild* this) {
|
||||
this->action = 5;
|
||||
this->animationIdx = Rand_ZeroOne() > 0.5f ? 0 : 1;
|
||||
DREG(53) = 0;
|
||||
R_EPONAS_SONG_PLAYED = false;
|
||||
Animation_Change(&this->skin.skelAnime, sAnimations[this->animationIdx], func_80A695A4(this), 0.0f,
|
||||
Animation_GetLastFrame(sAnimations[this->animationIdx]), ANIMMODE_ONCE, 0.0f);
|
||||
}
|
||||
|
@ -442,8 +442,8 @@ void func_80A6A4DC(EnHorseLinkChild* this) {
|
|||
void func_80A6A5A4(EnHorseLinkChild* this, PlayState* play) {
|
||||
s16 yawDiff;
|
||||
|
||||
if (DREG(53) != 0) {
|
||||
DREG(53) = 0;
|
||||
if (R_EPONAS_SONG_PLAYED) {
|
||||
R_EPONAS_SONG_PLAYED = false;
|
||||
Audio_PlaySfxGeneral(NA_SE_EV_KID_HORSE_NEIGH, &this->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
|
||||
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
|
||||
func_80A6A724(this);
|
||||
|
|
|
@ -87,7 +87,7 @@ u16 EnMa3_GetTextId(PlayState* play, Actor* thisx) {
|
|||
HIGH_SCORE(HS_HORSE_RACE) = 180;
|
||||
}
|
||||
|
||||
if (!GET_EVENTCHKINF(EVENTCHKINF_1E) && (((void)0, gSaveContext.timerSeconds) < 50)) {
|
||||
if (!GET_EVENTCHKINF(EVENTCHKINF_HORSE_RACE_COW_UNLOCK) && (((void)0, gSaveContext.timerSeconds) < 50)) {
|
||||
return 0x208F;
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ s16 EnMa3_UpdateTalkState(PlayState* play, Actor* thisx) {
|
|||
if (Message_ShouldAdvance(play)) {
|
||||
SET_INFTABLE(INFTABLE_B9);
|
||||
if (play->msgCtx.choiceIndex == 0) {
|
||||
if (GET_EVENTCHKINF(EVENTCHKINF_1E)) {
|
||||
if (GET_EVENTCHKINF(EVENTCHKINF_HORSE_RACE_COW_UNLOCK)) {
|
||||
Message_ContinueTextbox(play, 0x2091);
|
||||
} else if (HIGH_SCORE(HS_HORSE_RACE) == 0) {
|
||||
Message_ContinueTextbox(play, 0x2092);
|
||||
|
@ -145,7 +145,7 @@ s16 EnMa3_UpdateTalkState(PlayState* play, Actor* thisx) {
|
|||
talkState = NPC_TALK_STATE_IDLE;
|
||||
break;
|
||||
case 0x208F:
|
||||
SET_EVENTCHKINF(EVENTCHKINF_1E);
|
||||
SET_EVENTCHKINF(EVENTCHKINF_HORSE_RACE_COW_UNLOCK);
|
||||
FALLTHROUGH;
|
||||
case 0x2004:
|
||||
case 0x2012:
|
||||
|
|
|
@ -229,7 +229,7 @@ void EnNiw_Init(Actor* thisx, PlayState* play) {
|
|||
case 0xD:
|
||||
case 0xE:
|
||||
Collider_SetCylinder(play, &this->collider, &this->actor, &sCylinderInit2);
|
||||
if (play->sceneId == SCENE_LINKS_HOUSE && !GET_EVENTCHKINF(EVENTCHKINF_1E)) {
|
||||
if (play->sceneId == SCENE_LINKS_HOUSE && !GET_EVENTCHKINF(EVENTCHKINF_HORSE_RACE_COW_UNLOCK)) {
|
||||
Actor_Kill(&this->actor);
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue