diff --git a/assets/xml/objects/object_um.xml b/assets/xml/objects/object_um.xml
index 5717124a7c..aa979bf754 100644
--- a/assets/xml/objects/object_um.xml
+++ b/assets/xml/objects/object_um.xml
@@ -10,26 +10,31 @@
-
+
+
+
-
+
-
+
+
+
+
@@ -49,31 +54,35 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -85,7 +94,19 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -100,6 +121,6 @@
-
+
diff --git a/include/functions.h b/include/functions.h
index 120af69306..a72b6da7d8 100644
--- a/include/functions.h
+++ b/include/functions.h
@@ -130,6 +130,7 @@ u32 StackCheck_Check(StackEntry* entry);
void MtxConv_F2L(Mtx* m1, MtxF* m2);
void MtxConv_L2F(MtxF* m1, Mtx* m2);
+
void __assert(const char* file, u32 lineNum);
// void func_800862B4(void);
void* SystemArena_MallocMin1(u32 size);
diff --git a/spec b/spec
index 209727c3d7..45aa1aec4d 100644
--- a/spec
+++ b/spec
@@ -4064,8 +4064,7 @@ beginseg
name "ovl_Obj_Um"
compress
include "build/src/overlays/actors/ovl_Obj_Um/z_obj_um.o"
- include "build/data/ovl_Obj_Um/ovl_Obj_Um.data.o"
- include "build/data/ovl_Obj_Um/ovl_Obj_Um.reloc.o"
+ include "build/src/overlays/actors/ovl_Obj_Um/ovl_Obj_Um_reloc.o"
endseg
beginseg
diff --git a/src/overlays/actors/ovl_En_Horse/z_en_horse.c b/src/overlays/actors/ovl_En_Horse/z_en_horse.c
index 0e63d87c1c..1922a2f4bb 100644
--- a/src/overlays/actors/ovl_En_Horse/z_en_horse.c
+++ b/src/overlays/actors/ovl_En_Horse/z_en_horse.c
@@ -6,6 +6,8 @@
#include "z_en_horse.h"
#include "z64rumble.h"
+#include "overlays/actors/ovl_En_In/z_en_in.h"
+#include "overlays/actors/ovl_Obj_Um/z_obj_um.h"
#include "overlays/actors/ovl_En_Horse_Game_Check/z_en_horse_game_check.h"
#include "objects/object_horse_link_child/object_horse_link_child.h"
@@ -122,7 +124,9 @@ static AnimationHeader** sAnimationHeaders[] = {
NULL, NULL, sEponaAnimHeaders, sHniAnimHeaders, sHniAnimHeaders,
};
-static f32 sPlaybackSpeeds[] = { 2.0f / 3.0f, 2.0f / 3.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f / 3.0f, 2.0f / 3.0f };
+static f32 sPlaybackSpeeds[] = {
+ 2.0f / 3.0f, 2.0f / 3.0f, 3.0f / 3.0f, 3.0f / 3.0f, 3.0f / 3.0f, 3.0f / 3.0f, 3.0f / 3.0f, 2.0f / 3.0f, 2.0f / 3.0f,
+};
static SkeletonHeader* sSkeletonHeaders[] = {
NULL, NULL, &object_horse_link_child_Skel_00A480, NULL, NULL,
@@ -468,7 +472,7 @@ void EnHorse_PlayWalkingSound(EnHorse* this) {
return;
}
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_WALK);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_WALK);
@@ -482,7 +486,7 @@ void EnHorse_PlayWalkingSound(EnHorse* this) {
}
void func_8087C178(EnHorse* this) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
@@ -490,7 +494,7 @@ void func_8087C178(EnHorse* this) {
}
void func_8087C1C0(EnHorse* this) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
@@ -546,19 +550,19 @@ s32 func_8087C38C(PlayState* play, EnHorse* this, Vec3f* arg2) {
void EnHorse_IdleAnimSounds(EnHorse* this, PlayState* play) {
if ((this->animationIdx == ENHORSE_ANIM_IDLE) &&
- (((this->curFrame > 35.0f) && (this->type == HORSE_EPONA)) ||
- ((this->curFrame > 28.0f) && (this->type == HORSE_HNI)) ||
- ((this->curFrame > 25.0f) && (this->type == HORSE_2))) &&
+ (((this->curFrame > 35.0f) && (this->type == HORSE_TYPE_EPONA)) ||
+ ((this->curFrame > 28.0f) && (this->type == HORSE_TYPE_HNI)) ||
+ ((this->curFrame > 25.0f) && (this->type == HORSE_TYPE_2))) &&
!(this->stateFlags & ENHORSE_SANDDUST_SOUND)) {
this->stateFlags |= ENHORSE_SANDDUST_SOUND;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
}
} else if ((this->animationIdx == 3) && (this->curFrame > 25.0f) && !(this->stateFlags & ENHORSE_LAND2_SOUND)) {
this->stateFlags |= ENHORSE_LAND2_SOUND;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
@@ -694,8 +698,8 @@ void EnHorse_Init(Actor* thisx, PlayState* play2) {
this->unk_3E8 = 0.0f;
this->unk_528 = 100.0f;
- if (ENHORSE_GET_8000(&this->actor)) {
- this->type = HORSE_4;
+ if (ENHORSE_IS_DONKEY_TYPE(&this->actor)) {
+ this->type = HORSE_TYPE_DONKEY;
this->unk_528 = 80.0f;
this->boostSpeed = 12;
if ((this->bankIndex = Object_GetIndex(&play->objectCtx, OBJECT_HA)) < 0) {
@@ -704,8 +708,8 @@ void EnHorse_Init(Actor* thisx, PlayState* play2) {
}
this->unk_1EC |= 1;
thisx->update = func_8087D540;
- } else if (ENHORSE_GET_4000(&this->actor)) {
- this->type = HORSE_2;
+ } else if (ENHORSE_IS_4000_TYPE(&this->actor)) {
+ this->type = HORSE_TYPE_2;
this->unk_528 = 64.8f;
this->boostSpeed = 15;
if ((this->bankIndex = Object_GetIndex(&play->objectCtx, OBJECT_HORSE_LINK_CHILD)) < 0) {
@@ -717,8 +721,8 @@ void EnHorse_Init(Actor* thisx, PlayState* play2) {
} else {
thisx->update = func_8087D540;
}
- } else if (ENHORSE_GET_2000(&this->actor)) {
- this->type = HORSE_3;
+ } else if (ENHORSE_IS_BANDIT_TYPE(&this->actor)) {
+ this->type = HORSE_TYPE_BANDIT;
this->boostSpeed = 12;
if ((this->bankIndex = Object_GetIndex(&play->objectCtx, OBJECT_HA)) < 0) {
Actor_MarkForDeath(&this->actor);
@@ -727,14 +731,14 @@ void EnHorse_Init(Actor* thisx, PlayState* play2) {
this->unk_1EC |= 1;
thisx->update = func_8087D540;
} else {
- this->type = HORSE_EPONA;
+ this->type = HORSE_TYPE_EPONA;
this->boostSpeed = 15;
Actor_MarkForDeath(&this->actor);
}
- thisx->params &= ~0xE000;
- if (thisx->params == 0x1FFF) {
- thisx->params = ENHORSE_1;
+ this->actor.params &= ~(ENHORSE_PARAM_DONKEY | ENHORSE_PARAM_4000 | ENHORSE_PARAM_BANDIT);
+ if (this->actor.params == 0x1FFF) {
+ this->actor.params = ENHORSE_1;
}
if (thisx->params == ENHORSE_3) {
@@ -780,9 +784,9 @@ void EnHorse_Init(Actor* thisx, PlayState* play2) {
this->action = ENHORSE_ACT_IDLE;
thisx->speedXZ = 0.0f;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
sJntSphInit.elements[0].dim.limb = 13;
- } else if ((this->type == HORSE_3) || (this->type == HORSE_4)) {
+ } else if ((this->type == HORSE_TYPE_BANDIT) || (this->type == HORSE_TYPE_DONKEY)) {
sJntSphInit.elements[0].dim.limb = 10;
}
@@ -793,19 +797,19 @@ void EnHorse_Init(Actor* thisx, PlayState* play2) {
Collider_InitJntSph(play, &this->colliderJntSph);
Collider_SetJntSph(play, &this->colliderJntSph, &this->actor, &sJntSphInit, this->colliderJntSphElements);
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
this->colliderCylinder1.dim.radius = this->colliderCylinder1.dim.radius * 0.8f;
this->colliderCylinder2.dim.radius = this->colliderCylinder2.dim.radius * 0.8f;
this->colliderJntSph.elements[0].dim.modelSphere.radius *= 0.6f;
- } else if (this->type == HORSE_4) {
+ } else if (this->type == HORSE_TYPE_DONKEY) {
this->colliderCylinder1.dim.radius = 50;
}
CollisionCheck_SetInfo(&thisx->colChkInfo, NULL, &sColChkInfoInit);
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Actor_SetScale(&this->actor, 0.00648f);
- } else if (this->type == HORSE_4) {
+ } else if (this->type == HORSE_TYPE_DONKEY) {
Actor_SetScale(&this->actor, 0.008f);
} else {
Actor_SetScale(&this->actor, 0.01f);
@@ -889,7 +893,7 @@ void EnHorse_Init(Actor* thisx, PlayState* play2) {
thisx->world.rot.z = thisx->shape.rot.z;
thisx->home.rot.z = thisx->shape.rot.z;
this->unk_3EC = thisx->world.rot.y;
- this->unk_538 = 0;
+ this->unk_538 = OBJ_UM_ANIM_TROT;
if (this->unk_1EC & 0x100) {
this->colliderCylinder1.base.colType = COLTYPE_HIT3;
@@ -903,6 +907,7 @@ void EnHorse_Init(Actor* thisx, PlayState* play2) {
}
}
+// EnHorse_WaitForObject
void func_8087D540(Actor* thisx, PlayState* play) {
EnHorse* this = THIS;
@@ -911,7 +916,7 @@ void func_8087D540(Actor* thisx, PlayState* play) {
Actor_SetObjectDependency(play, &this->actor);
this->actor.update = EnHorse_Update;
if (this->unk_1EC & 1) {
- if (this->type == HORSE_3) {
+ if (this->type == HORSE_TYPE_BANDIT) {
SkelAnime_InitFlex(play, &this->skin.skelAnime, &object_ha_Skel_008C68, NULL, this->jointTable,
this->morphTable, OBJECT_HA_1_LIMB_MAX);
} else {
@@ -1097,11 +1102,11 @@ void EnHorse_StartMountedIdle(EnHorse* this) {
this->action = ENHORSE_ACT_MOUNTED_TURN;
this->animationIdx = ENHORSE_ANIM_IDLE;
- if (((this->curFrame > 35.0f) && (this->type == HORSE_EPONA)) ||
- ((this->curFrame > 28.0f) && (this->type == HORSE_HNI))) {
+ if (((this->curFrame > 35.0f) && (this->type == HORSE_TYPE_EPONA)) ||
+ ((this->curFrame > 28.0f) && (this->type == HORSE_TYPE_HNI))) {
if (!(this->stateFlags & ENHORSE_SANDDUST_SOUND)) {
this->stateFlags |= ENHORSE_SANDDUST_SOUND;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
@@ -1152,7 +1157,7 @@ void EnHorse_MountedIdleWhinney(EnHorse* this) {
Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, curFrame,
Animation_GetLastFrame(sAnimationHeaders[this->type][1]), ANIMMODE_ONCE, -3.0f);
if (this->stateFlags & ENHORSE_DRAW) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_GROAN);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_GROAN);
@@ -1437,7 +1442,7 @@ void EnHorse_StartRearing(EnHorse* this) {
if (sAnimationHeaders[this->type][this->animationIdx] == NULL) {
if (Rand_ZeroOne() > 0.5f) {
if (this->stateFlags & ENHORSE_DRAW) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
@@ -1451,7 +1456,7 @@ void EnHorse_StartRearing(EnHorse* this) {
this->stateFlags &= ~ENHORSE_LAND2_SOUND;
if (this->stateFlags & ENHORSE_DRAW) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
@@ -1471,7 +1476,7 @@ void EnHorse_MountedRearing(EnHorse* this, PlayState* play) {
if (this->curFrame > 25.0f) {
if (!(this->stateFlags & ENHORSE_LAND2_SOUND)) {
this->stateFlags |= ENHORSE_LAND2_SOUND;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
@@ -1511,7 +1516,7 @@ void EnHorse_StartBraking(EnHorse* this, PlayState* play) {
if (sAnimationHeaders[this->type][this->animationIdx] == NULL) {
if (Rand_ZeroOne() > 0.5f) {
if (this->stateFlags & ENHORSE_DRAW) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
@@ -1523,7 +1528,7 @@ void EnHorse_StartBraking(EnHorse* this, PlayState* play) {
EnHorse_StartMountedIdleResetAnim(this);
}
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_SLIP);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_SLIP);
@@ -1548,7 +1553,7 @@ void EnHorse_Stopping(EnHorse* this, PlayState* play) {
if ((Rand_ZeroOne() > 0.5f) &&
((gSaveContext.save.entranceIndex != 0x6400) || !Cutscene_GetSceneSetupIndex(play))) {
if (this->stateFlags & ENHORSE_DRAW) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
@@ -1681,7 +1686,7 @@ void EnHorse_StartLowJump(EnHorse* this, PlayState* play) {
y = jointTable->y;
this->riderPos.y -= ((y * 0.01f) * this->unk_528) * 0.01f;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
@@ -1740,7 +1745,7 @@ void EnHorse_LowJump(EnHorse* this, PlayState* play) {
if (SkelAnime_Update(&this->skin.skelAnime) ||
((curFrame > 17.0f) &&
(this->actor.world.pos.y < ((this->actor.floorHeight - this->actor.velocity.y) + 80.0f)))) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
@@ -1779,7 +1784,7 @@ void EnHorse_StartHighJump(EnHorse* this, PlayState* play) {
this->riderPos.y -= ((y * 0.01f) * this->unk_528) * 0.01f;
this->stateFlags |= ENHORSE_CALC_RIDER_POS;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
@@ -1837,7 +1842,7 @@ void EnHorse_HighJump(EnHorse* this, PlayState* play) {
if (SkelAnime_Update(&this->skin.skelAnime) ||
((curFrame > 23.0f) &&
(this->actor.world.pos.y < ((this->actor.floorHeight - this->actor.velocity.y) + 80.0f)))) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
@@ -1862,10 +1867,10 @@ void EnHorse_InitInactive(EnHorse* this) {
}
void EnHorse_Inactive(EnHorse* this, PlayState* play) {
- if ((D_801BDAA4 != 0) && (this->type == HORSE_2)) {
+ if ((D_801BDAA4 != 0) && (this->type == HORSE_TYPE_2)) {
D_801BDAA4 = 0;
if (EnHorse_Spawn(this, play)) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_NEIGH);
}
this->stateFlags &= ~ENHORSE_INACTIVE;
@@ -1901,7 +1906,7 @@ void EnHorse_PlayIdleAnimation(EnHorse* this, s32 anim, f32 morphFrames, f32 sta
} else {
if (this->animationIdx == ENHORSE_ANIM_WHINNEY) {
if (this->stateFlags & ENHORSE_DRAW) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_GROAN);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_GROAN);
@@ -1909,7 +1914,7 @@ void EnHorse_PlayIdleAnimation(EnHorse* this, s32 anim, f32 morphFrames, f32 sta
}
} else if (this->animationIdx == ENHORSE_ANIM_REARING) {
if (this->stateFlags & ENHORSE_DRAW) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
@@ -1942,11 +1947,11 @@ void EnHorse_Idle(EnHorse* this, PlayState* play) {
this->actor.speedXZ = 0.0f;
EnHorse_IdleAnimSounds(this, play);
- if ((D_801BDAA4 != 0) && (this->type == HORSE_2)) {
+ if ((D_801BDAA4 != 0) && (this->type == HORSE_TYPE_2)) {
D_801BDAA4 = 0;
if (!func_8087C38C(play, this, &this->actor.world.pos)) {
if (EnHorse_Spawn(this, play)) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_NEIGH);
@@ -1955,7 +1960,7 @@ void EnHorse_Idle(EnHorse* this, PlayState* play) {
EnHorse_SetFollowAnimation(this, play);
}
} else {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_NEIGH);
@@ -2067,7 +2072,7 @@ void EnHorse_FollowPlayer(EnHorse* this, PlayState* play) {
this->actor.shape.rot.y = this->actor.world.rot.y;
if ((this->curFrame > 25.0f) && !(this->stateFlags & ENHORSE_LAND2_SOUND)) {
this->stateFlags |= ENHORSE_LAND2_SOUND;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
@@ -2099,7 +2104,7 @@ void EnHorse_FollowPlayer(EnHorse* this, PlayState* play) {
if (this->followTimer > 300) {
EnHorse_StartIdleRidable(this);
if (this->stateFlags & ENHORSE_DRAW) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
@@ -2179,14 +2184,14 @@ void EnHorse_UpdateIngoHorseAnim(EnHorse* this) {
animSpeed = this->actor.speedXZ * 0.5f;
} else if (this->animationIdx == ENHORSE_ANIM_TROT) {
animSpeed = this->actor.speedXZ * 0.25f;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
}
} else if (this->animationIdx == ENHORSE_ANIM_GALLOP) {
animSpeed = this->actor.speedXZ * 0.2f;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
@@ -2259,7 +2264,7 @@ void func_80881290(EnHorse* this, PlayState* play) {
this->actor.gravity = 0.0f;
this->actor.velocity.y = 0.0f;
this->jumpStartY = this->actor.world.pos.y;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
@@ -2299,7 +2304,7 @@ void func_80881398(EnHorse* this, PlayState* play) {
if (animeUpdated || ((curFrame > 17.0f) &&
(this->actor.world.pos.y < ((this->actor.floorHeight - this->actor.velocity.y) + 80.0f)))) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
@@ -2371,14 +2376,14 @@ void func_8088168C(EnHorse* this) {
animSpeed = this->actor.speedXZ * 0.5f;
} else if (this->animationIdx == ENHORSE_ANIM_TROT) {
animSpeed = this->actor.speedXZ * 0.25f;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
}
} else if (this->animationIdx == ENHORSE_ANIM_GALLOP) {
animSpeed = this->actor.speedXZ * 0.2f;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
@@ -2516,7 +2521,7 @@ void EnHorse_CsPlayHighJumpAnim(EnHorse* this, PlayState* play) {
this->riderPos.y -= y * 0.01f * this->unk_528 * 0.01f;
this->stateFlags |= ENHORSE_ANIM_HIGH_JUMP;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
@@ -2566,7 +2571,7 @@ void EnHorse_CsJump(EnHorse* this, PlayState* play, CsCmdActorAction* action) {
((curFrame > 19.0f) &&
(this->actor.world.pos.y < ((this->actor.floorHeight - this->actor.velocity.y) + 80.0f)))) {
this->cutsceneFlags |= 1;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
@@ -2595,7 +2600,7 @@ void EnHorse_CsRearingInit(EnHorse* this, PlayState* play, CsCmdActorAction* act
this->cutsceneFlags &= ~4;
this->stateFlags &= ~ENHORSE_LAND2_SOUND;
if (this->stateFlags & ENHORSE_DRAW) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
@@ -2610,7 +2615,7 @@ void EnHorse_CsRearing(EnHorse* this, PlayState* play, CsCmdActorAction* action)
if (this->curFrame > 25.0f) {
if (!(this->stateFlags & ENHORSE_LAND2_SOUND)) {
this->stateFlags |= ENHORSE_LAND2_SOUND;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
@@ -2688,7 +2693,7 @@ void EnHorse_CsWarpRearingInit(EnHorse* this, PlayState* play, CsCmdActorAction*
this->stateFlags &= ~ENHORSE_LAND2_SOUND;
if (this->stateFlags & ENHORSE_DRAW) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
@@ -2703,7 +2708,7 @@ void EnHorse_CsWarpRearing(EnHorse* this, PlayState* play, CsCmdActorAction* act
if (this->curFrame > 25.0f) {
if (!(this->stateFlags & ENHORSE_LAND2_SOUND)) {
this->stateFlags |= ENHORSE_LAND2_SOUND;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
@@ -2860,7 +2865,7 @@ void EnHorse_UpdateHbaAnim(EnHorse* this) {
animSpeed = this->actor.speedXZ * 0.5f;
} else if (this->animationIdx == ENHORSE_ANIM_TROT) {
animSpeed = this->actor.speedXZ * 0.25f;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
@@ -2868,7 +2873,7 @@ void EnHorse_UpdateHbaAnim(EnHorse* this) {
Rumble_Request(0.0f, 60, 8, 255);
} else if (this->animationIdx == ENHORSE_ANIM_GALLOP) {
animSpeed = this->actor.speedXZ * 0.2f;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
@@ -2952,9 +2957,9 @@ void EnHorse_FleePlayer(EnHorse* this, PlayState* play) {
s32 animFinished;
s16 yaw;
- if ((D_801BDAA4 != 0) || (this->type == HORSE_HNI)) {
+ if ((D_801BDAA4 != 0) || (this->type == HORSE_TYPE_HNI)) {
EnHorse_StartIdleRidable(this);
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_NEIGH);
@@ -3059,7 +3064,7 @@ void EnHorse_FleePlayer(EnHorse* this, PlayState* play) {
} else {
this->animationIdx = ENHORSE_ANIM_WHINNEY;
if (this->stateFlags & ENHORSE_DRAW) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_GROAN);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_GROAN);
@@ -3331,12 +3336,12 @@ void func_80884994(EnHorse* this) {
}
void func_80884A40(EnHorse* this, PlayState* play) {
- s32 sp44[] = { 5, 6, 0 };
+ s32 sp44[] = { ENHORSE_ANIM_TROT, ENHORSE_ANIM_GALLOP, ENHORSE_ANIM_IDLE };
s32 sp40;
s32 temp_v0;
if (this->animationIdx == ENHORSE_ANIM_WHINNEY) {
- temp_v0 = 0;
+ temp_v0 = ENHORSE_ANIM_IDLE;
} else {
temp_v0 = this->animationIdx;
}
@@ -3366,9 +3371,9 @@ void func_80884A40(EnHorse* this, PlayState* play) {
0.0f);
}
- if ((this->unk_538 == 0) || (this->unk_538 == 1)) {
+ if ((this->unk_538 == OBJ_UM_ANIM_TROT) || (this->unk_538 == OBJ_UM_ANIM_GALLOP)) {
Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_HORSE_RUN);
- } else if (this->unk_538 == 2) {
+ } else if (this->unk_538 == OBJ_UM_ANIM_IDLE) {
if (this->animationIdx == ENHORSE_ANIM_IDLE) {
EnHorse_IdleAnimSounds(this, play);
} else if (this->animationIdx == ENHORSE_ANIM_WHINNEY) {
@@ -3392,6 +3397,7 @@ void func_80884D04(EnHorse* this, PlayState* play) {
Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, 0.0f);
}
+// Action func: EnHorse_UpdateBandit?
void func_80884E0C(EnHorse* this, PlayState* play) {
f32 playSpeed = (this->unk_56C * 0.2f * 0.5f) + 1.0f;
Vec3f pos;
@@ -3408,8 +3414,8 @@ void func_80884E0C(EnHorse* this, PlayState* play) {
}
this->unk_57C = this->actor.world.pos;
- this->actor.world.pos.x = this->unk_570.x;
- this->actor.world.pos.z = this->unk_570.z;
+ this->actor.world.pos.x = this->banditPosition.x;
+ this->actor.world.pos.z = this->banditPosition.z;
this->unk_56C = Math3D_Distance(&this->actor.world.pos, &this->actor.prevPos);
if (((this->unk_550 == 5) || (this->unk_550 == 7)) && (Player_GetMask(play) != PLAYER_MASK_CIRCUS_LEADER)) {
@@ -3429,7 +3435,7 @@ void func_80884E0C(EnHorse* this, PlayState* play) {
}
this->actor.world.pos.y += this->actor.velocity.y * 0.5f;
} else {
- this->actor.world.pos.y = this->unk_570.y;
+ this->actor.world.pos.y = this->banditPosition.y;
}
}
@@ -3536,7 +3542,7 @@ void EnHorse_CheckFloors(EnHorse* this, PlayState* play) {
return;
}
- if (this->type != HORSE_2) {
+ if (this->type != HORSE_TYPE_2) {
EnHorse_Vec3fOffset(&this->actor.world.pos, this->actor.shape.rot.y, 30.0f, 55.0f, &frontPos);
} else {
EnHorse_Vec3fOffset(&this->actor.world.pos, this->actor.shape.rot.y, 15.0f, 30.0f, &frontPos);
@@ -3555,7 +3561,7 @@ void EnHorse_CheckFloors(EnHorse* this, PlayState* play) {
return;
}
- if (this->type != HORSE_2) {
+ if (this->type != HORSE_TYPE_2) {
EnHorse_Vec3fOffset(&this->actor.world.pos, this->actor.shape.rot.y, -30.0f, 55.0f, &backPos);
} else {
EnHorse_Vec3fOffset(&this->actor.world.pos, this->actor.shape.rot.y, -15.0f, 30.0f, &backPos);
@@ -3732,7 +3738,7 @@ void EnHorse_UpdateBgCheckInfo(EnHorse* this, PlayState* play) {
if ((this->actor.bgCheckFlags & 8) && (Math_CosS(this->actor.wallYaw - this->actor.world.rot.y) < -0.3f)) {
if (this->actor.speedXZ > 4.0f) {
this->actor.speedXZ -= 1.0f;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
@@ -3749,7 +3755,7 @@ void EnHorse_UpdateBgCheckInfo(EnHorse* this, PlayState* play) {
this->unk_3E8 += ((-10.0f / this->actor.scale.y) - this->unk_3E8) * 0.5f;
if (this->actor.speedXZ > 2.0f) {
this->actor.speedXZ -= 1.0f;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
} else {
Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
@@ -3990,7 +3996,7 @@ void func_80886C00(EnHorse* this, PlayState* play) {
this->boostTimer = 0;
if (this->numBoosts == 0) {
this->boostRegenTime = 140;
- } else if (this->type == HORSE_EPONA) {
+ } else if (this->type == HORSE_TYPE_EPONA) {
if (this->stateFlags & ENHORSE_FIRST_BOOST_REGEN) {
this->boostRegenTime = 60;
this->stateFlags &= ~ENHORSE_FIRST_BOOST_REGEN;
@@ -4001,7 +4007,7 @@ void func_80886C00(EnHorse* this, PlayState* play) {
this->boostRegenTime = 70;
}
} else if ((this->stateFlags & ENHORSE_DRAW) && (Rand_ZeroOne() < 0.1f)) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
@@ -4056,7 +4062,7 @@ void EnHorse_RegenBoost(EnHorse* this, PlayState* play) {
if (this->boostTimer == 8) {
if ((Rand_ZeroOne() < 0.25f) && (this->stateFlags & ENHORSE_DRAW)) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
@@ -4175,9 +4181,9 @@ void EnHorse_Update(Actor* thisx, PlayState* play2) {
Vec3f dustVel = { 0.0f, 1.0f, 0.0f };
Player* player = GET_PLAYER(play);
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Actor_SetScale(&this->actor, 0.00648f);
- } else if (this->type == HORSE_4) {
+ } else if (this->type == HORSE_TYPE_DONKEY) {
Actor_SetScale(&this->actor, 0.008f);
} else {
Actor_SetScale(&this->actor, 0.01f);
@@ -4258,7 +4264,7 @@ void EnHorse_Update(Actor* thisx, PlayState* play2) {
}
if ((this->colliderJntSph.base.acFlags & AC_HIT) && (this->stateFlags & ENHORSE_DRAW)) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
} else {
Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
@@ -4290,7 +4296,7 @@ void EnHorse_Update(Actor* thisx, PlayState* play2) {
Collider_UpdateCylinder(&this->actor, &this->colliderCylinder1);
Collider_UpdateCylinder(&this->actor, &this->colliderCylinder2);
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
this->colliderCylinder1.dim.pos.x =
(s16)(Math_SinS(thisx->shape.rot.y) * 11.0f) + this->colliderCylinder1.dim.pos.x;
this->colliderCylinder1.dim.pos.z =
@@ -4456,7 +4462,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
f32 sp34;
if (!(this->stateFlags & ENHORSE_CALC_RIDER_POS)) {
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetVertexPos(skin, 5, 120, &this->riderPos);
this->riderPos.y += 13.0f;
} else {
@@ -4471,7 +4477,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
this->stateFlags &= ~ENHORSE_CALC_RIDER_POS;
}
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 13, &sp7C, &sp38);
} else {
Skin_GetLimbPos(skin, 13, &sp7C, &sp38);
@@ -4492,7 +4498,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
if (((curFrame > 10.0f) && (curFrame < 13.0f)) || ((curFrame > 25.0f) && (curFrame < 33.0f))) {
if (Rand_ZeroOne() < 0.02f) {
this->dustFlags |= 2;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 20, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 20, &hoofOffset, &sp64);
@@ -4502,7 +4508,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
if (Rand_ZeroOne() < 0.02f) {
this->dustFlags |= 1;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 28, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 28, &hoofOffset, &sp64);
@@ -4514,7 +4520,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
if (((curFrame > 6.0f) && (curFrame < 10.0f)) || ((curFrame > 23.0f) && (curFrame < 29.0f))) {
if (Rand_ZeroOne() < 0.02f) {
this->dustFlags |= 8;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 36, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 37, &hoofOffset, &sp64);
@@ -4526,7 +4532,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
if ((((curFrame > 7.0f) && (curFrame < 14.0f)) || ((curFrame > 26.0f) && (curFrame < 30.0f))) &&
(Rand_ZeroOne() < 0.02f)) {
this->dustFlags |= 4;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 44, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 45, &hoofOffset, &sp64);
@@ -4536,7 +4542,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
} else if (this->animationIdx == ENHORSE_ANIM_GALLOP) {
if ((curFrame > 14.0f) && (curFrame < 16.0f) && (Rand_ZeroOne() < 0.02f)) {
this->dustFlags |= 1;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 28, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 28, &hoofOffset, &sp64);
@@ -4544,7 +4550,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
EnHorse_RandomOffset(&sp64, 5.0f, &this->frontRightHoof);
} else if ((curFrame > 8.0f) && (curFrame < 10.0f) && (Rand_ZeroOne() < 0.02f)) {
this->dustFlags |= 2;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 20, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 20, &hoofOffset, &sp64);
@@ -4552,7 +4558,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
EnHorse_RandomOffset(&sp64, 10.0f, &this->frontLeftHoof);
} else if ((curFrame > 1.0f) && (curFrame < 3.0f) && (Rand_ZeroOne() < 0.02f)) {
this->dustFlags |= 4;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 44, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 45, &hoofOffset, &sp64);
@@ -4560,7 +4566,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
EnHorse_RandomOffset(&sp64, 10.0f, &this->backRightHoof);
} else if ((curFrame > 26.0f) && (curFrame < 28.0f) && (Rand_ZeroOne() < 0.02f)) {
this->dustFlags |= 8;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 36, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 37, &hoofOffset, &sp64);
@@ -4571,7 +4577,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
(Rand_ZeroOne() < (1.0f - ((curFrame - 6.0f) * (1.0f / 17.0f))))) {
if (Rand_ZeroOne() < 0.05f) {
this->dustFlags |= 8;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 36, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 37, &hoofOffset, &sp64);
@@ -4580,7 +4586,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
}
if (Rand_ZeroOne() < 0.02f) {
this->dustFlags |= 4;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 44, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 45, &hoofOffset, &sp64);
@@ -4591,7 +4597,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
if (Rand_ZeroOne() < (1.0f - ((curFrame - 5.0f) * 0.04f))) {
if (Rand_ZeroOne() < 0.05f) {
this->dustFlags |= 8;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 36, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 37, &hoofOffset, &sp64);
@@ -4601,7 +4607,7 @@ void EnHorse_PostDraw(Actor* thisx, PlayState* play, Skin* skin) {
if (Rand_ZeroOne() < 0.02f) {
this->dustFlags |= 4;
- if (this->type == HORSE_2) {
+ if (this->type == HORSE_TYPE_2) {
Skin_GetLimbPos(skin, 44, &hoofOffset, &sp64);
} else {
Skin_GetLimbPos(skin, 45, &hoofOffset, &sp64);
@@ -4649,12 +4655,12 @@ s32 EnHorse_OverrideLimbDraw(Actor* thisx, PlayState* play, s32 limbIndex, Skin*
OPEN_DISPS(play->state.gfxCtx);
- if ((limbIndex != 13) || (this->type != HORSE_EPONA)) {
- if ((limbIndex == 13) && (this->type == HORSE_2)) {
+ if ((limbIndex != 13) || (this->type != HORSE_TYPE_EPONA)) {
+ if ((limbIndex == 13) && (this->type == HORSE_TYPE_2)) {
u8 idx = D_80889210[this->blinkTimer];
gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(D_80889204[idx]));
- } else if ((this->type == HORSE_HNI) && (this->stateFlags & ENHORSE_FLAG_18) && (limbIndex == 30)) {
+ } else if ((this->type == HORSE_TYPE_HNI) && (this->stateFlags & ENHORSE_FLAG_18) && (limbIndex == 30)) {
drawOriginalLimb = false;
}
}
diff --git a/src/overlays/actors/ovl_En_Horse/z_en_horse.h b/src/overlays/actors/ovl_En_Horse/z_en_horse.h
index a05e1a2c58..9f32331c6d 100644
--- a/src/overlays/actors/ovl_En_Horse/z_en_horse.h
+++ b/src/overlays/actors/ovl_En_Horse/z_en_horse.h
@@ -3,11 +3,11 @@
#include "global.h"
#include "z64skin.h"
-#include "overlays/actors/ovl_En_In/z_en_in.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/object_ha/object_ha.h"
struct EnHorse;
+struct EnIn;
typedef void (*EnHorseActionFunc)(struct EnHorse*, PlayState*);
typedef void (*EnHorsePostdrawFunc)(struct EnHorse*, PlayState*);
@@ -97,18 +97,22 @@ typedef enum {
} EnHorseAnimationIndex;
typedef enum {
- /* 0 */ HORSE_EPONA,
- /* 1 */ HORSE_HNI,
- /* 2 */ HORSE_2,
- /* 3 */ HORSE_3,
- /* 4 */ HORSE_4
+ /* 0 */ HORSE_TYPE_EPONA,
+ /* 1 */ HORSE_TYPE_HNI,
+ /* 2 */ HORSE_TYPE_2,
+ /* 3 */ HORSE_TYPE_BANDIT,
+ /* 4 */ HORSE_TYPE_DONKEY // Cremia's donkey
} HorseType;
-#define ENHORSE_GET_2000(thisx) ((thisx)->params & 0x2000)
-#define ENHORSE_GET_4000(thisx) ((thisx)->params & 0x4000)
-#define ENHORSE_GET_8000(thisx) ((thisx)->params & 0x8000)
+#define ENHORSE_PARAM_BANDIT 0x2000
+#define ENHORSE_PARAM_4000 0x4000
+#define ENHORSE_PARAM_DONKEY 0x8000
-enum {
+#define ENHORSE_IS_BANDIT_TYPE(thisx) ((thisx)->params & ENHORSE_PARAM_BANDIT)
+#define ENHORSE_IS_4000_TYPE(thisx) ((thisx)->params & ENHORSE_PARAM_4000)
+#define ENHORSE_IS_DONKEY_TYPE(thisx) ((thisx)->params & ENHORSE_PARAM_DONKEY)
+
+typedef enum {
/* 0 */ ENHORSE_0,
/* 1 */ ENHORSE_1,
/* 2 */ ENHORSE_2,
@@ -130,7 +134,13 @@ enum {
/* 18 */ ENHORSE_18,
/* 19 */ ENHORSE_19,
/* 20 */ ENHORSE_20,
-};
+} EnHorseParam;
+
+/**
+ * `paramtype` should be `ENHORSE_PARAM_BANDIT`, `ENHORSE_PARAM_4000` or `ENHORSE_PARAM_DONKEY`
+ * `lower` should be a value of the enum `EnHorseParam`
+ */
+#define ENHORSE_PARAMS(type, lower) ((type) | (lower))
typedef struct EnHorse {
/* 0x000 */ Actor actor;
@@ -180,7 +190,7 @@ typedef struct EnHorse {
/* 0x384 */ u16 cutsceneFlags;
/* 0x388 */ s32 inRace;
/* 0x38C */ struct EnIn* rider;
- /* 0x390 */ UNK_TYPE1 unk390[0x4];
+ /* 0x390 */ UNK_TYPE1 unk_390[0x4];
/* 0x394 */ u16 unk_394;
/* 0x398 */ f32 unk_398;
/* 0x39C */ s32 unk_39C;
@@ -193,7 +203,7 @@ typedef struct EnHorse {
/* 0x3C8 */ Vec3f backRightHoof;
/* 0x3D4 */ Vec3f backLeftHoof;
/* 0x3E0 */ s32 unk_3E0;
- /* 0x3E4 */ UNK_TYPE1 unk3E4[0x4];
+ /* 0x3E4 */ UNK_TYPE1 unk_3E4[0x4];
/* 0x3E8 */ f32 unk_3E8;
/* 0x3EC */ s16 unk_3EC;
/* 0x3EE */ Vec3s jointTable[OBJECT_HA_1_LIMB_MAX];
@@ -205,13 +215,19 @@ typedef struct EnHorse {
/* 0x538 */ s32 unk_538;
/* 0x53C */ s32 unk_53C;
/* 0x540 */ Vec3f unk_540;
- /* 0x54C */ UNK_TYPE1 unk54C[0x4];
+ /* 0x54C */ UNK_TYPE unk_54C;
/* 0x550 */ s32 unk_550;
- /* 0x554 */ UNK_TYPE1 unk554[0x18];
+ /* 0x554 */ UNK_TYPE unk_554;
+ /* 0x558 */ UNK_TYPE unk_558;
+ /* 0x55C */ s32 unk_55C; // maybe currentDistanceToCart... it isn't really a distance tho
+ /* 0x560 */ s32 unk_560; // maybe initialDistanceToCart
+ /* 0x564 */ s32 unk_564; // set but not used
+ /* 0x568 */ f32 unk_568; // set but not used
/* 0x56C */ f32 unk_56C;
- /* 0x570 */ Vec3f unk_570;
+ /* 0x570 */ Vec3f banditPosition; // Milk run minigame bandit
/* 0x57C */ Vec3f unk_57C;
- /* 0x588 */ UNK_TYPE1 unk588[0x4];
+ /* 0x588 */ s16 unk_588;
+ /* 0x58A */ UNK_TYPE1 unk_58A[0x2]; // struct padding?
/* 0x58C */ s32 unk_58C;
/* 0x590 */ s32 unk_590;
} EnHorse; // size = 0x594
diff --git a/src/overlays/actors/ovl_En_Horse_Game_Check/z_en_horse_game_check.c b/src/overlays/actors/ovl_En_Horse_Game_Check/z_en_horse_game_check.c
index 278ec71441..f3ec0c245c 100644
--- a/src/overlays/actors/ovl_En_Horse_Game_Check/z_en_horse_game_check.c
+++ b/src/overlays/actors/ovl_En_Horse_Game_Check/z_en_horse_game_check.c
@@ -124,14 +124,14 @@ s32 func_808F8CCC(EnHorseGameCheck* this, PlayState* play2) {
func_8010E9F0(4, 0);
play->interfaceCtx.unk_280 = 1;
- this->horse1 =
- (EnHorse*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, -1149.0f, -106.0f, 470.0f, 0, 0x7FFF, 0, 0x2004);
+ this->horse1 = (EnHorse*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, -1149.0f, -106.0f, 470.0f, 0, 0x7FFF, 0,
+ ENHORSE_PARAMS(ENHORSE_PARAM_BANDIT, ENHORSE_4));
if (this->horse1 == NULL) {
__assert("../z_en_horse_game_check.c", 1517);
}
- this->horse2 =
- (EnHorse*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, -1376.0f, -106.0f, 470.0f, 0, 0x7FFF, 0, 0x2005);
+ this->horse2 = (EnHorse*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, -1376.0f, -106.0f, 470.0f, 0, 0x7FFF, 0,
+ ENHORSE_PARAMS(ENHORSE_PARAM_BANDIT, ENHORSE_5));
if (this->horse2 == NULL) {
__assert("../z_en_horse_game_check.c", 1526);
}
diff --git a/src/overlays/actors/ovl_En_Test4/z_en_test4.c b/src/overlays/actors/ovl_En_Test4/z_en_test4.c
index ef82244535..5311b35a6e 100644
--- a/src/overlays/actors/ovl_En_Test4/z_en_test4.c
+++ b/src/overlays/actors/ovl_En_Test4/z_en_test4.c
@@ -404,7 +404,7 @@ void func_80A42AB8(EnTest4* this, PlayState* play) {
if (player->stateFlags1 & 0x800000) {
EnHorse* rideActor = (EnHorse*)player->rideActor;
- if ((rideActor->type == HORSE_EPONA) || (rideActor->type == HORSE_2)) {
+ if ((rideActor->type == HORSE_TYPE_EPONA) || (rideActor->type == HORSE_TYPE_2)) {
if (CURRENT_DAY < 3) {
D_801BDA9C = 1;
} else {
diff --git a/src/overlays/actors/ovl_Obj_Um/z_obj_um.c b/src/overlays/actors/ovl_Obj_Um/z_obj_um.c
index 5175a8ee10..658cae6525 100644
--- a/src/overlays/actors/ovl_Obj_Um/z_obj_um.c
+++ b/src/overlays/actors/ovl_Obj_Um/z_obj_um.c
@@ -1,39 +1,66 @@
/*
* File: z_obj_um.c
* Overlay: ovl_Obj_Um
- * Description: Cremia's cart and milk run quest
+ * Description: Cremia's Cart and milk run minigame
*/
#include "z_obj_um.h"
+#include "overlays/actors/ovl_En_In/z_en_in.h"
+#include "objects/gameplay_keep/gameplay_keep.h"
#define FLAGS (ACTOR_FLAG_1 | ACTOR_FLAG_8 | ACTOR_FLAG_10 | ACTOR_FLAG_20)
#define THIS ((ObjUm*)thisx)
+/**
+ * weekEventReg flags checked by this actor:
+ * - gSaveContext.save.weekEventReg[22] & 1: Aliens defeated
+ * If false: The actor doesn't spawn
+ * - gSaveContext.save.weekEventReg[31] & 0x40
+ * If true: Cremia doesn't explain again she'll deliever milk to town
+ * - gSaveContext.save.weekEventReg[31] & 0x80
+ * If true: Triggers cutscene on Romani's Ranch
+ * - gSaveContext.save.weekEventReg[34] & 0x80
+ * If true: Doesn't spawn on Romani's Ranch
+ * - gSaveContext.save.weekEventReg[52] & 1
+ * If true: Doesn't spawn on Romani's Ranch or Milk Road
+ * - gSaveContext.save.weekEventReg[52] & 2
+ * If true: Doesn't spawn on Romani's Ranch or Milk Road
+ * - gSaveContext.save.weekEventReg[59] & 2
+ * If true: Doesn't spawn again on Milk Road
+ *
+ * weekEventReg flags set by this actor:
+ * - gSaveContext.save.weekEventReg[31] |= 0x40: Cremia offered a ride
+ * Cremia offered a ride accross the Milk Road to Player
+ * - gSaveContext.save.weekEventReg[31] |= 0x80: Player is in Milk Run
+ * Player accepts the ride and is with Cremia during the Milk Run.
+ * - gSaveContext.save.weekEventReg[34] |= 0x80: Cremia does Milk Run alone
+ * Player didn't interact or didn't accept the ride
+ * - gSaveContext.save.weekEventReg[52] |= 1: Won Milk Run minigame
+ * At least one pot is safe. Turns off the "Lose Milk Run minigame"
+ * - gSaveContext.save.weekEventReg[52] |= 2: Lose Milk Run minigame
+ * Every pot was broken by bandits. Turns off the "Win Milk Run minigame"
+ * - gSaveContext.save.weekEventReg[59] |= 2: ?
+ * Passed through Milk Road after winning the Milk Run
+ *
+ * weekEventReg flags unset by this actor:
+ * - gSaveContext.save.weekEventReg[31] &= (u8)~0x80
+ * Turned off when the Milk Run finishes
+ * - gSaveContext.save.weekEventReg[52] &= (u8)~1
+ * Turned off if Player lose the Milk Run
+ * - gSaveContext.save.weekEventReg[52] &= (u8)~2
+ * Turned off if Player wins the Milk Run
+ */
+
void ObjUm_Init(Actor* thisx, PlayState* play);
void ObjUm_Destroy(Actor* thisx, PlayState* play);
void ObjUm_Update(Actor* thisx, PlayState* play);
void ObjUm_Draw(Actor* thisx, PlayState* play);
-void func_80B79A50(ObjUm* this, PlayState* play);
-void func_80B79F10(ObjUm* this, PlayState* play);
-void func_80B7A070(ObjUm* this, PlayState* play);
-void func_80B7A0E0(ObjUm* this, PlayState* play);
-void func_80B7A144(ObjUm* this, PlayState* play);
-void func_80B7A2AC(ObjUm* this, PlayState* play);
-void func_80B7A394(ObjUm* this, PlayState* play);
-void func_80B7A400(ObjUm* this, PlayState* play);
-void func_80B7A494(ObjUm* this, PlayState* play);
-void func_80B7A614(ObjUm* this, PlayState* play);
-void func_80B7A7AC(ObjUm* this, PlayState* play);
-void func_80B7ABE4(ObjUm* this, PlayState* play);
-void func_80B7AC94(ObjUm* this, PlayState* play);
-void func_80B7AD34(ObjUm* this, PlayState* play);
-void func_80B7AE58(ObjUm* this, PlayState* play);
-
+void ObjUm_DefaultAnim(ObjUm* this, PlayState* play);
+void ObjUm_UpdateAnim(ObjUm* this, PlayState* play, ObjUmAnimimations index);
void ObjUm_SetupAction(ObjUm* this, ObjUmActionFunc actionFunc);
-#if 0
const ActorInit Obj_Um_InitVars = {
ACTOR_OBJ_UM,
ACTORCAT_NPC,
@@ -46,131 +73,1949 @@ const ActorInit Obj_Um_InitVars = {
(ActorFunc)ObjUm_Draw,
};
-// static ColliderCylinderInit sCylinderInit = {
-static ColliderCylinderInit D_80B7C138 = {
- { COLTYPE_HIT3, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_NONE, OC2_TYPE_1, COLSHAPE_CYLINDER, },
- { ELEMTYPE_UNK1, { 0x00000000, 0x00, 0x00 }, { 0x00000020, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON, OCELEM_NONE, },
+static TexturePtr sEyeTextures[] = {
+ gUmCremiaEyeOpenTex, gUmCremiaEyeHalfTex, gUmCremiaEyeClosedTex,
+ gUmCremiaEyeHappyTex, gUmCremiaEyeAngryTex, gUmCremiaEyeSadTex,
+};
+
+static TexturePtr sMouthTextures[] = {
+ gUmMouthNormalTex,
+ gUmMouthHappyTex,
+ gUmMouthHangingOpenTex,
+ gUmMouthFrownTex,
+};
+
+static ColliderCylinderInit sCylinderInit = {
+ {
+ COLTYPE_HIT3,
+ AT_NONE,
+ AC_ON | AC_TYPE_PLAYER,
+ OC1_NONE,
+ OC2_TYPE_1,
+ COLSHAPE_CYLINDER,
+ },
+ {
+ ELEMTYPE_UNK1,
+ { 0x00000000, 0x00, 0x00 },
+ { 0x00000020, 0x00, 0x00 },
+ TOUCH_NONE | TOUCH_SFX_NORMAL,
+ BUMP_ON,
+ OCELEM_NONE,
+ },
{ 40, 64, 0, { 0, 0, 0 } },
};
-// static InitChainEntry sInitChain[] = {
-static InitChainEntry D_80B7C254[] = {
+// actionfuncs
+void func_80B7A144(ObjUm* this, PlayState* play);
+void ObjUm_RanchWait(ObjUm* this, PlayState* play);
+void ObjUm_PreMilkRunStartCs(ObjUm* this, PlayState* play);
+void ObjUm_StartCs(ObjUm* this, PlayState* play);
+void ObjUm_PostMilkRunStartCs(ObjUm* this, PlayState* play);
+void ObjUm_TerminaFieldIdle(ObjUm* this, PlayState* play);
+void ObjUm_RanchWaitPathFinished(ObjUm* this, PlayState* play);
+void func_80B7A0E0(ObjUm* this, PlayState* play);
+void func_80B7A070(ObjUm* this, PlayState* play);
+void ObjUm_RanchStartCs(ObjUm* this, PlayState* play);
+void func_80B7A2AC(ObjUm* this, PlayState* play);
+void func_80B7A240(ObjUm* this, PlayState* play);
+void func_80B7A394(ObjUm* this, PlayState* play);
+void ObjUm_RunMinigame(ObjUm* this, PlayState* play);
+void func_80B7A614(ObjUm* this, PlayState* play);
+void func_80B7AB78(ObjUm* this, PlayState* play);
+void func_80B7ABE4(ObjUm* this, PlayState* play);
+void ObjUm_PostMilkRunWaitPathFinished(ObjUm* this, PlayState* play);
+
+// Maybe it is updating the bandits positions?
+void func_80B77770(ObjUm* this, PlayState* play) {
+ s16 rotY = this->dyna.actor.shape.rot.y;
+ Vec3f sp108;
+ Vec3f spFC;
+ Vec3f spF0;
+ Vec3f spE4;
+ Vec3f spD8;
+ Vec3f spCC;
+ Vec3f spC0;
+ Vec3f spB4;
+ Vec3f spA8;
+ Vec3f sp9C;
+ Vec3f sp90;
+ Vec3f sp84;
+ Vec3f sp78;
+ Vec3f sp6C;
+ Vec3f sp60 = this->dyna.actor.world.pos;
+
+ // Loop unroll?
+ this->unk_360[15] = sp60;
+ sp6C = sp60;
+ this->unk_360[14] = sp6C;
+ sp78 = sp6C;
+ this->unk_360[13] = sp78;
+ sp84 = sp78;
+ this->unk_360[12] = sp84;
+ sp90 = sp84;
+ this->unk_360[11] = sp90;
+ sp9C = sp90;
+ this->unk_360[10] = sp9C;
+ spA8 = sp9C;
+ this->unk_360[9] = spA8;
+ spB4 = spA8;
+ this->unk_360[8] = spB4;
+ spC0 = spB4;
+ this->unk_360[7] = spC0;
+ spCC = spC0;
+ this->unk_360[6] = spCC;
+ spD8 = spCC;
+ this->unk_360[5] = spD8;
+ spE4 = spD8;
+ this->unk_360[4] = spE4;
+ spF0 = spE4;
+ this->unk_360[3] = spF0;
+ spFC = spF0;
+ this->unk_360[2] = spFC;
+ sp108 = spFC;
+ this->unk_360[1] = sp108;
+ this->unk_360[0] = sp108;
+
+ this->unk_360[0].x += 110.0f * Math_SinS(rotY + 0x4000);
+ this->unk_360[0].z += 110.0f * Math_CosS(rotY + 0x4000);
+ this->unk_360[1].x += 110.0f * Math_SinS(rotY - 0x4000);
+ this->unk_360[1].z += 110.0f * Math_CosS(rotY - 0x4000);
+ Math_Vec3f_Copy(&this->unk_360[2], &this->unk_360[0]);
+ this->unk_360[2].x -= 200.0f * Math_SinS(rotY);
+ this->unk_360[2].z -= 200.0f * Math_CosS(rotY);
+ Math_Vec3f_Copy(&this->unk_360[4], &this->unk_360[1]);
+ this->unk_360[4].x -= 200.0f * Math_SinS(rotY);
+ this->unk_360[4].z -= 200.0f * Math_CosS(rotY);
+ this->unk_360[3].x -= 220.0f * Math_SinS(rotY);
+ this->unk_360[3].z -= 220.0f * Math_CosS(rotY);
+ Math_Vec3f_Copy(&this->unk_360[5], &this->unk_360[0]);
+ this->unk_360[5].x -= 500.0f * Math_SinS(rotY);
+ this->unk_360[5].z -= 500.0f * Math_CosS(rotY);
+ Math_Vec3f_Copy(&this->unk_360[7], &this->unk_360[1]);
+ this->unk_360[7].x -= 500.0f * Math_SinS(rotY);
+ this->unk_360[7].z -= 500.0f * Math_CosS(rotY);
+ this->unk_360[6].x -= 500.0f * Math_SinS(rotY);
+ this->unk_360[6].z -= 500.0f * Math_CosS(rotY);
+ Math_Vec3f_Copy(&this->unk_360[8], &this->unk_360[0]);
+ this->unk_360[8].x -= 700.0f * Math_SinS(rotY);
+ this->unk_360[8].z -= 700.0f * Math_CosS(rotY);
+ Math_Vec3f_Copy(&this->unk_360[10], &this->unk_360[1]);
+ this->unk_360[10].x -= 700.0f * Math_SinS(rotY);
+ this->unk_360[10].z -= 700.0f * Math_CosS(rotY);
+ this->unk_360[9].x -= 700.0f * Math_SinS(rotY);
+ this->unk_360[9].z -= 700.0f * Math_CosS(rotY);
+ this->unk_360[11] = this->unk_360[3];
+ this->unk_360[11].x += 40.0f * Math_SinS(rotY + 0x4000);
+ this->unk_360[11].z += 40.0f * Math_CosS(rotY + 0x4000);
+ this->unk_360[12] = this->unk_360[3];
+ this->unk_360[12].x += 40.0f * Math_SinS(rotY - 0x4000);
+ this->unk_360[12].z += 40.0f * Math_CosS(rotY - 0x4000);
+ this->unk_360[13] = this->unk_360[2];
+ this->unk_360[14] = this->unk_360[4];
+}
+
+s32 ObjUm_InitBandits(ObjUm* this, PlayState* play) {
+ Path* path = &play->setupPathList[this->pathIndex];
+ s16 pad;
+ Vec3s* spawnPoints;
+ EnHorse* bandit1;
+ EnHorse* bandit2;
+
+ spawnPoints = Lib_SegmentedToVirtual(path->points);
+ Audio_QueueSeqCmd(0x8000 | NA_BGM_CHASE);
+
+ bandit1 = (EnHorse*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, spawnPoints[0].x, spawnPoints[0].y,
+ spawnPoints[0].z, 0, this->dyna.actor.shape.rot.y, 0,
+ ENHORSE_PARAMS(ENHORSE_PARAM_BANDIT, ENHORSE_19));
+ this->bandit1 = bandit1;
+
+ bandit1->unk_540 = bandit1->actor.world.pos;
+
+ bandit1->unk_54C = 0xF;
+ bandit1->unk_550 = 10;
+
+ bandit1->unk_554 = this->pathIndex;
+ bandit1->unk_568 = 0.0f;
+ bandit1->unk_56C = 0.0f;
+ bandit1->unk_558 = 0;
+ bandit1->unk_55C = 40;
+ bandit1->unk_560 = 40;
+
+ bandit1->banditPosition = gZeroVec3f;
+ bandit1->unk_57C = gZeroVec3f;
+
+ bandit1->unk_588 = this->dyna.actor.shape.rot.y;
+ bandit1->curRaceWaypoint = 1;
+
+ bandit2 = (EnHorse*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, spawnPoints[1].x, spawnPoints[1].y,
+ spawnPoints[1].z, 0, this->dyna.actor.shape.rot.y, 0,
+ ENHORSE_PARAMS(ENHORSE_PARAM_BANDIT, ENHORSE_20));
+ this->bandit2 = bandit2;
+
+ bandit2->unk_540 = bandit2->actor.world.pos;
+
+ bandit2->unk_54C = 0xF;
+ bandit2->unk_550 = 8;
+
+ bandit2->unk_554 = this->pathIndex;
+ bandit2->unk_568 = 0.0f;
+ bandit2->unk_56C = 0.0f;
+ bandit2->unk_55C = 40;
+ bandit2->unk_560 = 40;
+
+ bandit2->unk_57C = gZeroVec3f;
+
+ bandit2->unk_588 = this->dyna.actor.shape.rot.y;
+ bandit2->curRaceWaypoint = 2;
+
+ this->potsLife[0] = 4;
+ this->potsLife[1] = 4;
+ this->potsLife[2] = 4;
+
+ return 0;
+}
+
+typedef struct {
+ /* 0x00 */ s32 unk_00;
+ /* 0x04 */ s32 unk_04;
+ /* 0x08 */ s32 unk_08;
+ /* 0x0C */ f32 unk_0C;
+ /* 0x10 */ s32 unk_10;
+} struct_80B7C254; // size = 0x14
+
+struct_80B7C254 D_80B7C164[] = {
+ { 2, 0, 0, 1.0f, 40 }, { 4, 1, 0, 1.0f, 40 }, { 3, 2, 0, 1.0f, 40 }, { 3, 4, 0, 1.0f, 40 },
+ { 5, 3, 1, -1.0f, 30 }, { 7, 3, 1, 1.0f, 30 }, { 0, 13, 1, -1.0f, 60 }, { 1, 14, 1, 1.0f, 60 },
+ { 13, 10, 0, 1.0f, 40 }, { 14, 8, 0, 1.0f, 40 }, { 8, 5, 0, 1.0f, 30 }, { 10, 7, 0, 1.0f, 30 },
+};
+
+// BanditAttack?
+s32 func_80B781DC(ObjUm* this, EnHorse* bandit1, EnHorse* bandit2, PlayState* play) {
+ s32 temp_v0;
+ s32 phi_s3 = -1;
+ s32 phi_s4 = 0;
+ s32 phi_s2 = 0;
+ f32 phi_f20 = 0.0f;
+ s32 i;
+ s32 mask;
+
+ for (i = 0; i < ARRAY_COUNT(D_80B7C164); i++) {
+ if (bandit1->unk_550 == D_80B7C164[i].unk_00) {
+ if (bandit2->unk_550 != D_80B7C164[i].unk_04) {
+ if (D_80B7C164[i].unk_00 != 3) {
+ if (D_80B7C164[i].unk_04 != 3 ||
+ ((mask = Player_GetMask(play)), PLAYER_MASK_CIRCUS_LEADER != mask)) {
+ phi_s3 = D_80B7C164[i].unk_04;
+ phi_s4 = D_80B7C164[i].unk_08;
+ phi_f20 = D_80B7C164[i].unk_0C;
+ phi_s2 = D_80B7C164[i].unk_10;
+ }
+ } else if (((bandit1->unk_54C != 5) || (D_80B7C164[i].unk_04 != 2)) &&
+ ((bandit1->unk_54C != 7) || (D_80B7C164[i].unk_04 != 4))) {
+ phi_s3 = D_80B7C164[i].unk_04;
+ phi_s4 = D_80B7C164[i].unk_08;
+ phi_f20 = D_80B7C164[i].unk_0C;
+ if ((2.0f * Rand_ZeroOne()) < 1.0f) {
+ phi_f20 *= -1.0f;
+ }
+ phi_s2 = D_80B7C164[i].unk_10;
+ }
+ //! FAKE:
+ ;
+ }
+ }
+ }
+
+ if (phi_s3 == -1) {
+ return 0;
+ }
+
+ bandit1->unk_540 = bandit1->actor.world.pos;
+ bandit1->unk_54C = bandit1->unk_550;
+ bandit1->unk_550 = phi_s3;
+ bandit1->unk_55C = phi_s2;
+ bandit1->unk_560 = phi_s2;
+ bandit1->unk_564 = phi_s4;
+ bandit1->unk_568 = phi_f20;
+
+ if (phi_s3 == 3) {
+ f32 rand = Rand_ZeroOne();
+
+ bandit1->unk_558 = (s32)(rand * 3.0f);
+ } else {
+ bandit1->unk_558 = 0;
+ }
+
+ return 0;
+}
+
+// ObjUm_Bandit_UpdatePosition?
+s32 func_80B783E0(ObjUm* this, PlayState* play, s32 banditIndex, EnHorse* bandit) {
+ Path* sp6C = &play->setupPathList[this->pathIndex];
+ s32 sp68;
+ Vec3s* sp64;
+ f32 phi_f12;
+ s32 phi_v1_2;
+ Vec3f sp50;
+ f32 sp4C;
+ f32 sp48;
+ f32 sp44;
+ s32 temp_a1;
+ f32 sp3C;
+ f32 phi_f14;
+
+ sp68 = sp6C->count;
+ sp64 = Lib_SegmentedToVirtual(sp6C->points);
+
+ if (sp68 == 0) {
+ return 0;
+ }
+
+ if (Math3D_Distance(&bandit->actor.world.pos, &this->dyna.actor.world.pos) < 800.0f) {
+ if (banditIndex == 0) {
+ this->flags |= OBJ_UM_FLAG_0200;
+ } else {
+ this->flags |= OBJ_UM_FLAG_0400;
+ }
+ bandit->unk_540 = bandit->actor.world.pos;
+ bandit->unk_55C = 50;
+ bandit->unk_560 = 50;
+ bandit->unk_564 = 1;
+ }
+
+ Math_Vec3s_ToVec3f(&sp50, &sp64[bandit->curRaceWaypoint]);
+
+ if (bandit->curRaceWaypoint == 0) {
+ phi_f12 = sp64[1].x - sp64[0].x;
+ phi_f14 = sp64[1].z - sp64[0].z;
+ } else {
+ if ((bandit->curRaceWaypoint + 1) == sp6C->count) {
+ phi_f12 = sp64[sp6C->count - 1].x - sp64[sp6C->count - 2].x;
+ phi_f14 = sp64[sp6C->count - 1].z - sp64[sp6C->count - 2].z;
+ } else {
+ phi_f12 = sp64[bandit->curRaceWaypoint + 1].x - sp64[bandit->curRaceWaypoint - 1].x;
+ phi_f14 = sp64[bandit->curRaceWaypoint + 1].z - sp64[bandit->curRaceWaypoint - 1].z;
+ }
+ }
+
+ temp_a1 = Math_Atan2S(phi_f12, phi_f14);
+
+ func_8017B7F8(&sp50, temp_a1, &sp4C, &sp48, &sp44);
+ if (((bandit->actor.world.pos.x * sp4C) + (sp48 * bandit->actor.world.pos.z) + sp44) > 0.0f) {
+ bandit->curRaceWaypoint++;
+ if (bandit->curRaceWaypoint >= sp68) {
+ bandit->curRaceWaypoint = 0;
+ }
+ Math_Vec3s_ToVec3f(&sp50, &sp64[bandit->curRaceWaypoint]);
+ }
+
+ bandit->actor.world.rot.y = Math_Vec3f_Yaw(&bandit->actor.world.pos, &sp50);
+ bandit->actor.speedXZ = 45.0f;
+
+ sp3C = Math_CosS(bandit->actor.world.rot.x) * bandit->actor.speedXZ;
+ bandit->actor.velocity.x = Math_SinS(bandit->actor.world.rot.y) * sp3C;
+ bandit->actor.velocity.y = Math_SinS(bandit->actor.world.rot.x) * bandit->actor.speedXZ;
+ bandit->actor.velocity.z = Math_CosS(bandit->actor.world.rot.y) * sp3C;
+
+ bandit->banditPosition.x =
+ bandit->actor.world.pos.x + (bandit->actor.velocity.x * 0.5f) + bandit->actor.colChkInfo.displacement.x;
+ bandit->banditPosition.y =
+ bandit->actor.world.pos.y + (bandit->actor.velocity.y * 0.5f) + bandit->actor.colChkInfo.displacement.y;
+ bandit->banditPosition.z =
+ bandit->actor.world.pos.z + (bandit->actor.velocity.z * 0.5f) + bandit->actor.colChkInfo.displacement.z;
+
+ phi_v1_2 = BINANG_SUB(bandit->actor.world.rot.y, bandit->actor.shape.rot.y);
+
+ if (phi_v1_2 > 0x190) {
+ phi_v1_2 = 0x190;
+ } else if (phi_v1_2 < -0x190) {
+ phi_v1_2 = -0x190;
+ }
+
+ bandit->actor.shape.rot.y = bandit->actor.shape.rot.y + phi_v1_2;
+ return 0;
+}
+
+// ObjUm_Bandit_GetCloserAndAttack
+s32 func_80B78764(ObjUm* this, PlayState* play, EnHorse* bandit1, EnHorse* bandit2) {
+ s32 pad;
+ Vec3f sp30;
+ s16 phi_v1_5;
+
+ bandit1->unk_55C--;
+ if (bandit1->unk_55C <= 0) {
+ bandit1->unk_55C = 0;
+
+ if ((bandit1->unk_550 == 3) && !(this->flags & OBJ_UM_FLAG_MINIGAME_FINISHED)) {
+ s32 potIndex = -1;
+
+ if (this->potsLife[0] != 1) {
+ potIndex = 0;
+ }
+
+ if (this->potsLife[1] != 1) {
+ if ((potIndex == -1) || (potIndex == 0 && Rand_ZeroOne() < 0.3f)) {
+ potIndex = 1;
+ }
+ }
+
+ if (this->potsLife[2] != 1) {
+ if ((potIndex == -1) || (potIndex != -1 && Rand_ZeroOne() < 0.3f)) {
+ potIndex = 2;
+ }
+ }
+
+ if (this->potsLife[potIndex] != 1) {
+ this->wasPotHit[potIndex] = true;
+ if (this->potsLife[potIndex] == 2) {
+ Audio_PlaySfxAtPos(&this->potPos[potIndex], NA_SE_EV_MILK_POT_BROKEN);
+ } else {
+ Audio_PlaySfxAtPos(&this->potPos[potIndex], NA_SE_EV_MILK_POT_DAMAGE);
+ }
+
+ this->potsLife[potIndex]--;
+ if (this->potsLife[potIndex] < 1) {
+ this->potsLife[potIndex] = 1;
+ }
+ }
+ }
+
+ func_80B781DC(this, bandit1, bandit2, play);
+ }
+
+ Math3D_Lerp(&bandit1->unk_540, &this->unk_360[bandit1->unk_550], 1.0f - ((f32)bandit1->unk_55C / bandit1->unk_560),
+ &sp30);
+ bandit1->banditPosition = sp30;
+ bandit1->unk_588 = this->dyna.actor.shape.rot.y;
+
+ if ((bandit1->unk_550 == 10) || ((bandit1->unk_550 == 8))) {
+ phi_v1_5 = bandit1->unk_588;
+ } else if (Math3D_Distance(&bandit1->actor.prevPos, &bandit1->actor.world.pos) < 10.0f) {
+ phi_v1_5 = bandit1->unk_588;
+ } else {
+ phi_v1_5 = Math_Vec3f_Yaw(&bandit1->actor.prevPos, &bandit1->actor.world.pos);
+ }
+
+ if (1) {}
+
+ phi_v1_5 -= bandit1->actor.shape.rot.y;
+ if (phi_v1_5 > 0x190) {
+ bandit1->actor.shape.rot.y += 0x190;
+ } else if (phi_v1_5 < -0x190) {
+ bandit1->actor.shape.rot.y -= 0x190;
+ } else {
+ bandit1->actor.shape.rot.y += phi_v1_5;
+ }
+
+ return 0;
+}
+
+// ObjUm_UpdateBanditsDamage?
+s32 func_80B78A54(ObjUm* this, PlayState* play, s32 arg2, EnHorse* arg3, EnHorse* arg4) {
+ if (this->banditsCollisions[arg2].base.acFlags & AC_HIT) {
+ if (arg3->unk_550 == 3) {
+ s16 sp36 =
+ Math_Vec3f_Yaw(&this->dyna.actor.world.pos, &arg3->actor.world.pos) - this->dyna.actor.shape.rot.y;
+
+ this->banditsCollisions[arg2].base.acFlags &= ~AC_HIT;
+ Audio_PlaySfxAtPos(&arg3->actor.projectedPos, NA_SE_EN_CUTBODY);
+ arg3->unk_54C = 0xF;
+
+ if (Math_SinS(sp36) > 0.0f) {
+ arg3->unk_550 = arg4->unk_550 != 10 ? 10 : 8;
+ arg3->unk_568 = -1.0f;
+ } else {
+ arg3->unk_550 = arg4->unk_550 != 8 ? 8 : 10;
+ arg3->unk_568 = 1.0f;
+ }
+
+ arg3->unk_540 = arg3->actor.world.pos;
+ arg3->unk_55C = 40;
+ arg3->unk_560 = 40;
+ arg3->unk_564 = 1;
+ if (arg3->rider != NULL) {
+ arg3->rider->actor.colorFilterTimer = 20;
+ Actor_SetColorFilter(&arg3->rider->actor, 0x4000, 0xFF, 0, 40);
+ }
+ } else {
+ if (arg3->rider != NULL) {
+ arg3->rider->actor.colorFilterTimer = 20;
+ Actor_SetColorFilter(&arg3->rider->actor, 0x4000, 0xFF, 0, 40);
+ }
+ Audio_PlaySfxAtPos(&arg3->actor.projectedPos, NA_SE_EN_CUTBODY);
+ }
+ }
+
+ return 0;
+}
+
+// ObjUm_UpdateBanditLogic?
+s32 func_80B78C18(ObjUm* this, PlayState* play) {
+ EnHorse* bandit1 = this->bandit1;
+ EnHorse* bandit2 = this->bandit2;
+
+ if (!(this->flags & OBJ_UM_FLAG_0200)) {
+ func_80B783E0(this, play, 0, bandit1);
+ } else {
+ func_80B78764(this, play, bandit1, bandit2);
+ }
+
+ if (!(this->flags & OBJ_UM_FLAG_0400)) {
+ func_80B783E0(this, play, 1, bandit2);
+ } else {
+ func_80B78764(this, play, bandit2, bandit1);
+ }
+
+ func_80B78A54(this, play, 0, bandit1, bandit2);
+ func_80B78A54(this, play, 1, bandit2, bandit1);
+ return 0;
+}
+
+s32 ObjUm_UpdateBanditsCollisions(ObjUm* this, PlayState* play) {
+ s32 pad[3];
+
+ this->banditsCollisions[0].dim.pos.x = this->bandit1->actor.world.pos.x;
+ this->banditsCollisions[0].dim.pos.y = this->bandit1->actor.world.pos.y + 70.0f;
+ this->banditsCollisions[0].dim.pos.z = this->bandit1->actor.world.pos.z;
+
+ this->banditsCollisions[1].dim.pos.x = this->bandit2->actor.world.pos.x;
+ this->banditsCollisions[1].dim.pos.y = this->bandit2->actor.world.pos.y + 70.0f;
+ this->banditsCollisions[1].dim.pos.z = this->bandit2->actor.world.pos.z;
+
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->banditsCollisions[0].base);
+ CollisionCheck_SetAC(play, &play->colChkCtx, &this->banditsCollisions[1].base);
+ return 0;
+}
+
+// ObjUm_UpdateBandits?
+s32 func_80B78DF0(ObjUm* this, PlayState* play) {
+ func_80B78C18(this, play);
+ ObjUm_UpdateBanditsCollisions(this, play);
+ return 0;
+}
+
+void ObjUm_SetupAction(ObjUm* this, ObjUmActionFunc actionFunc) {
+ this->actionFunc = actionFunc;
+}
+
+void ObjUm_SetPlayerPosition(ObjUm* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ if (this->flags & OBJ_UM_FLAG_DRAWN_FLOOR) {
+ player->actor.world.pos = this->unk_308;
+ player->actor.prevPos = this->unk_308;
+ }
+}
+
+void ObjUm_RotatePlayer(ObjUm* this, PlayState* play, s16 angle) {
+ Player* player = GET_PLAYER(play);
+
+ player->actor.shape.rot.y = player->actor.world.rot.y = player->currentYaw = this->dyna.actor.shape.rot.y + angle;
+}
+
+void func_80B78EBC(ObjUm* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ player->actor.focus.rot.x = 0;
+ player->actor.focus.rot.z = 0;
+ player->actor.focus.rot.y = player->actor.shape.rot.y;
+
+ player->unk_AAC.x = 0;
+ player->unk_AAC.y = 0;
+ player->unk_AAC.z = 0;
+
+ player->unk_AB2.x = 0;
+ player->unk_AB2.y = 0;
+ player->unk_AB2.z = 0;
+
+ player->currentYaw = player->actor.focus.rot.y;
+}
+
+void ObjUm_RotatePlayerView(ObjUm* this, PlayState* play, s16 angle) {
+ Player* player = GET_PLAYER(play);
+
+ player->actor.focus.rot.y += angle;
+}
+
+static InitChainEntry sInitChain[] = {
ICHAIN_F32(uncullZoneScale, 1200, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneDownward, 300, ICHAIN_STOP),
};
-#endif
+void ObjUm_Init(Actor* thisx, PlayState* play) {
+ s32 pad;
+ ObjUm* this = THIS;
+ s32 sp54 = true;
+ s32 i;
-extern ColliderCylinderInit D_80B7C138;
-extern InitChainEntry D_80B7C254[];
+ DynaPolyActor_Init(&this->dyna, 0);
+ this->unk_350 = 0;
-extern UNK_TYPE D_06011DF8;
-extern UNK_TYPE D_06012CC0;
+ this->unk_2C4 = this->dyna.actor.world.pos;
+ this->unk_2DC = this->dyna.actor.world.pos;
+ this->unk_308 = this->dyna.actor.world.pos;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B77770.s")
+ for (i = 0; i < MILK_POTS_COUNT; i++) {
+ this->potsLife[i] = 5;
+ this->wasPotHit[i] = false;
+ this->potPos[i] = gZeroVec3f;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B77FA4.s")
+ this->donkey = NULL;
+ this->unk_354 = 0;
+ this->unk_420 = 0;
+ this->cartBedPos = this->dyna.actor.world.pos;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B781DC.s")
+ this->unk_4CC = 0;
+ this->mouthTexIndex = 0;
+ this->flags = OBJ_UM_FLAG_NONE;
+ this->dyna.actor.gravity = -3.5f;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B783E0.s")
+ Actor_ProcessInitChain(&this->dyna.actor, sInitChain);
+ ActorShape_Init(&this->dyna.actor.shape, 0.0f, NULL, 50.0f);
+ SkelAnime_InitFlex(play, &this->skelAnime, &gUmSkel, NULL, this->jointTable, this->morphTable, UM_LIMB_MAX);
+ Animation_PlayLoop(&this->skelAnime, &gUmTrotAnim);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B78764.s")
+ this->wheelRot = 0;
+ ObjUm_DefaultAnim(this, play);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B78A54.s")
+ this->type = OBJ_UM_PARSE_TYPE(thisx);
+ this->initialPathIndex = OBJ_UM_PARSE_PATH_INDEX(thisx);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B78C18.s")
+ // if (!AliensDefeated)
+ if (!(gSaveContext.save.weekEventReg[22] & 1)) {
+ Actor_MarkForDeath(&this->dyna.actor);
+ return;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B78D08.s")
+ if (this->type == OBJ_UM_TYPE_TERMINA_FIELD) {
+ ObjUm_SetupAction(this, ObjUm_TerminaFieldIdle);
+ } else if (this->type == OBJ_UM_TYPE_RANCH) {
+ this->pathIndex = this->initialPathIndex;
+ if (gSaveContext.save.weekEventReg[31] & 0x80) {
+ // In cutscene
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B78DF0.s")
+ sp54 = false;
+ this->flags |= OBJ_UM_FLAG_0100;
+ ObjUm_SetupAction(this, func_80B7A144);
+ func_800FE484();
+ } else {
+ // Waiting for player
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/ObjUm_SetupAction.s")
+ if ((gSaveContext.save.weekEventReg[34] & 0x80) || gSaveContext.save.time >= CLOCK_TIME(19, 0) ||
+ gSaveContext.save.time <= CLOCK_TIME(6, 0) || (gSaveContext.save.weekEventReg[52] & 1) ||
+ (gSaveContext.save.weekEventReg[52] & 2)) {
+ Actor_MarkForDeath(&this->dyna.actor);
+ return;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B78E38.s")
+ this->dyna.actor.targetMode = 6;
+ this->unk_2B4 = 0;
+ ObjUm_SetupAction(this, ObjUm_RanchWait);
+ }
+ } else if (this->type == OBJ_UM_TYPE_PRE_MILK_RUN) {
+ if (!(gSaveContext.save.weekEventReg[31] & 0x80) || (gSaveContext.save.weekEventReg[52] & 1)) {
+ Actor_MarkForDeath(&this->dyna.actor);
+ return;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B78E88.s")
+ if (!(gSaveContext.save.weekEventReg[52] & 2)) {
+ this->pathIndex = this->initialPathIndex;
+ sp54 = false;
+ func_800FE484();
+ ObjUm_SetupAction(this, ObjUm_PreMilkRunStartCs);
+ this->unk_354 = 0;
+ ObjUm_RotatePlayer(this, play, 0);
+ }
+ } else if (this->type == OBJ_UM_TYPE_MILK_RUN_MINIGAME) {
+ if (!(gSaveContext.save.weekEventReg[31] & 0x80)) {
+ Actor_MarkForDeath(&this->dyna.actor);
+ return;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B78EBC.s")
+ this->pathIndex = this->initialPathIndex;
+ sp54 = false;
+ func_800FE484();
+ ObjUm_SetupAction(this, ObjUm_StartCs);
+ this->unk_354 = 0;
+ ObjUm_RotatePlayer(this, play, 0);
+ } else if (this->type == OBJ_UM_TYPE_POST_MILK_RUN) {
+ if (!(gSaveContext.save.weekEventReg[52] & 1) || (gSaveContext.save.weekEventReg[59] & 2)) {
+ Actor_MarkForDeath(&this->dyna.actor);
+ return;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B78EFC.s")
+ this->pathIndex = this->initialPathIndex;
+ sp54 = false;
+ func_800FE484();
+ ObjUm_SetupAction(this, ObjUm_PostMilkRunStartCs);
+ this->unk_354 = 0;
+ ObjUm_RotatePlayer(this, play, 0);
+ func_801A3098(NA_BGM_CLEAR_EVENT);
+ } else {
+ this->type = OBJ_UM_TYPE_TERMINA_FIELD;
+ ObjUm_SetupAction(this, ObjUm_TerminaFieldIdle);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/ObjUm_Init.s")
+ this->unk_2F8 = this->unk_2FE = gZeroVec3s;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/ObjUm_Destroy.s")
+ if (sp54) {
+ DynaPolyActor_Init(&this->dyna, 0);
+ DynaPolyActor_LoadMesh(play, &this->dyna, &object_um_Colheader_007E20);
+ } else {
+ DynaPolyActor_Init(&this->dyna, 3);
+ DynaPolyActor_LoadMesh(play, &this->dyna, &object_um_Colheader_007F50);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B79524.s")
+ if (this->dyna.bgId == BGCHECK_SCENE) {
+ Actor_MarkForDeath(&this->dyna.actor);
+ return;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B79560.s")
+ func_800C636C(play, &play->colCtx.dyna, this->dyna.bgId);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B795A0.s")
+ this->donkey =
+ (EnHorse*)Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, this->dyna.actor.world.pos.x,
+ this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0,
+ this->dyna.actor.shape.rot.y, 0, ENHORSE_PARAMS(ENHORSE_PARAM_DONKEY, ENHORSE_18));
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B79734.s")
+ if (this->donkey == NULL) {
+ Actor_MarkForDeath(&this->dyna.actor);
+ return;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B797EC.s")
+ Collider_InitAndSetCylinder(play, &this->banditsCollisions[0], &this->dyna.actor, &sCylinderInit);
+ Collider_InitAndSetCylinder(play, &this->banditsCollisions[1], &this->dyna.actor, &sCylinderInit);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7984C.s")
+void ObjUm_Destroy(Actor* thisx, PlayState* play) {
+ ObjUm* this = THIS;
+ s32 i;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B79A24.s")
+ DynaPoly_DeleteBgActor(play, &play->colCtx.dyna, this->dyna.bgId);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B79A50.s")
+ for (i = 0; i < ARRAY_COUNT(this->potPos); i++) {
+ Audio_StopSfxByPos(&this->potPos[i]);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B79BA0.s")
+ Collider_DestroyCylinder(play, &this->banditsCollisions[0]);
+ Collider_DestroyCylinder(play, &this->banditsCollisions[1]);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B79F10.s")
+// ObjUm_MarkMyDonkeyAndMyselfForDeath, ObjUm_TerminateMe, ObjUmn't, ObjUm_Asinucide
+void func_80B79524(ObjUm* this) {
+ Actor_MarkForDeath(&this->dyna.actor);
+ if (this->donkey != NULL) {
+ Actor_MarkForDeath(&this->donkey->actor);
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B79FFC.s")
+void func_80B79560(PlayState* play, ObjUm* this, s32 arg2, u16 textId) {
+ // "Thanks, I rely on you"
+ if (textId == 0x33BF) {
+ ObjUm_SetupAction(this, ObjUm_StartCs);
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A070.s")
+s32 func_80B795A0(PlayState* play, ObjUm* this, s32 arg2) {
+ s32 pad[2];
+ s32 phi_v1 = true;
+ u16 textId = this->dyna.actor.textId;
+ Player* player;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A0E0.s")
+ switch (textId) {
+ // "I'll go to town"
+ case 0x33B4:
+ // "Want a ride?"
+ case 0x33CF:
+ gSaveContext.save.weekEventReg[31] |= 0x40;
+ if (play->msgCtx.choiceIndex == 0) {
+ player = GET_PLAYER(play);
+ func_8019F208();
+ gSaveContext.save.weekEventReg[31] |= 0x80;
+ play->nextEntranceIndex = 0x64B0;
+ if (player->stateFlags1 & PLAYER_STATE1_800000) {
+ D_801BDAA0 = 1;
+ }
+ play->transitionType = TRANS_TYPE_64;
+ gSaveContext.nextTransitionType = TRANS_TYPE_03;
+ play->transitionTrigger = TRANS_TRIGGER_START;
+ phi_v1 = true;
+ } else {
+ Actor_ContinueText(play, &this->dyna.actor, 0x33B5);
+ func_8019F230();
+ func_80151BB4(play, 6);
+ phi_v1 = false;
+ }
+ break;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A144.s")
+ // "I'll go as fast as I can!"
+ case 0x33BB:
+ Actor_ContinueText(play, &this->dyna.actor, 0x33BC);
+ phi_v1 = false;
+ break;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A1B4.s")
+ // "Chase pursuers with your arrows."
+ case 0x33BC:
+ Actor_ContinueText(play, &this->dyna.actor, 0x33BD);
+ phi_v1 = false;
+ break;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A240.s")
+ // "Understand?"
+ case 0x33BD:
+ if (play->msgCtx.choiceIndex == 0) {
+ Actor_ContinueText(play, &this->dyna.actor, 0x33BE);
+ func_8019F230();
+ } else {
+ Actor_ContinueText(play, &this->dyna.actor, 0x33BF);
+ func_8019F208();
+ }
+ phi_v1 = false;
+ break;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A2AC.s")
+ // "I'll tell you again!"
+ case 0x33BE:
+ Actor_ContinueText(play, &this->dyna.actor, 0x33BC);
+ phi_v1 = false;
+ break;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A394.s")
+ return phi_v1;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A400.s")
+s32 func_80B79734(PlayState* play, ObjUm* this, s32 arg2) {
+ MessageContext* msgCtx = &play->msgCtx;
+ s32 ret = false;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A494.s")
+ switch (Message_GetState(msgCtx)) {
+ case TEXT_STATE_CLOSING:
+ func_80B79560(play, this, arg2, this->dyna.actor.textId);
+ return true;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A614.s")
+ case TEXT_STATE_CHOICE:
+ case TEXT_STATE_5:
+ if (Message_ShouldAdvance(play) && func_80B795A0(play, this, arg2)) {
+ msgCtx->msgMode = 0x43;
+ ret = true;
+ }
+ break;
+ }
+ return ret;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A7AC.s")
+u16 ObjUm_RanchGetDialogue(PlayState* play, ObjUm* this, s32 arg2) {
+ u16 textId = 0;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7A860.s")
+ if (gSaveContext.save.playerForm == PLAYER_FORM_HUMAN) {
+ if (gSaveContext.save.weekEventReg[31] & 0x40) {
+ // "Want a ride?"
+ textId = 0x33CF;
+ } else {
+ // "I'll deliver milk"
+ textId = 0x33B4;
+ }
+ } else {
+ textId = 0x33B7;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7AB78.s")
+ if (textId == 0) {
+ textId = 1;
+ }
+ return textId;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7ABE4.s")
+s32 func_80B7984C(PlayState* play, ObjUm* this, s32 arg2, s32* arg3) {
+ s16 temp_v0_2;
+ s16 phi_v1;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7AC94.s")
+ if (*arg3 == 4) {
+ return 0;
+ }
+ if (*arg3 == 2) {
+ Message_StartTextbox(play, this->dyna.actor.textId, &this->dyna.actor);
+ *arg3 = 1;
+ return 0;
+ }
+ if (*arg3 == 3) {
+ func_80151938(play, this->dyna.actor.textId);
+ *arg3 = 1;
+ return 0;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7AD34.s")
+ if (Actor_ProcessTalkRequest(&this->dyna.actor, &play->state)) {
+ *arg3 = 1;
+ return 1;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7AE58.s")
+ if (*arg3 == 1) {
+ if (func_80B79734(play, this, arg2)) {
+ *arg3 = 0;
+ }
+ return 0;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7AEFC.s")
+ phi_v1 = this->dyna.actor.yawTowardsPlayer - this->dyna.actor.shape.rot.y;
+ temp_v0_2 = ABS_ALT(phi_v1);
+ if (temp_v0_2 >= 0x4E20) {
+ return 0;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7AF30.s")
+ if ((this->dyna.actor.xyzDistToPlayerSq > SQ(100.0f)) && !this->dyna.actor.isTargeted) {
+ return 0;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7B154.s")
+ if (this->dyna.actor.xyzDistToPlayerSq <= SQ(50.0f)) {
+ if (func_800B8614(&this->dyna.actor, play, 50.0f)) {
+ this->dyna.actor.textId = ObjUm_RanchGetDialogue(play, this, arg2);
+ }
+ } else if (func_800B863C(&this->dyna.actor, play)) {
+ this->dyna.actor.textId = ObjUm_RanchGetDialogue(play, this, arg2);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7B18C.s")
+ return 0;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/ObjUm_Update.s")
+s32 func_80B79A24(s32 arg0) {
+ switch (arg0) {
+ case 1:
+ case 2:
+ case 3:
+ return true;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7B598.s")
+ default:
+ return false;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7B93C.s")
+void ObjUm_RanchWait(ObjUm* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7BABC.s")
+ this->dyna.actor.flags |= ACTOR_FLAG_1;
+ SkelAnime_Update(&this->skelAnime);
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_IDLE);
+ this->flags |= OBJ_UM_FLAG_WAITING;
+ if ((gSaveContext.save.time > CLOCK_TIME(18, 0)) && (gSaveContext.save.time <= CLOCK_TIME(19, 0))) {
+ if (!(player->stateFlags1 & PLAYER_STATE1_800000)) {
+ func_80B7984C(play, this, 0, &this->unk_2B4);
+ }
+ } else if (!func_80B79A24(this->unk_2B4) && (gSaveContext.save.time > CLOCK_TIME(19, 0))) {
+ gSaveContext.save.weekEventReg[34] |= 0x80;
+ ObjUm_SetupAction(this, ObjUm_RanchWaitPathFinished);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/func_80B7BEA4.s")
+ switch (play->msgCtx.currentTextId) {
+ default:
+ this->unk_4CC = 0;
+ this->mouthTexIndex = 0;
+ break;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Obj_Um/ObjUm_Draw.s")
+ // "I'm worried about my sister"
+ case 0x33B7:
+ // "I'll deliver milk"
+ case 0x33B4:
+ this->unk_4CC = 0;
+ this->mouthTexIndex = 1;
+ break;
+
+ // "I'll leave at 7"
+ case 0x33B5:
+ this->unk_4CC = 3;
+ this->mouthTexIndex = 1;
+ break;
+ }
+}
+
+typedef enum ObjUmPathState {
+ /* 0 */ OBJUM_PATH_STATE_0,
+ /* 1 */ OBJUM_PATH_STATE_1,
+ /* 2 */ OBJUM_PATH_STATE_FINISH,
+ /* 3 */ OBJUM_PATH_STATE_3,
+ /* 4 */ OBJUM_PATH_STATE_4,
+} ObjUmPathState;
+
+ObjUmPathState ObjUm_UpdatePath(ObjUm* this, PlayState* play) {
+ Path* path = &play->setupPathList[this->pathIndex];
+ s32 pathCount;
+ Vec3s* pathPoints;
+ f32 xDiff;
+ f32 zDiff;
+ Vec3f sp50;
+ f32 sp4C;
+ f32 sp48;
+ f32 sp44;
+ s32 angle;
+ ObjUmPathState sp3C;
+ s16 yawDiff;
+
+ pathCount = path->count;
+ pathPoints = Lib_SegmentedToVirtual(path->points);
+ sp3C = OBJUM_PATH_STATE_0;
+
+ if (pathCount == 0) {
+ return 0;
+ }
+
+ Math_Vec3s_ToVec3f(&sp50, &pathPoints[this->pointIndex]);
+
+ if (this->pointIndex == 0) {
+ xDiff = pathPoints[1].x - pathPoints[0].x;
+ zDiff = pathPoints[1].z - pathPoints[0].z;
+ } else if ((this->pointIndex + 1) == path->count) {
+ xDiff = pathPoints[path->count - 1].x - pathPoints[path->count - 2].x;
+ zDiff = pathPoints[path->count - 1].z - pathPoints[path->count - 2].z;
+ } else {
+ xDiff = pathPoints[this->pointIndex + 1].x - pathPoints[this->pointIndex - 1].x;
+ zDiff = pathPoints[this->pointIndex + 1].z - pathPoints[this->pointIndex - 1].z;
+ }
+
+ angle = Math_Atan2S(xDiff, zDiff);
+
+ func_8017B7F8(&sp50, angle, &sp4C, &sp48, &sp44);
+ if (((this->dyna.actor.world.pos.x * sp4C) + (sp48 * this->dyna.actor.world.pos.z) + sp44) > 0.0f) {
+ this->pointIndex++;
+
+ if (this->pointIndex >= (pathCount - 7)) {
+ sp3C = OBJUM_PATH_STATE_3;
+ }
+ if (this->pointIndex >= (pathCount - 3)) {
+ sp3C = OBJUM_PATH_STATE_1;
+ }
+ if (this->pointIndex >= (pathCount - 2)) {
+ sp3C = OBJUM_PATH_STATE_4;
+ }
+ if (this->pointIndex >= pathCount) {
+ this->pointIndex = 0;
+ sp3C = OBJUM_PATH_STATE_FINISH;
+ }
+
+ Math_Vec3s_ToVec3f(&sp50, &pathPoints[this->pointIndex]);
+ }
+
+ if (this->donkey != NULL) {
+ this->dyna.actor.world.rot.y = Math_Vec3f_Yaw(&this->dyna.actor.world.pos, &sp50);
+ func_800F415C(&this->donkey->actor, &sp50, 0x190);
+
+ if (1) {}
+
+ yawDiff = this->donkey->actor.shape.rot.y - this->dyna.actor.shape.rot.y;
+ if (fabsf(yawDiff) < 2730.0f) {
+ if (fabsf(yawDiff) < 100.0f) {
+ this->dyna.actor.shape.rot.y = this->donkey->actor.shape.rot.y;
+ } else if (yawDiff > 0) {
+ this->dyna.actor.shape.rot.y = this->dyna.actor.shape.rot.y + 0x64;
+ yawDiff = 0x64;
+ } else if (yawDiff < 0) {
+ this->dyna.actor.shape.rot.y = this->dyna.actor.shape.rot.y - 0x64;
+ yawDiff = -0x64;
+ }
+ } else if (yawDiff > 0) {
+ this->dyna.actor.shape.rot.y = this->dyna.actor.shape.rot.y + 0x190;
+ yawDiff = 0x190;
+ } else if (yawDiff < 0) {
+ this->dyna.actor.shape.rot.y = this->dyna.actor.shape.rot.y - 0x190;
+ yawDiff = -0x190;
+ }
+
+ if (this->flags & (OBJ_UM_FLAG_0010 | OBJ_UM_FLAG_0004)) {
+ ObjUm_RotatePlayerView(this, play, yawDiff);
+ }
+ }
+
+ if (this->currentAnimIndex == OBJ_UM_ANIM_TROT) {
+ this->dyna.actor.speedXZ = 4.0f;
+ } else if (this->currentAnimIndex == OBJ_UM_ANIM_GALLOP) {
+ this->dyna.actor.speedXZ = 8.0f;
+ }
+
+ return sp3C;
+}
+
+void ObjUm_RanchWaitPathFinished(ObjUm* this, PlayState* play) {
+ this->wheelRot += 0x3E8;
+ this->flags &= ~OBJ_UM_FLAG_WAITING;
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_TROT);
+
+ switch (ObjUm_UpdatePath(this, play)) {
+ case OBJUM_PATH_STATE_1:
+ case OBJUM_PATH_STATE_FINISH:
+ if (gSaveContext.save.weekEventReg[31] & 0x80) {
+ ActorCutscene_Stop(this->dyna.actor.cutscene);
+ play->nextEntranceIndex = 0x3E50;
+ play->transitionType = TRANS_TYPE_64;
+ gSaveContext.nextTransitionType = TRANS_TYPE_03;
+ play->transitionTrigger = TRANS_TRIGGER_START;
+ } else {
+ func_80B79524(this);
+ }
+ break;
+
+ default:
+ Actor_MoveWithGravity(&this->dyna.actor);
+ break;
+ }
+}
+
+void ObjUm_RanchStartCs(ObjUm* this, PlayState* play) {
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_IDLE);
+
+ if (ActorCutscene_GetCanPlayNext(this->dyna.actor.cutscene)) {
+ ActorCutscene_StartAndSetUnkLinkFields(this->dyna.actor.cutscene, &this->dyna.actor);
+ this->lastTime = gSaveContext.save.time;
+ ObjUm_SetupAction(this, func_80B7A0E0);
+ } else {
+ ActorCutscene_SetIntentToPlay(this->dyna.actor.cutscene);
+ }
+}
+
+void func_80B7A070(ObjUm* this, PlayState* play) {
+ ObjUm_RanchWaitPathFinished(this, play);
+ ObjUm_RotatePlayer(this, play, 0);
+
+ switch (play->msgCtx.currentTextId) {
+ case 0x33B6:
+ this->unk_4CC = 1;
+ this->mouthTexIndex = 1;
+ break;
+
+ default:
+ this->unk_4CC = 0;
+ this->mouthTexIndex = 0;
+ break;
+ }
+}
+
+void func_80B7A0E0(ObjUm* this, PlayState* play) {
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_IDLE);
+ if (gSaveContext.save.time != this->lastTime) {
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_TROT);
+ ObjUm_SetupAction(this, func_80B7A070);
+ }
+}
+
+void func_80B7A144(ObjUm* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ ObjUm_SetPlayerPosition(this, play);
+ this->flags |= OBJ_UM_FLAG_0100;
+ this->flags |= OBJ_UM_FLAG_0004;
+ player->stateFlags1 |= PLAYER_STATE1_20;
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_IDLE);
+ ObjUm_SetupAction(this, ObjUm_RanchStartCs);
+}
+
+void ObjUm_PreMilkRunDialogueHandler(ObjUm* this, PlayState* play) {
+ ObjUm_SetPlayerPosition(this, play);
+ this->flags |= OBJ_UM_FLAG_0004;
+
+ switch (play->msgCtx.currentTextId) {
+ case 0x33B8:
+ this->unk_4CC = 0;
+ this->mouthTexIndex = 3;
+ break;
+
+ case 0x33B9:
+ this->unk_4CC = 2;
+ this->mouthTexIndex = 0;
+ break;
+
+ default:
+ this->flags &= ~OBJ_UM_FLAG_LOOK_BACK;
+ this->unk_4CC = 0;
+ this->mouthTexIndex = 0;
+ break;
+ }
+}
+
+void func_80B7A240(ObjUm* this, PlayState* play) {
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_IDLE);
+ if (gSaveContext.save.time != this->lastTime) {
+ ObjUm_SetupAction(this, func_80B7A2AC);
+ }
+
+ this->lastTime = gSaveContext.save.time;
+ ObjUm_PreMilkRunDialogueHandler(this, play);
+}
+
+void func_80B7A2AC(ObjUm* this, PlayState* play) {
+ this->wheelRot += 0x3E8;
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_TROT);
+
+ switch (ObjUm_UpdatePath(this, play)) {
+ case OBJUM_PATH_STATE_1:
+ case OBJUM_PATH_STATE_FINISH:
+ play->nextEntranceIndex = 0xCE40;
+ play->transitionType = TRANS_TYPE_64;
+ gSaveContext.nextTransitionType = TRANS_TYPE_03;
+ play->transitionTrigger = TRANS_TRIGGER_START;
+ break;
+
+ default:
+ if (gSaveContext.save.time == this->lastTime) {
+ ObjUm_SetupAction(this, func_80B7A240);
+ }
+
+ this->lastTime = gSaveContext.save.time;
+ Actor_MoveWithGravity(&this->dyna.actor);
+ ObjUm_PreMilkRunDialogueHandler(this, play);
+ break;
+ }
+}
+
+void func_80B7A394(ObjUm* this, PlayState* play) {
+ ObjUm_SetPlayerPosition(this, play);
+ this->flags |= OBJ_UM_FLAG_0004;
+ if (gSaveContext.save.time != this->lastTime) {
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_TROT);
+ ObjUm_SetupAction(this, func_80B7A2AC);
+ }
+}
+
+void ObjUm_PreMilkRunStartCs(ObjUm* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ ObjUm_SetPlayerPosition(this, play);
+ this->flags |= OBJ_UM_FLAG_0004;
+ player->stateFlags1 |= PLAYER_STATE1_20;
+ if (ActorCutscene_GetCanPlayNext(this->dyna.actor.cutscene)) {
+ ActorCutscene_StartAndSetUnkLinkFields(this->dyna.actor.cutscene, &this->dyna.actor);
+ this->lastTime = gSaveContext.save.time;
+ ObjUm_SetupAction(this, func_80B7A394);
+ } else {
+ ActorCutscene_SetIntentToPlay(this->dyna.actor.cutscene);
+ }
+}
+
+void ObjUm_RunMinigame(ObjUm* this, PlayState* play) {
+ ObjUm_SetPlayerPosition(this, play);
+ ObjUm_RotatePlayer(this, play, 0x7FFF);
+ this->wheelRot += 0x7D0;
+ this->flags |= OBJ_UM_FLAG_0010;
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_GALLOP);
+
+ switch (ObjUm_UpdatePath(this, play)) {
+ case OBJUM_PATH_STATE_1:
+ case OBJUM_PATH_STATE_FINISH:
+ gSaveContext.seqIndex = 0xFF;
+ gSaveContext.save.weekEventReg[31] &= (u8)~0x80;
+ gSaveContext.nightSeqIndex = 0xFF;
+
+ if (!(gSaveContext.save.weekEventReg[52] & 1) && !(gSaveContext.save.weekEventReg[52] & 2)) {
+ if (!this->areAllPotsBroken) {
+ play->nextEntranceIndex = 0x3E60;
+ play->transitionType = TRANS_TYPE_64;
+ gSaveContext.nextTransitionType = TRANS_TYPE_03;
+ play->transitionTrigger = TRANS_TRIGGER_START;
+ gSaveContext.save.weekEventReg[52] |= 1;
+ gSaveContext.save.weekEventReg[52] &= (u8)~2;
+ } else {
+ play->nextEntranceIndex = 0x6480;
+ play->transitionType = TRANS_TYPE_64;
+ gSaveContext.nextTransitionType = TRANS_TYPE_03;
+ play->transitionTrigger = TRANS_TRIGGER_START;
+ gSaveContext.save.weekEventReg[52] |= 2;
+ gSaveContext.save.weekEventReg[52] &= (u8)~1;
+ }
+ }
+ break;
+
+ default:
+ Actor_MoveWithGravity(&this->dyna.actor);
+ func_80B78DF0(this, play);
+ break;
+ }
+}
+
+void func_80B7A614(ObjUm* this, PlayState* play) {
+ s32 pad;
+
+ ObjUm_SetPlayerPosition(this, play);
+ ObjUm_RotatePlayer(this, play, 0x7FFF);
+ this->wheelRot += 0x7D0;
+ this->flags |= OBJ_UM_FLAG_0010;
+ this->flags |= OBJ_UM_FLAG_PLAYING_MINIGAME;
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_GALLOP);
+
+ if (ObjUm_UpdatePath(this, play) == OBJUM_PATH_STATE_3 && this->unk_4DC == 0) {
+ this->unk_4DC = 1;
+ } else if (this->unk_4DC > 0) {
+ if (this->unk_4DC == 1) {
+ s32 i;
+
+ this->areAllPotsBroken = true;
+
+ for (i = 0; i < ARRAY_COUNT(this->potsLife); i++) {
+ if (this->potsLife[i] != 1) {
+ this->areAllPotsBroken = false;
+ break;
+ }
+ }
+
+ this->flags |= OBJ_UM_FLAG_MINIGAME_FINISHED;
+ }
+
+ this->unk_4DC++;
+ }
+
+ if (this->flags & OBJ_UM_FLAG_MINIGAME_FINISHED) {
+ s32 sp20 = ActorCutscene_GetAdditionalCutscene(this->dyna.actor.cutscene);
+
+ if (this->areAllPotsBroken) {
+ sp20 = ActorCutscene_GetAdditionalCutscene(sp20);
+ }
+ if (ActorCutscene_GetCanPlayNext(sp20)) {
+ ActorCutscene_StartAndSetUnkLinkFields(sp20, &this->dyna.actor);
+ ObjUm_SetupAction(this, ObjUm_RunMinigame);
+ this->flags &= ~OBJ_UM_FLAG_PLAYING_MINIGAME;
+ } else {
+ ActorCutscene_SetIntentToPlay(sp20);
+ }
+ }
+
+ Actor_MoveWithGravity(&this->dyna.actor);
+ func_80B78DF0(this, play);
+}
+
+void func_80B7A7AC(ObjUm* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ this->unk_4DC = 0;
+ this->areAllPotsBroken = false;
+ player->stateFlags1 &= ~PLAYER_STATE1_20;
+ ObjUm_SetPlayerPosition(this, play);
+ ObjUm_RotatePlayer(this, play, 0x7FFF);
+ func_80B78EBC(this, play);
+ this->flags |= OBJ_UM_FLAG_0010;
+ func_80B78DF0(this, play);
+ this->flags |= 4;
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_GALLOP);
+ ObjUm_SetupAction(this, func_80B7A614);
+}
+
+void func_80B7A860(ObjUm* this, PlayState* play) {
+ ObjUm_SetPlayerPosition(this, play);
+ ObjUm_RotatePlayer(this, play, 0);
+ this->flags |= OBJ_UM_FLAG_0004;
+
+ if (play->csCtx.frames == 449) {
+ ObjUm_InitBandits(this, play);
+ } else if (play->csCtx.frames >= 450) {
+ func_80B78DF0(this, play);
+ }
+
+ if (play->csCtx.state == 0) {
+ ActorCutscene_Stop(this->dyna.actor.cutscene);
+ ObjUm_SetupAction(this, func_80B7A7AC);
+ }
+
+ switch (play->msgCtx.currentTextId) {
+ case 0x33BA:
+ this->unk_4CC = 2;
+ this->mouthTexIndex = 3;
+ break;
+
+ // "We'll go through here as fast as we can"
+ case 0x33BB:
+ if ((fabsf(this->skelAnime.curFrame) < 0.008f) && !(this->flags & OBJ_UM_FLAG_1000)) {
+ this->flags |= OBJ_UM_FLAG_1000;
+ this->unk_4CC = 4;
+ this->mouthTexIndex = 0;
+ } else if (fabsf(this->skelAnime.morphWeight) < 0.008f) {
+ this->unk_4CC = 2;
+ this->mouthTexIndex = 2;
+ } else {
+ this->unk_4CC = 5;
+ this->mouthTexIndex = 0;
+ }
+
+ this->flags |= OBJ_UM_FLAG_LOOK_BACK;
+ break;
+
+ // "Chase pursuers with your arrows"
+ case 0x33BC:
+ if ((fabsf(this->skelAnime.curFrame) < 0.008f) && !(this->flags & OBJ_UM_FLAG_1000)) {
+ this->flags |= OBJ_UM_FLAG_1000;
+ this->unk_4CC = 4;
+ this->mouthTexIndex = 0;
+ } else if (fabsf(this->skelAnime.morphWeight) < 0.008f) {
+ this->unk_4CC = 2;
+ this->mouthTexIndex = 2;
+ } else {
+ this->unk_4CC = 5;
+ this->mouthTexIndex = 0;
+ }
+ this->flags |= OBJ_UM_FLAG_LOOK_BACK;
+ break;
+
+ // "Understand?"
+ case 0x33BD:
+ if ((fabsf(this->skelAnime.curFrame) < 0.008f) && !(this->flags & OBJ_UM_FLAG_1000)) {
+ this->flags |= OBJ_UM_FLAG_1000;
+ this->unk_4CC = 4;
+ this->mouthTexIndex = 0;
+ } else if (fabsf(this->skelAnime.morphWeight) < 0.008f) {
+ this->unk_4CC = 2;
+ } else {
+ this->unk_4CC = 5;
+ }
+ this->mouthTexIndex = 0;
+ this->unk_4D8 = 0;
+ this->flags |= OBJ_UM_FLAG_LOOK_BACK;
+ break;
+
+ case 0x33BE:
+ this->flags |= OBJ_UM_FLAG_LOOK_BACK;
+ this->unk_4CC = 2;
+ this->mouthTexIndex = 3;
+ break;
+
+ case 0x33BF:
+ this->unk_4D8++;
+ if ((fabsf(this->skelAnime.morphWeight) < 0.008f) && this->unk_4D8 >= 6) {
+ this->unk_4CC = 0;
+ this->mouthTexIndex = 0;
+ } else {
+ this->unk_4CC = 2;
+ this->mouthTexIndex = 2;
+ }
+ this->flags &= ~OBJ_UM_FLAG_LOOK_BACK;
+ break;
+
+ default:
+ this->unk_4CC = 0;
+ this->mouthTexIndex = 0;
+ break;
+ }
+}
+
+void func_80B7AB78(ObjUm* this, PlayState* play) {
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_IDLE);
+ if (gSaveContext.save.time != this->lastTime) {
+ ObjUm_SetupAction(this, func_80B7ABE4);
+ }
+
+ this->lastTime = gSaveContext.save.time;
+ func_80B7A860(this, play);
+}
+
+void func_80B7ABE4(ObjUm* this, PlayState* play) {
+ this->wheelRot += 0x3E8;
+
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_TROT);
+ switch (ObjUm_UpdatePath(this, play)) {
+ case OBJUM_PATH_STATE_FINISH:
+ func_80B79524(this);
+ break;
+
+ default:
+ if (gSaveContext.save.time == this->lastTime) {
+ ObjUm_SetupAction(this, func_80B7AB78);
+ }
+
+ this->lastTime = gSaveContext.save.time;
+ Actor_MoveWithGravity(&this->dyna.actor);
+ func_80B7A860(this, play);
+ break;
+ }
+}
+
+void ObjUm_StartCs(ObjUm* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ player->stateFlags1 |= PLAYER_STATE1_20;
+ ObjUm_SetPlayerPosition(this, play);
+ ObjUm_RotatePlayer(this, play, 0);
+ this->flags |= OBJ_UM_FLAG_0004;
+
+ if (ActorCutscene_GetCanPlayNext(this->dyna.actor.cutscene)) {
+ ActorCutscene_StartAndSetUnkLinkFields(this->dyna.actor.cutscene, &this->dyna.actor);
+ this->lastTime = gSaveContext.save.time;
+ ObjUm_SetupAction(this, func_80B7ABE4);
+ } else {
+ ActorCutscene_SetIntentToPlay(this->dyna.actor.cutscene);
+ }
+}
+
+void ObjUm_PostMilkRunWaitPathFinished(ObjUm* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ player->stateFlags1 |= PLAYER_STATE1_20;
+ ObjUm_SetPlayerPosition(this, play);
+ ObjUm_RotatePlayer(this, play, 0);
+ this->flags |= OBJ_UM_FLAG_0004;
+ this->wheelRot += 0x3E8;
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_TROT);
+
+ if ((ObjUm_UpdatePath(this, play) == OBJUM_PATH_STATE_4) && !(gSaveContext.save.weekEventReg[59] & 2)) {
+ ActorCutscene_Stop(this->dyna.actor.cutscene);
+ Audio_SetCutsceneFlag(false);
+ gSaveContext.save.weekEventReg[59] |= 2;
+ gSaveContext.nextCutsceneIndex = 0xFFF3;
+ play->nextEntranceIndex = 0x5400;
+ play->transitionType = TRANS_TYPE_64;
+ gSaveContext.nextTransitionType = TRANS_TYPE_03;
+ play->transitionTrigger = TRANS_TRIGGER_START;
+ gSaveContext.save.time += CLOCK_TIME(1, 0) + 2;
+ }
+ Actor_MoveWithGravity(&this->dyna.actor);
+}
+
+void ObjUm_PostMilkRunStartCs(ObjUm* this, PlayState* play) {
+ Player* player = GET_PLAYER(play);
+
+ player->stateFlags1 |= PLAYER_STATE1_20;
+ ObjUm_SetPlayerPosition(this, play);
+ ObjUm_RotatePlayer(this, play, 0);
+ this->flags |= OBJ_UM_FLAG_0004;
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_IDLE);
+
+ if (ActorCutscene_GetCanPlayNext(this->dyna.actor.cutscene)) {
+ ActorCutscene_StartAndSetUnkLinkFields(this->dyna.actor.cutscene, &this->dyna.actor);
+ ObjUm_SetupAction(this, ObjUm_PostMilkRunWaitPathFinished);
+ } else {
+ ActorCutscene_SetIntentToPlay(this->dyna.actor.cutscene);
+ }
+}
+
+void ObjUm_TerminaFieldIdle(ObjUm* this, PlayState* play) {
+ ObjUm_UpdateAnim(this, play, OBJ_UM_ANIM_IDLE);
+ SkelAnime_Update(&this->skelAnime);
+}
+
+void func_80B7AF30(ObjUm* this, PlayState* play) {
+ if (!(this->flags & OBJ_UM_FLAG_0001)) {
+ this->dyna.actor.shape.rot.x = 0;
+ this->dyna.actor.shape.rot.z = 0;
+ } else {
+ CollisionPoly* sp44;
+ s32 pad[2];
+ Vec3f sp30;
+
+ this->flags &= ~OBJ_UM_FLAG_0001;
+
+ if (1) {}
+
+ this->unk_2D0 = this->unk_2C4;
+ this->unk_2E8 = this->unk_2DC;
+
+ this->unk_2D0.y = BgCheck_EntityRaycastFloor1(&play->colCtx, &sp44, &this->unk_2C4);
+ if (this->unk_2D0.y == BGCHECK_Y_MIN) {
+ this->unk_2D0.y = this->dyna.actor.floorHeight;
+ }
+
+ if (1) {}
+
+ this->unk_2E8.y = BgCheck_EntityRaycastFloor1(&play->colCtx, &sp44, &this->unk_2DC);
+ if (this->unk_2E8.y == BGCHECK_Y_MIN) {
+ this->unk_2E8.y = this->dyna.actor.floorHeight;
+ }
+
+ sp30.x = (this->unk_2D0.x + this->unk_2E8.x) * 0.5f;
+ sp30.y = (this->unk_2D0.y + this->unk_2E8.y) * 0.5f;
+ sp30.z = (this->unk_2D0.z + this->unk_2E8.z) * 0.5f;
+
+ this->dyna.actor.shape.rot.x =
+ (s16)Math_Atan2S(sp30.y - this->dyna.actor.world.pos.y, sqrtf(SQ(sp30.x - this->dyna.actor.world.pos.x) +
+ SQ(sp30.z - this->dyna.actor.world.pos.z)));
+ this->dyna.actor.shape.rot.z = (s16)-Math_Atan2S(
+ sp30.y - this->unk_2D0.y, sqrtf(SQ(sp30.x - this->unk_2D0.x) + SQ(sp30.z - this->unk_2D0.z)));
+ if (this->flags & OBJ_UM_FLAG_MOVING) {
+ this->dyna.actor.shape.rot.x += BINANG_SUB((Rand_ZeroOne() * 100.0f), 50.0f);
+ this->dyna.actor.shape.rot.z += BINANG_SUB((Rand_ZeroOne() * 100.0f), 50.0f);
+ }
+ }
+}
+
+void ObjUm_DefaultAnim(ObjUm* this, PlayState* play) {
+ Animation_PlayOnce(&this->skelAnime, &gUmTrotAnim);
+ this->currentAnimIndex = OBJ_UM_ANIM_TROT;
+}
+
+typedef struct {
+ /* 0x00 */ AnimationHeader* anim;
+ /* 0x04 */ s32 doesMove; // `true` if the animation is intended to be used while the actor is moving
+} struct_80B7C25C; // size = 0x08
+
+struct_80B7C25C sUmAnims[] = {
+ { &gUmTrotAnim, true }, // OBJ_UM_ANIM_TROT
+ { &gUmGallopAnim, true }, // OBJ_UM_ANIM_GALLOP
+ { &gUmIdleAnim, false }, // OBJ_UM_ANIM_IDLE
+ { NULL, false }, // OBJ_UM_ANIM_3
+ { &gUmLookBackAnim, false }, // OBJ_UM_ANIM_LOOK_BACK
+};
+
+void ObjUm_UpdateAnim(ObjUm* this, PlayState* play, ObjUmAnimimations index) {
+ s32 changeAnim;
+ s32 temp;
+ s32 indexTemp = index;
+ f32 animPlaybackSpeed = 0.0f;
+
+ if (sUmAnims[index].doesMove) {
+ this->flags |= OBJ_UM_FLAG_MOVING;
+ } else {
+ this->flags &= ~OBJ_UM_FLAG_MOVING;
+ }
+
+ if (index == OBJ_UM_ANIM_TROT) {
+ animPlaybackSpeed = this->dyna.actor.speedXZ * 0.25f;
+ } else if (index == OBJ_UM_ANIM_GALLOP) {
+ animPlaybackSpeed = this->dyna.actor.speedXZ * 0.2f;
+ } else if (index == OBJ_UM_ANIM_IDLE) {
+ animPlaybackSpeed = 1.0f;
+ }
+ this->skelAnime.playSpeed = animPlaybackSpeed;
+
+ if (this->flags & OBJ_UM_FLAG_LOOK_BACK) {
+ this->skelAnime.playSpeed = 1.0f;
+ index = OBJ_UM_ANIM_MINUS_1;
+ }
+
+ changeAnim = (index != this->currentAnimIndex);
+ if (SkelAnime_Update(&this->skelAnime) || changeAnim) {
+ this->currentAnimIndex = index;
+
+ if (index != OBJ_UM_ANIM_MINUS_1) {
+ if (this->donkey != NULL) {
+ this->donkey->unk_538 = index;
+ }
+
+ if (changeAnim) {
+ Animation_MorphToPlayOnce(&this->skelAnime, sUmAnims[index].anim, -3.0f);
+ } else {
+ Animation_PlayOnce(&this->skelAnime, sUmAnims[index].anim);
+ }
+ } else {
+ EnHorse* donkey = this->donkey;
+
+ if (donkey != NULL) {
+ donkey->unk_538 = indexTemp;
+ }
+
+ if (changeAnim) {
+ temp = 3 - index; // OBJ_UM_ANIM_LOOK_BACK
+ Animation_MorphToPlayOnce(&this->skelAnime, sUmAnims[temp].anim, -10.0f);
+ } else {
+ temp = 3 - index; // OBJ_UM_ANIM_LOOK_BACK
+ Animation_PlayOnce(&this->skelAnime, sUmAnims[temp].anim);
+ }
+ }
+ }
+
+ if (this->wheelRot / 0x199A != this->unk_420) {
+ this->unk_420 = this->wheelRot / 0x199A;
+ //! FAKE
+ if (!&sUmAnims[0]) {}
+ Actor_PlaySfxAtPos(&this->dyna.actor, NA_SE_EV_CART_WHEEL);
+ }
+}
+
+void ObjUm_Update(Actor* thisx, PlayState* play) {
+ ObjUm* this = THIS;
+
+ this->actionFunc(this, play);
+ this->unk_350++;
+ Actor_UpdateBgCheckInfo(play, &this->dyna.actor, 0.0f, 0.0f, 0.0f, 0x1C);
+
+ if (this->donkey != NULL) {
+ this->donkey->actor.world.pos.x = this->dyna.actor.world.pos.x;
+ this->donkey->actor.world.pos.y = this->dyna.actor.floorHeight;
+ this->donkey->actor.world.pos.z = this->dyna.actor.world.pos.z;
+ }
+
+ if (this->flags & OBJ_UM_FLAG_0010) {
+ func_80123F2C(play, 0x63);
+ this->flags &= ~OBJ_UM_FLAG_0010;
+ } else if (this->flags & OBJ_UM_FLAG_0004) {
+ func_80123F2C(play, -3);
+ this->flags &= ~OBJ_UM_FLAG_0004;
+ }
+
+ if (this->flags & OBJ_UM_FLAG_0100) {
+ this->flags &= ~OBJ_UM_FLAG_0100;
+ ObjUm_RotatePlayer(this, play, 0);
+ func_80B78EBC(this, play);
+ }
+
+ func_80B7AF30(this, play);
+ switch (this->unk_4CC) {
+ case 0:
+ switch (this->eyeTexIndex) {
+ case 0:
+ if (Rand_ZeroOne() < 0.025f) {
+ this->eyeTexIndex = 1;
+ }
+ break;
+
+ case 1:
+ if (Rand_ZeroOne() < 0.6f) {
+ this->eyeTexIndex = 2;
+ }
+ break;
+
+ case 2:
+ if (Rand_ZeroOne() < 0.6f) {
+ this->eyeTexIndex = 0;
+ }
+ break;
+
+ default:
+ this->eyeTexIndex = 0;
+ break;
+ }
+ break;
+
+ case 1:
+ this->eyeTexIndex = 3;
+ break;
+ case 2:
+ this->eyeTexIndex = 4;
+ break;
+ case 3:
+ this->eyeTexIndex = 5;
+ break;
+ case 4:
+ this->eyeTexIndex = 2;
+ break;
+ case 5:
+ this->eyeTexIndex = 0;
+ break;
+ default:
+ this->unk_4CC = 0;
+ this->eyeTexIndex = 0;
+ break;
+ }
+}
+
+s32 ObjUm_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) {
+ ObjUm* this = THIS;
+ Player* player = GET_PLAYER(play);
+ s32 pad;
+ s16 temp_v0_3;
+ Vec3f sp5C = { 4223.0f, -979.0f, 4098.0f };
+ Vec3f sp50 = { 4223.0f, -980.0f, -4083.0f };
+
+ if ((limbIndex >= UM_LIMB_CREMIA_ROOT) && (this->type == OBJ_UM_TYPE_TERMINA_FIELD)) {
+ *dList = NULL;
+ return false;
+ }
+
+ if (limbIndex == UM_LIMB_CREMIA_HEAD) {
+ OPEN_DISPS(play->state.gfxCtx);
+
+ gSPSegment(POLY_OPA_DISP++, 0x08, Lib_SegmentedToVirtual(sEyeTextures[this->eyeTexIndex]));
+ gSPSegment(POLY_OPA_DISP++, 0x09, Lib_SegmentedToVirtual(sMouthTextures[this->mouthTexIndex]));
+
+ CLOSE_DISPS(play->state.gfxCtx);
+ }
+
+ if (limbIndex == UM_LIMB_WAGON_RIGHT_WHEEL) {
+ if (this->flags & OBJ_UM_FLAG_MOVING) {
+ rot->x = -this->wheelRot;
+ }
+ Matrix_MultVec3f(&sp5C, &this->unk_2C4);
+ } else if (limbIndex == UM_LIMB_WAGON_LEFT_WHEEL) {
+ if (this->flags & OBJ_UM_FLAG_MOVING) {
+ rot->x = this->wheelRot;
+ }
+ Matrix_MultVec3f(&sp50, &this->unk_2DC);
+ } else if ((limbIndex == UM_LIMB_CREMIA_HEAD) && (this->flags & OBJ_UM_FLAG_WAITING)) {
+ if (SubS_AngleDiffLessEqual(this->dyna.actor.shape.rot.y, 0x4E20, this->dyna.actor.yawTowardsPlayer) &&
+ (this->dyna.actor.xzDistToPlayer < 500.0f)) {
+ s16 sp3E;
+ Vec3f sp30 = player->actor.world.pos;
+
+ sp30.y = player->bodyPartsPos[7].y + 3.0f;
+ sp3E = Math_Vec3f_Yaw(&this->dyna.actor.focus.pos, &sp30) - this->dyna.actor.shape.rot.y;
+ temp_v0_3 = Math_Atan2S(
+ this->dyna.actor.focus.pos.y - sp30.y,
+ Math3D_XZLength(sp30.x - this->dyna.actor.focus.pos.x, sp30.z - this->dyna.actor.focus.pos.z));
+ this->unk_2FE.x = rot->x + sp3E;
+ this->unk_2FE.y = rot->y;
+ this->unk_2FE.z = rot->z + temp_v0_3;
+ Math_SmoothStepToS(&this->unk_2F8.x, this->unk_2FE.x, 4, 0x3E8, 1);
+ Math_SmoothStepToS(&this->unk_2F8.z, this->unk_2FE.z, 4, 0x3E8, 1);
+ this->unk_2F8.y = rot->y;
+ rot->x = this->unk_2F8.x;
+ rot->z = this->unk_2F8.z;
+ } else {
+ this->unk_2FE.x = rot->x;
+ this->unk_2FE.y = rot->y;
+ this->unk_2FE.z = rot->z;
+ Math_SmoothStepToS(&this->unk_2F8.x, this->unk_2FE.x, 4, 0x3E8, 1);
+ Math_SmoothStepToS(&this->unk_2F8.z, this->unk_2FE.z, 4, 0x3E8, 1);
+ this->unk_2F8.y = rot->y;
+ rot->x = this->unk_2F8.x;
+ rot->z = this->unk_2F8.z;
+ }
+ } else if ((limbIndex == UM_LIMB_WAGON_CART_COVER) && (this->flags & OBJ_UM_FLAG_PLAYING_MINIGAME)) {
+ *dList = NULL;
+ }
+
+ return false;
+}
+
+void ObjUm_SpawnFragments(PlayState* play, Vec3f* potPos) {
+ Vec3f sp8C = { 0.0f, -1.0f, 0.0f };
+ Gfx* potFragments[] = { object_um_DL_000040, object_um_DL_000910, object_um_DL_0011E0 };
+ s32 i;
+ Vec3f sp70;
+
+ EffectSsHitmark_SpawnFixedScale(play, 0, potPos);
+
+ for (i = 0; i < 20; i++) {
+ sp70.x = (Rand_ZeroOne() * 20.0f) - 10.0f;
+ sp70.y = -((Rand_ZeroOne() * 20.0f) - 10.0f);
+ sp70.z = (Rand_ZeroOne() * 20.0f) - 10.0f;
+ EffectSsHahen_Spawn(play, potPos, &sp70, &sp8C, 1, 100, OBJECT_UM, 10,
+ potFragments[(s32)(Rand_ZeroOne() * ARRAY_COUNT(potFragments))]);
+ }
+}
+
+void ObjUm_PostLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {
+ ObjUm* this = THIS;
+ GraphicsContext* gfxCtx = play->state.gfxCtx;
+ Mtx* mtx_s3;
+ Gfx* spFC[] = {
+ NULL, gUmBrokenMinigamePotDL, gUmMinigamePotDL, gUmMinigamePotDL, gUmMinigamePotDL, object_um_DL_0067C0
+ };
+ Gfx* spE4[] = { NULL, NULL, object_um_DL_004B60, object_um_DL_0043E0, NULL, NULL };
+ f32 spCC[] = { 0.0f, 1070.0f, 1070.0f, 1070.0f, 1070.0f, 2100.0f };
+ Vec3f spC0 = gZeroVec3f;
+ Vec3f calcPotPos;
+ f32 spB0;
+
+ spC0.y += 1700.0f;
+
+ if (limbIndex == UM_LIMB_WAGON_CART_BED) {
+ Vec3f spA4 = { 2000.0f, 1070.0f, 0.0f };
+
+ Matrix_MultVec3f(&spA4, &this->unk_308);
+ this->flags |= OBJ_UM_FLAG_DRAWN_FLOOR;
+ }
+
+ if (limbIndex == UM_LIMB_WAGON_CART_BED) {
+ Vec3f sp98 = { 2500.0f, 200.0f, 0.0f };
+
+ Matrix_MultVec3f(&sp98, &this->cartBedPos);
+ }
+
+ if (limbIndex == UM_LIMB_WAGON_CART_BED) {
+ Vec3f* potPos;
+ Vec3f sp88;
+ Vec3s sp80;
+ s32 i;
+ f32 sp70[] = { 2000.0f, 0.0f, -2000.0f };
+
+ //! FAKE
+ if (!i) {}
+
+ sp80.x = 0;
+ sp80.z = 0;
+ sp88.x = 6800.0f;
+ OPEN_DISPS(gfxCtx);
+
+ for (i = 0; i < ARRAY_COUNT(this->potsLife); i++) {
+ sp88.z = sp70[i];
+ sp88.y = spCC[this->potsLife[i]];
+
+ if (this->potsLife[i] == 5) {
+ sp80.y = 0x4000;
+ } else {
+ sp80.y = -0x4000;
+ }
+
+ Matrix_Push();
+ Matrix_TranslateRotateZYX(&sp88, &sp80);
+ mtx_s3 = Matrix_NewMtx(gfxCtx);
+ potPos = &this->potPos[i];
+ Matrix_MultVec3f(&spC0, &calcPotPos);
+ SkinMatrix_Vec3fMtxFMultXYZW(&play->viewProjectionMtxF, &calcPotPos, potPos, &spB0);
+
+ if (this->wasPotHit[i]) {
+ this->wasPotHit[i] = false;
+ if (this->potsLife[i] == 1) {
+ ObjUm_SpawnFragments(play, &calcPotPos);
+ } else {
+ EffectSsHitmark_SpawnFixedScale(play, 0, &calcPotPos);
+ }
+ }
+ Matrix_Pop();
+
+ if (mtx_s3 != NULL) {
+ if (play) {}
+ gSPMatrix(POLY_OPA_DISP++, mtx_s3, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+
+ if (spFC[this->potsLife[i]] != NULL) {
+ s32 pad;
+
+ gSPDisplayList(POLY_OPA_DISP++, spFC[this->potsLife[i]]);
+
+ if (spE4[this->potsLife[i]] != NULL) {
+ gSPDisplayList(POLY_OPA_DISP++, spE4[this->potsLife[i]]);
+ }
+ }
+ } else {
+ //! @bug skips CLOSE_DISPS
+ return;
+ }
+ }
+
+ CLOSE_DISPS(gfxCtx);
+ }
+
+ if (limbIndex == UM_LIMB_CREMIA_HEAD) {
+ Matrix_MultZero(&this->dyna.actor.focus.pos);
+ }
+}
+
+void func_80B7BEA4(Vec3f* cartBedPos, s16 arg1, Vec3f* arg2, u8 alpha, PlayState* play) {
+ f32 temp;
+ Vec3f sp108;
+ CollisionPoly* sp104;
+ Mtx* sp100;
+ MtxF spC0;
+ MtxF sp80;
+ MtxF sp40;
+
+ sp108.x = cartBedPos->x;
+ sp108.y = cartBedPos->y + 1.0f;
+ sp108.z = cartBedPos->z;
+
+ temp = BgCheck_EntityRaycastFloor2(play, &play->colCtx, &sp104, &sp108);
+ if (sp104 != NULL) {
+ func_800C0094(sp104, cartBedPos->x, temp, cartBedPos->z, &spC0);
+ } else {
+ SkinMatrix_SetTranslate(&spC0, cartBedPos->x, cartBedPos->y, cartBedPos->z);
+ }
+
+ SkinMatrix_MulYRotation(&spC0, arg1);
+ SkinMatrix_SetScale(&sp80, arg2->x, 1.0f, arg2->z);
+ SkinMatrix_MtxFMtxFMult(&spC0, &sp80, &sp40);
+
+ sp100 = SkinMatrix_MtxFToNewMtx(play->state.gfxCtx, &sp40);
+ if (sp100 != NULL) {
+ OPEN_DISPS(play->state.gfxCtx);
+
+ gSPMatrix(POLY_OPA_DISP++, &gIdentityMtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ POLY_OPA_DISP = Gfx_CallSetupDL(POLY_OPA_DISP, 0x2C);
+ gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0, 0, 0, alpha);
+ gSPMatrix(POLY_OPA_DISP++, sp100, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ gSPDisplayList(POLY_OPA_DISP++, gSquareShadowDL);
+
+ CLOSE_DISPS(play->state.gfxCtx);
+ }
+}
+
+void ObjUm_Draw(Actor* thisx, PlayState* play) {
+ s32 pad;
+ ObjUm* this = THIS;
+ Vec3f sp34;
+
+ this->flags |= OBJ_UM_FLAG_0001;
+ SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount,
+ ObjUm_OverrideLimbDraw, ObjUm_PostLimbDraw, &this->dyna.actor);
+ sp34.x = 0.45f;
+ sp34.y = 0.0f;
+ sp34.z = 0.7f;
+ func_80B7BEA4(&this->cartBedPos, this->dyna.actor.shape.rot.y, &sp34, 180, play);
+ func_80B77770(this, play);
+}
diff --git a/src/overlays/actors/ovl_Obj_Um/z_obj_um.h b/src/overlays/actors/ovl_Obj_Um/z_obj_um.h
index d343d3a512..9d228eda85 100644
--- a/src/overlays/actors/ovl_Obj_Um/z_obj_um.h
+++ b/src/overlays/actors/ovl_Obj_Um/z_obj_um.h
@@ -2,18 +2,93 @@
#define Z_OBJ_UM_H
#include "global.h"
+#include "objects/object_um/object_um.h"
+#include "overlays/actors/ovl_En_Horse/z_en_horse.h"
struct ObjUm;
typedef void (*ObjUmActionFunc)(struct ObjUm*, PlayState*);
+#define MILK_POTS_COUNT 3
+
+typedef enum ObjUmAnimimations {
+ /* -1 */ OBJ_UM_ANIM_MINUS_1 = -1,
+ /* 0 */ OBJ_UM_ANIM_TROT,
+ /* 1 */ OBJ_UM_ANIM_GALLOP,
+ /* 2 */ OBJ_UM_ANIM_IDLE,
+ /* 3 */ OBJ_UM_ANIM_3, // NULL pointer
+ /* 4 */ OBJ_UM_ANIM_LOOK_BACK
+} ObjUmAnimimations;
+
typedef struct ObjUm {
- /* 0x000 */ Actor actor;
- /* 0x144 */ char unk_144[0x18];
+ /* 0x000 */ DynaPolyActor dyna;
/* 0x15C */ ObjUmActionFunc actionFunc;
- /* 0x160 */ char unk_160[0x384];
+ /* 0x160 */ SkelAnime skelAnime;
+ /* 0x1A4 */ Vec3s jointTable[UM_LIMB_MAX];
+ /* 0x228 */ Vec3s morphTable[UM_LIMB_MAX];
+ /* 0x2AC */ s16 wheelRot;
+ /* 0x2AE */ s16 type;
+ /* 0x2B0 */ s16 initialPathIndex;
+ /* 0x2B4 */ s32 unk_2B4;
+ /* 0x2B8 */ EnHorse* donkey;
+ /* 0x2BC */ s32 pathIndex;
+ /* 0x2BE */ s32 pointIndex;
+ /* 0x2C4 */ Vec3f unk_2C4;
+ /* 0x2D0 */ Vec3f unk_2D0;
+ /* 0x2DC */ Vec3f unk_2DC;
+ /* 0x2E8 */ Vec3f unk_2E8;
+ /* 0x2F4 */ s32 flags;
+ /* 0x2BC */ Vec3s unk_2F8;
+ /* 0x2FE */ Vec3s unk_2FE;
+ /* 0x304 */ ObjUmAnimimations currentAnimIndex;
+ /* 0x308 */ Vec3f unk_308;
+ /* 0x314 */ s32 potsLife[MILK_POTS_COUNT];
+ /* 0x320 */ s32 wasPotHit[MILK_POTS_COUNT]; // resets to false in the same frame
+ /* 0x32C */ Vec3f potPos[MILK_POTS_COUNT];
+ /* 0x350 */ s32 unk_350; // unused counter?
+ /* 0x354 */ s32 unk_354; // unused?
+ /* 0x358 */ EnHorse* bandit1;
+ /* 0x35C */ EnHorse* bandit2;
+ /* 0x360 */ Vec3f unk_360[16];
+ /* 0x420 */ s32 unk_420; // ?
+ /* 0x424 */ ColliderCylinder banditsCollisions[2];
+ /* 0x4BC */ Vec3f cartBedPos;
+ /* 0x4C8 */ u16 lastTime;
+ /* 0x4CC */ s32 unk_4CC;
+ /* 0x4D0 */ s32 eyeTexIndex;
+ /* 0x4D4 */ s32 mouthTexIndex;
+ /* 0x4D8 */ s32 unk_4D8;
+ /* 0x4DC */ s32 unk_4DC;
+ /* 0x4E0 */ s32 areAllPotsBroken; // true when all of the pots have been broken
} ObjUm; // size = 0x4E4
extern const ActorInit Obj_Um_InitVars;
+typedef enum {
+ /* 0 */ OBJ_UM_TYPE_TERMINA_FIELD,
+ /* 1 */ OBJ_UM_TYPE_RANCH,
+ /* 2 */ OBJ_UM_TYPE_PRE_MILK_RUN, // milk road, pre-minigame
+ /* 3 */ OBJ_UM_TYPE_MILK_RUN_MINIGAME,
+ /* 4 */ OBJ_UM_TYPE_POST_MILK_RUN // milk road, post-minigame
+} ObjUmType;
+
+#define OBJ_UM_PARSE_TYPE(thisx) (((thisx)->params & 0xFF00) >> 8)
+#define OBJ_UM_PARSE_PATH_INDEX(thisx) ((thisx)->params & 0xFF)
+
+#define OBJ_UM_FLAG_NONE (0)
+#define OBJ_UM_FLAG_0001 (1 << 0)
+#define OBJ_UM_FLAG_MOVING (1 << 1)
+#define OBJ_UM_FLAG_0004 (1 << 2)
+#define OBJ_UM_FLAG_WAITING (1 << 3) // Waiting in the Ranch
+#define OBJ_UM_FLAG_0010 (1 << 4)
+#define OBJ_UM_FLAG_DRAWN_FLOOR (1 << 5)
+#define OBJ_UM_FLAG_0040 (1 << 6)
+#define OBJ_UM_FLAG_PLAYING_MINIGAME (1 << 7)
+#define OBJ_UM_FLAG_0100 (1 << 8)
+#define OBJ_UM_FLAG_0200 (1 << 9) // Something bandit1
+#define OBJ_UM_FLAG_0400 (1 << 10) // Something bandit2
+#define OBJ_UM_FLAG_LOOK_BACK (1 << 11)
+#define OBJ_UM_FLAG_1000 (1 << 12)
+#define OBJ_UM_FLAG_MINIGAME_FINISHED (1 << 13)
+
#endif // Z_OBJ_UM_H
diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt
index ebcf5d2a4e..3f26ba062b 100644
--- a/tools/disasm/functions.txt
+++ b/tools/disasm/functions.txt
@@ -14462,57 +14462,57 @@
0x80B77354:("EnTruMt_TransformLimbDraw",),
0x80B773D0:("EnTruMt_Draw",),
0x80B77770:("func_80B77770",),
- 0x80B77FA4:("func_80B77FA4",),
+ 0x80B77FA4:("ObjUm_InitBandits",),
0x80B781DC:("func_80B781DC",),
0x80B783E0:("func_80B783E0",),
0x80B78764:("func_80B78764",),
0x80B78A54:("func_80B78A54",),
0x80B78C18:("func_80B78C18",),
- 0x80B78D08:("func_80B78D08",),
+ 0x80B78D08:("ObjUm_UpdateBanditsCollisions",),
0x80B78DF0:("func_80B78DF0",),
0x80B78E2C:("ObjUm_SetupAction",),
- 0x80B78E38:("func_80B78E38",),
- 0x80B78E88:("func_80B78E88",),
+ 0x80B78E38:("ObjUm_SetPlayerPosition",),
+ 0x80B78E88:("ObjUm_RotatePlayer",),
0x80B78EBC:("func_80B78EBC",),
- 0x80B78EFC:("func_80B78EFC",),
+ 0x80B78EFC:("ObjUm_RotatePlayerView",),
0x80B78F24:("ObjUm_Init",),
0x80B7949C:("ObjUm_Destroy",),
0x80B79524:("func_80B79524",),
0x80B79560:("func_80B79560",),
0x80B795A0:("func_80B795A0",),
0x80B79734:("func_80B79734",),
- 0x80B797EC:("func_80B797EC",),
+ 0x80B797EC:("ObjUm_RanchGetDialogue",),
0x80B7984C:("func_80B7984C",),
0x80B79A24:("func_80B79A24",),
- 0x80B79A50:("func_80B79A50",),
- 0x80B79BA0:("func_80B79BA0",),
- 0x80B79F10:("func_80B79F10",),
- 0x80B79FFC:("func_80B79FFC",),
+ 0x80B79A50:("ObjUm_RanchWait",),
+ 0x80B79BA0:("ObjUm_UpdatePath",),
+ 0x80B79F10:("ObjUm_RanchWaitPathFinished",),
+ 0x80B79FFC:("ObjUm_RanchStartCs",),
0x80B7A070:("func_80B7A070",),
0x80B7A0E0:("func_80B7A0E0",),
0x80B7A144:("func_80B7A144",),
- 0x80B7A1B4:("func_80B7A1B4",),
+ 0x80B7A1B4:("ObjUm_PreMilkRunDialogueHandler",),
0x80B7A240:("func_80B7A240",),
0x80B7A2AC:("func_80B7A2AC",),
0x80B7A394:("func_80B7A394",),
- 0x80B7A400:("func_80B7A400",),
- 0x80B7A494:("func_80B7A494",),
+ 0x80B7A400:("ObjUm_PreMilkRunStartCs",),
+ 0x80B7A494:("ObjUm_RunMinigame",),
0x80B7A614:("func_80B7A614",),
0x80B7A7AC:("func_80B7A7AC",),
0x80B7A860:("func_80B7A860",),
0x80B7AB78:("func_80B7AB78",),
0x80B7ABE4:("func_80B7ABE4",),
- 0x80B7AC94:("func_80B7AC94",),
- 0x80B7AD34:("func_80B7AD34",),
- 0x80B7AE58:("func_80B7AE58",),
- 0x80B7AEFC:("func_80B7AEFC",),
+ 0x80B7AC94:("ObjUm_StartCs",),
+ 0x80B7AD34:("ObjUm_PostMilkRunWaitPathFinished",),
+ 0x80B7AE58:("ObjUm_PostMilkRunStartCs",),
+ 0x80B7AEFC:("ObjUm_TerminaFieldIdle",),
0x80B7AF30:("func_80B7AF30",),
- 0x80B7B154:("func_80B7B154",),
- 0x80B7B18C:("func_80B7B18C",),
+ 0x80B7B154:("ObjUm_DefaultAnim",),
+ 0x80B7B18C:("ObjUm_UpdateAnim",),
0x80B7B368:("ObjUm_Update",),
- 0x80B7B598:("func_80B7B598",),
- 0x80B7B93C:("func_80B7B93C",),
- 0x80B7BABC:("func_80B7BABC",),
+ 0x80B7B598:("ObjUm_OverrideLimbDraw",),
+ 0x80B7B93C:("ObjUm_SpawnFragments",),
+ 0x80B7BABC:("ObjUm_PostLimbDraw",),
0x80B7BEA4:("func_80B7BEA4",),
0x80B7C03C:("ObjUm_Draw",),
0x80B7C890:("EnNeoReeba_Init",),
diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt
index d9ce9cf704..77f840dbe7 100644
--- a/tools/disasm/variables.txt
+++ b/tools/disasm/variables.txt
@@ -15003,14 +15003,12 @@
0x80B77684:("D_80B77684","f32","",0x4),
0x80B77688:("D_80B77688","f32","",0x4),
0x80B7C0F0:("Obj_Um_InitVars","UNK_TYPE1","",0x1),
- 0x80B7C110:("D_80B7C110","UNK_TYPE1","",0x1),
- 0x80B7C128:("D_80B7C128","UNK_TYPE1","",0x1),
- 0x80B7C138:("D_80B7C138","UNK_TYPE1","",0x1),
+ 0x80B7C110:("sEyeTextures","UNK_TYPE1","",0x1),
+ 0x80B7C128:("sMouthTextures","UNK_TYPE1","",0x1),
+ 0x80B7C138:("sCylinderInit","UNK_TYPE1","",0x1),
0x80B7C164:("D_80B7C164","UNK_TYPE4","",0x4),
- 0x80B7C254:("D_80B7C254","UNK_TYPE4","",0x4),
- 0x80B7C25C:("D_80B7C25C","UNK_TYPE1","",0x1),
- 0x80B7C260:("D_80B7C260","UNK_TYPE1","",0x1),
- 0x80B7C274:("D_80B7C274","UNK_TYPE1","",0x1),
+ 0x80B7C254:("sInitChain","UNK_TYPE4","",0x4),
+ 0x80B7C25C:("sUmAnims","UNK_TYPE1","[5]",0x28),
0x80B7C284:("D_80B7C284","UNK_TYPE4","",0x4),
0x80B7C290:("D_80B7C290","UNK_TYPE4","",0x4),
0x80B7C29C:("D_80B7C29C","UNK_TYPE4","",0x4),
diff --git a/tools/namefixer.py b/tools/namefixer.py
index aa77383115..d2cf4ba773 100755
--- a/tools/namefixer.py
+++ b/tools/namefixer.py
@@ -576,6 +576,7 @@ wordReplace = {
"func_800E8F08": "Actor_TrackNone",
"func_800E8FA4": "Actor_TrackPoint",
"func_800E9250": "Actor_TrackPlayer",
+ "func_800E8EA0": "Actor_ContinueText",
"func_8010A000": "Map_GetDungeonOrBossAreaIndex",
"func_8010A074": "Map_IsInDungeonOrBossArea",
diff --git a/tools/permuter_settings.toml b/tools/permuter_settings.toml
index 9b1959be9a..bf61be3410 100644
--- a/tools/permuter_settings.toml
+++ b/tools/permuter_settings.toml
@@ -11,6 +11,8 @@ CLOSE_DISPS = "void"
ABS = "int"
ABS_ALT = "int"
SQ = "int"
+ARRAY_COUNT = "int"
+ARRAY_COUNTU = "int"
CLAMP = "int"
CLOCK_TIME = "int"
CURRENT_DAY = "int"
diff --git a/undefined_syms.txt b/undefined_syms.txt
index a9cc3e6f5e..c9a2964db2 100644
--- a/undefined_syms.txt
+++ b/undefined_syms.txt
@@ -1480,13 +1480,6 @@ D_06001100 = 0x06001100;
D_06001140 = 0x06001140;
D_06001CB0 = 0x06001CB0;
-// ovl_Obj_Um
-
-D_06007E20 = 0x06007E20;
-D_06007F50 = 0x06007F50;
-D_06011DF8 = 0x06011DF8;
-D_06012CC0 = 0x06012CC0;
-
// ovl_Obj_Usiyane
D_06000098 = 0x06000098;