diff --git a/assets/xml/objects/object_horse_link_child.xml b/assets/xml/objects/object_horse_link_child.xml
index 47ceff55aa..506135e0c9 100644
--- a/assets/xml/objects/object_horse_link_child.xml
+++ b/assets/xml/objects/object_horse_link_child.xml
@@ -10,7 +10,9 @@
-
+
+
+
diff --git a/include/functions.h b/include/functions.h
index 75c0727b37..79d2f0d559 100644
--- a/include/functions.h
+++ b/include/functions.h
@@ -1488,7 +1488,7 @@ void FireObj_Init(GlobalContext* globalCtx, FireObj* fire, FireObjInitParams* in
void FireObj_Destroy(GlobalContext* globalCtx, FireObj* fire);
void FireObj_SetState2(FireObj* fire, f32 dynamicSizeStep, u8 newState);
void FireObj_Update(GlobalContext* globalCtx, FireObj* fire, Actor* actor);
-// void func_800F3940(void);
+s32 func_800F3940(GlobalContext* globalCtx);
// void func_800F39B4(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5);
// void func_800F3A64(void);
void func_800F3B2C(GlobalContext* globalCtx);
@@ -1496,7 +1496,7 @@ void func_800F3B2C(GlobalContext* globalCtx);
// void func_800F3C44(void);
// void func_800F3ED4(void);
void func_800F40A0(GameState* gameState, Player* player);
-// void func_800F415C(void);
+void func_800F415C(Actor* actor, Vec3f* arg1, s16 arg2);
UNK_TYPE func_800F41E4(GlobalContext* globalCtx, ActorContext* actorCtx);
void func_800F4A10(GlobalContext* globalCtx);
@@ -2408,7 +2408,6 @@ void SkelAnime_UpdateTranslation(SkelAnime* skelAnime, Vec3f* pos, s16 angle);
s32 Animation_OnFrame(SkelAnime* skelAnime, f32 frame);
void SkelAnime_Free(SkelAnime* skelAnime, GlobalContext* globalCtx);
void SkelAnime_CopyFrameTable(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src);
-
void SkinMatrix_Vec3fMtxFMultXYZW(MtxF* mf, Vec3f* src, Vec3f* xyzDest, f32* wDest);
void SkinMatrix_Vec3fMtxFMultXYZ(MtxF* mf, Vec3f* src, Vec3f* dest);
void SkinMatrix_MtxFMtxFMult(MtxF* mfB, MtxF* mfA, MtxF* dest);
@@ -3068,7 +3067,7 @@ s32 Math3D_LineSegVsPlane(f32 nx, f32 ny, f32 nz, f32 originDist, Vec3f* linePoi
void Math3D_TriSetCoords(TriNorm* tri, Vec3f* pointA, Vec3f* pointB, Vec3f* pointC);
u32 Math3D_IsPointInSphere(Sphere16* sphere, Vec3f* point);
s32 Math3D_PointDistToLine2D(f32 arg0, f32 arg1, f32 arg2, f32 arg3, f32 arg4, f32 arg5, f32* arg6, f32* arg7, f32* arg8); // returns boolean
-// void func_8017D7C0(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6, UNK_TYPE4 param_7);
+s32 func_8017D7C0(f32 x0, f32 y0, f32 x1, f32 y1, f32 x2, f32 y2, f32* lineLenSq);
// void func_8017D814(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5);
// void func_8017D91C(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5);
// void func_8017DA24(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5);
diff --git a/include/variables.h b/include/variables.h
index f603f7c1ad..1ce8e336d1 100644
--- a/include/variables.h
+++ b/include/variables.h
@@ -893,7 +893,7 @@ extern s32 graphNumGameStates;
// extern UNK_TYPE2 D_801BDA7C;
extern s32 D_801BDA9C;
extern UNK_TYPE4 D_801BDAA0;
-extern UNK_TYPE4 D_801BDAA4;
+extern s32 D_801BDAA4;
// extern UNK_TYPE2 D_801BDAA8;
// extern UNK_TYPE2 D_801BDAAA;
// extern UNK_TYPE2 D_801BDAAC;
diff --git a/spec b/spec
index f028bfa1a6..2cc83081ca 100644
--- a/spec
+++ b/spec
@@ -822,8 +822,11 @@ beginseg
name "ovl_En_Horse"
compress
include "build/src/overlays/actors/ovl_En_Horse/z_en_horse.o"
- include "build/data/ovl_En_Horse/ovl_En_Horse.data.o"
+#ifdef NON_MATCHING
+ include "build/src/overlays/actors/ovl_En_Horse/ovl_En_Horse_reloc.o"
+#else
include "build/data/ovl_En_Horse/ovl_En_Horse.reloc.o"
+#endif
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 ad9089df6c..440ac35783 100644
--- a/src/overlays/actors/ovl_En_Horse/z_en_horse.c
+++ b/src/overlays/actors/ovl_En_Horse/z_en_horse.c
@@ -5,6 +5,7 @@
*/
#include "z_en_horse.h"
+#include "objects/object_horse_link_child/object_horse_link_child.h"
#define FLAGS (ACTOR_FLAG_10)
@@ -15,7 +16,116 @@ void EnHorse_Destroy(Actor* thisx, GlobalContext* globalCtx);
void EnHorse_Update(Actor* thisx, GlobalContext* globalCtx);
void EnHorse_Draw(Actor* thisx, GlobalContext* globalCtx);
-#if 0
+void func_8087D540(Actor* thisx, GlobalContext* globalCtx);
+void EnHorse_StartMountedIdleResetAnim(EnHorse* this);
+void EnHorse_StartMountedIdle(EnHorse* this);
+void EnHorse_MountedIdle(EnHorse* this, GlobalContext* globalCtx);
+void EnHorse_MountedIdleAnim(EnHorse* this);
+void EnHorse_MountedIdleWhinney(EnHorse* this);
+void EnHorse_StartTurning(EnHorse* this);
+void EnHorse_StartWalkingFromIdle(EnHorse* this);
+void EnHorse_StartWalkingInterruptable(EnHorse* this);
+void EnHorse_StartWalking(EnHorse* this);
+void EnHorse_StartTrotting(EnHorse* this);
+void EnHorse_StartGallopingInterruptable(EnHorse* this);
+void EnHorse_StartGalloping(EnHorse* this);
+void EnHorse_StartBraking(EnHorse* this, GlobalContext* globalCtx);
+void EnHorse_StartReversingInterruptable(EnHorse* this);
+void EnHorse_StartReversing(EnHorse* this);
+void EnHorse_StartLowJump(EnHorse* this, GlobalContext* globalCtx);
+void EnHorse_StartHighJump(EnHorse* this, GlobalContext* globalCtx);
+void EnHorse_InitInactive(EnHorse* this);
+void EnHorse_ChangeIdleAnimation(EnHorse* this, s32 anim, f32 morphFrames);
+void EnHorse_ResetIdleAnimation(EnHorse* this);
+void EnHorse_StartIdleRidable(EnHorse* this);
+void EnHorse_StartMovingAnimation(EnHorse* this, s32 anim, f32 morphFrames, f32 startFrames);
+void EnHorse_SetFollowAnimation(EnHorse* this, GlobalContext* globalCtx);
+void EnHorse_InitIngoHorse(EnHorse* this);
+void EnHorse_UpdateIngoHorseAnim(EnHorse* this);
+void func_80881290(EnHorse* this, GlobalContext* globalCtx);
+void func_8088159C(EnHorse* this, GlobalContext* globalCtx);
+void func_80881634(EnHorse* this);
+void func_8088168C(EnHorse* this);
+void EnHorse_CsMoveInit(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void EnHorse_CsMoveToPoint(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void EnHorse_CsPlayHighJumpAnim(EnHorse* this, GlobalContext* globalCtx);
+void EnHorse_CsJumpInit(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void EnHorse_CsJump(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void EnHorse_CsRearingInit(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void EnHorse_CsRearing(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void EnHorse_WarpMoveInit(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void EnHorse_CsWarpMoveToPoint(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void EnHorse_CsWarpRearingInit(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void EnHorse_CsWarpRearing(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void EnHorse_InitCutscene(EnHorse* this, GlobalContext* globalCtx);
+void EnHorse_InitHorsebackArchery(EnHorse* this);
+void EnHorse_UpdateHbaAnim(EnHorse* this);
+void func_80883BEC(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80883CB0(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80883D64(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80883DE0(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80883E10(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80883EA0(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80883F18(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80883F98(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80884010(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_808840C4(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80884194(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_8088424C(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80884314(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_808843B4(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80884444(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_808844E0(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80884564(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_80884604(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_808846B4(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_808846DC(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action);
+void func_808846F0(EnHorse* this, GlobalContext* globalCtx);
+void func_80884994(EnHorse* this);
+void func_80884D04(EnHorse* this, GlobalContext* globalCtx);
+void EnHorse_StickDirection(Vec2f* curStick, f32* stickMag, s16* angle);
+s32 EnHorse_GetMountSide(EnHorse* this, GlobalContext* globalCtx);
+
+typedef struct {
+ s32 csAction;
+ s32 csFuncIdx;
+} CsActionEntry;
+
+typedef struct {
+ s16 x;
+ s16 y;
+ s16 z;
+ s16 speed;
+ s16 angle;
+} RaceWaypoint;
+
+typedef struct {
+ s32 numWaypoints;
+ RaceWaypoint* waypoints;
+} RaceInfo;
+
+static AnimationHeader* sEponaAnimHeaders[] = {
+ &object_horse_link_child_Anim_006D44, &object_horse_link_child_Anim_007468, &object_horse_link_child_Anim_005F64,
+ &object_horse_link_child_Anim_004DE8, &object_horse_link_child_Anim_007D50, &object_horse_link_child_Anim_0043AC,
+ &object_horse_link_child_Anim_002F98, &object_horse_link_child_Anim_0035B0, &object_horse_link_child_Anim_003D38,
+};
+
+static AnimationHeader* sHniAnimHeaders[] = {
+ &object_ha_Anim_00C850, &object_ha_Anim_00CE70, &object_ha_Anim_00B9C8,
+ &object_ha_Anim_00B00C, &object_ha_Anim_00D648, &object_ha_Anim_00A650,
+ &object_ha_Anim_009208, &object_ha_Anim_009858, &object_ha_Anim_00A05C,
+};
+
+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 SkeletonHeader* sSkeletonHeaders[] = {
+ NULL, NULL, &object_horse_link_child_Skel_00A480, NULL, NULL,
+};
+
const ActorInit En_Horse_InitVars = {
ACTOR_EN_HORSE,
ACTORCAT_BG,
@@ -28,370 +138,4617 @@ const ActorInit En_Horse_InitVars = {
(ActorFunc)EnHorse_Draw,
};
-// static ColliderCylinderInit sCylinderInit = {
-static ColliderCylinderInit D_80888F74 = {
- { COLTYPE_NONE, AT_NONE | AT_TYPE_PLAYER, AC_NONE, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1 | OC2_UNK1, COLSHAPE_CYLINDER, },
- { ELEMTYPE_UNK0, { 0x00000004, 0x00, 0x02 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NONE, BUMP_NONE, OCELEM_ON, },
- { 20, 70, 0, { 0, 0, 0 } },
-};
-
-// static ColliderCylinderInit sCylinderInit = {
-static ColliderCylinderInit D_80888FA0 = {
- { COLTYPE_NONE, AT_NONE, AC_NONE, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1 | OC2_UNK1, COLSHAPE_CYLINDER, },
- { ELEMTYPE_UNK0, { 0xF7CFFFFF, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_NONE, OCELEM_ON, },
- { 20, 70, 0, { 0, 0, 0 } },
-};
-
-// static ColliderJntSphElementInit sJntSphElementsInit[1] = {
-static ColliderJntSphElementInit D_80888FCC[1] = {
+static ColliderCylinderInit sCylinderInit1 = {
{
- { ELEMTYPE_UNK0, { 0x00000000, 0x00, 0x00 }, { 0x00013820, 0x00, 0x00 }, TOUCH_NONE | TOUCH_SFX_NORMAL, BUMP_ON | BUMP_NO_AT_INFO | BUMP_NO_DAMAGE | BUMP_NO_SWORD_SFX | BUMP_NO_HITMARK, OCELEM_ON, },
+ COLTYPE_NONE,
+ AT_NONE | AT_TYPE_PLAYER,
+ AC_NONE,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_1 | OC2_UNK1,
+ COLSHAPE_CYLINDER,
+ },
+ {
+ ELEMTYPE_UNK0,
+ { 0x00000004, 0x00, 0x02 },
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ TOUCH_ON | TOUCH_SFX_NONE,
+ BUMP_NONE,
+ OCELEM_ON,
+ },
+ { 20, 70, 0, { 0, 0, 0 } },
+};
+
+static ColliderCylinderInit sCylinderInit2 = {
+ {
+ COLTYPE_NONE,
+ AT_NONE,
+ AC_NONE,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_1 | OC2_UNK1,
+ COLSHAPE_CYLINDER,
+ },
+ {
+ ELEMTYPE_UNK0,
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ { 0xF7CFFFFF, 0x00, 0x00 },
+ TOUCH_NONE | TOUCH_SFX_NORMAL,
+ BUMP_NONE,
+ OCELEM_ON,
+ },
+ { 20, 70, 0, { 0, 0, 0 } },
+};
+
+static ColliderJntSphElementInit sJntSphElementsInit[] = {
+ {
+ {
+ ELEMTYPE_UNK0,
+ { 0x00000000, 0x00, 0x00 },
+ { 0x00013820, 0x00, 0x00 },
+ TOUCH_NONE | TOUCH_SFX_NORMAL,
+ BUMP_ON | BUMP_NO_AT_INFO | BUMP_NO_DAMAGE | BUMP_NO_SWORD_SFX | BUMP_NO_HITMARK,
+ OCELEM_ON,
+ },
{ 13, { { 0, 0, 0 }, 20 }, 100 },
},
};
-// static ColliderJntSphInit sJntSphInit = {
-static ColliderJntSphInit D_80888FF0 = {
- { COLTYPE_NONE, AT_NONE, AC_ON | AC_TYPE_PLAYER, OC1_ON | OC1_TYPE_ALL, OC2_TYPE_1 | OC2_UNK1, COLSHAPE_JNTSPH, },
- 1, D_80888FCC, // sJntSphElementsInit,
+static ColliderJntSphInit sJntSphInit = {
+ {
+ COLTYPE_NONE,
+ AT_NONE,
+ AC_ON | AC_TYPE_PLAYER,
+ OC1_ON | OC1_TYPE_ALL,
+ OC2_TYPE_1 | OC2_UNK1,
+ COLSHAPE_JNTSPH,
+ },
+ 1,
+ sJntSphElementsInit,
};
-// sColChkInfoInit
-static CollisionCheckInfoInit D_80889000 = { 10, 35, 100, MASS_HEAVY };
+static CollisionCheckInfoInit sColChkInfoInit = { 10, 35, 100, MASS_HEAVY };
-// static InitChainEntry sInitChain[] = {
-static InitChainEntry D_80889010[] = {
+static s32 sAnimSoundFrames[] = {
+ 0,
+ 16,
+};
+
+static InitChainEntry sInitChain[] = {
ICHAIN_F32(uncullZoneScale, 1200, ICHAIN_CONTINUE),
ICHAIN_F32(uncullZoneDownward, 300, ICHAIN_STOP),
};
+static u8 sResetNoInput[] = {
+ false, false, false, false, false, false, true, true, true, true, true, true,
+ true, true, true, false, false, false, false, false, false, false, false, false,
+};
+
+static s32 sIdleAnimIds[] = {
+ 1, 3, 0, 3, 1, 0,
+};
+
+static s16 sIngoAnimations[] = { 7, 6, 2, 2, 1, 1, 0, 0, 0, 0 };
+
+static EnHorseCsFunc sCutsceneInitFuncs[] = {
+ NULL,
+ EnHorse_CsMoveInit,
+ EnHorse_CsJumpInit,
+ EnHorse_CsRearingInit,
+ EnHorse_WarpMoveInit,
+ EnHorse_CsWarpRearingInit,
+};
+
+static EnHorseCsFunc sCutsceneActionFuncs[] = {
+ NULL, EnHorse_CsMoveToPoint, EnHorse_CsJump, EnHorse_CsRearing, EnHorse_CsWarpMoveToPoint, EnHorse_CsWarpRearing,
+};
+
+static CsActionEntry sCsActionTable[] = {
+ { 36, 1 }, { 37, 2 }, { 38, 3 }, { 64, 4 }, { 65, 5 },
+};
+
+static RaceWaypoint sHbaWaypoints[] = {
+ { 3600, 1413, -5055, 11, 0x8001 }, { 3360, 1413, -5220, 5, 0xC000 }, { 3100, 1413, -4900, 5, 0x0000 },
+ { 3600, 1413, -4100, 11, 0x0000 }, { 3600, 1413, 360, 11, 0x0000 },
+};
+
+static RaceInfo sHbaInfo = { 5, sHbaWaypoints };
+
+static EnHorseCsFunc D_808890F0[] = {
+ NULL, func_80883BEC, func_80883D64, func_80883E10, func_80883F18, func_80884010,
+ func_80884194, func_80884314, func_80884444, func_80884564, func_808846B4,
+};
+
+static EnHorseCsFunc D_8088911C[] = {
+ NULL, func_80883CB0, func_80883DE0, func_80883EA0, func_80883F98, func_808840C4,
+ func_8088424C, func_808843B4, func_808844E0, func_80884604, func_808846DC,
+};
+
+void EnHorse_RaceWaypointPos(RaceWaypoint* waypoints, s32 idx, Vec3f* pos) {
+ pos->x = waypoints[idx].x;
+ pos->y = waypoints[idx].y;
+ pos->z = waypoints[idx].z;
+}
+
+void EnHorse_RotateToPoint(EnHorse* this, GlobalContext* globalCtx, Vec3f* pos, s16 turnAmount) {
+ func_800F415C(&this->actor, pos, turnAmount);
+}
+
+void func_8087B7C0(EnHorse* this, GlobalContext* globalCtx, Path* path) {
+ s32 spA4;
+ Vec3s* spA0;
+ f32 phi_f12;
+ f32 phi_f14;
+ Vec3f sp8C;
+ Vec3f sp80;
+ f32 sp7C;
+ f32 sp78;
+ f32 sp74;
+ f32 sp70;
+ s32 i;
+ s32 sp68;
+ f32 sp64;
+ s32 sp60;
+ f32 temp_f0;
+ Vec3f sp50;
+
+ spA4 = path->count;
+ spA0 = Lib_SegmentedToVirtual(path->points);
+ Math_Vec3s_ToVec3f(&sp8C, &spA0[this->curRaceWaypoint]);
+
+ if (this->curRaceWaypoint == 0) {
+ phi_f12 = spA0[1].x - spA0[0].x;
+ phi_f14 = spA0[1].z - spA0[0].z;
+ } else if ((this->curRaceWaypoint + 1) == path->count) {
+ phi_f12 = spA0[path->count - 1].x - spA0[path->count - 2].x;
+ phi_f14 = spA0[path->count - 1].z - spA0[path->count - 2].z;
+ } else {
+ phi_f12 = spA0[this->curRaceWaypoint + 1].x - spA0[this->curRaceWaypoint - 1].x;
+ phi_f14 = spA0[this->curRaceWaypoint + 1].z - spA0[this->curRaceWaypoint - 1].z;
+ }
+
+ func_8017B7F8(&sp8C, Math_Atan2S(phi_f12, phi_f14), &sp7C, &sp78, &sp74);
+
+ if (((this->actor.world.pos.x * sp7C) + (sp78 * this->actor.world.pos.z) + sp74) > 0.0f) {
+ this->curRaceWaypoint++;
+ if (this->curRaceWaypoint >= spA4) {
+ this->curRaceWaypoint = spA4 - 1;
+ }
+ Math_Vec3s_ToVec3f(&sp8C, &spA0[this->curRaceWaypoint]);
+ }
+
+ if (this->curRaceWaypoint == 0) {
+ Math_Vec3s_ToVec3f(&sp80, &spA0[1]);
+ } else {
+ Math_Vec3s_ToVec3f(&sp80, &spA0[this->curRaceWaypoint - 1]);
+ }
+
+ func_8017D7C0(this->actor.world.pos.x, this->actor.world.pos.z, sp80.x, sp80.z, sp8C.x, sp8C.z, &sp70);
+
+ if ((this->actor.bgCheckFlags & 8) || (this->unk_1EC & 4)) {
+ EnHorse_RotateToPoint(this, globalCtx, &sp8C, 0xC80);
+ if (this->unk_1EC & 4) {
+ this->unk_1EC &= ~4;
+ }
+ } else {
+ EnHorse_RotateToPoint(this, globalCtx, &sp8C, 0x320);
+ if (sp70 < SQ(100.0f)) {
+ if ((this->actor.xzDistToPlayer < 100.0f) ||
+ (this->colliderJntSph.elements[0].info.ocElemFlags & OCELEM_HIT)) {
+ s32 pad;
+
+ if (Math_SinS(this->actor.yawTowardsPlayer - this->actor.world.rot.y) > 0.0f) {
+ this->actor.world.rot.y -= 0x1E0;
+ } else {
+ this->actor.world.rot.y += 0x1E0;
+ }
+ } else if (this->actor.xzDistToPlayer < 300.0f) {
+ if (Math_SinS(this->actor.yawTowardsPlayer - this->actor.world.rot.y) > 0.0f) {
+ this->actor.world.rot.y += 0x1E0;
+ } else {
+ this->actor.world.rot.y -= 0x1E0;
+ }
+ }
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+ }
+ }
+
+ sp68 = this->curRaceWaypoint - 3;
+ if (sp68 < 0) {
+ sp68 = 0;
+ }
+
+ sp64 = 1.0e+38;
+ sp60 = sp68 + 5;
+ if (path->count < sp60) {
+ sp60 = path->count;
+ }
+
+ for (i = sp68; i < sp60; i++) {
+ Math_Vec3s_ToVec3f(&sp50, &spA0[i]);
+ temp_f0 = Math3D_Distance(&this->actor.world.pos, &sp50);
+ if (temp_f0 < sp64) {
+ sp64 = temp_f0;
+ sp68 = i;
+ }
+ }
+
+ this->unk_398 = spA0[this->curRaceWaypoint].y * 0.01f;
+ if ((this->unk_1EC & 0x100) && !(this->stateFlags & ENHORSE_JUMPING) &&
+ ((this->colliderCylinder1.base.acFlags & AC_HIT) || (this->colliderCylinder2.base.acFlags & AC_HIT) ||
+ (this->unk_58C > 0))) {
+ if (this->unk_58C == 0) {
+ this->unk_590 = 0x1F4;
+ this->unk_58C = 0x2B;
+ }
+ this->unk_58C--;
+ if (this->actor.speedXZ > 5.0f) {
+ this->actor.speedXZ -= 0.5f;
+ }
+ } else if (this->unk_590 > 0) {
+ if (this->unk_590 == 0x1F4) {
+ if (this->rider != NULL) {
+ Actor_PlaySfxAtPos(&this->rider->actor, NA_SE_VO_IN_CRY_0);
+ }
+ }
+ this->unk_590--;
+ if (this->actor.speedXZ < this->unk_398) {
+ this->actor.speedXZ += 1.0f;
+ } else {
+ this->actor.speedXZ -= 0.5f;
+ }
+ } else if (this->actor.params == ENHORSE_5) {
+ s16 sp4A;
+
+ if (sp68 >= this->curRaceWaypoint) {
+ if (this->actor.speedXZ < this->unk_398) {
+ this->actor.speedXZ += 0.5f;
+ } else {
+ this->actor.speedXZ -= 0.5f;
+ }
+ this->unk_394 |= 1;
+ return;
+ }
+
+ sp4A = Actor_YawBetweenActors(&this->actor, &GET_PLAYER(globalCtx)->actor) - this->actor.world.rot.y;
+
+ if ((fabsf(Math_SinS(sp4A)) < 0.9f) && (Math_CosS(sp4A) > 0.0f)) {
+ if (this->actor.speedXZ < this->unk_398) {
+ this->actor.speedXZ += 0.5f;
+ } else {
+ this->actor.speedXZ -= 0.25f;
+ }
+ this->unk_394 |= 1;
+ } else {
+ if (this->actor.speedXZ < 13.0f) {
+ this->actor.speedXZ += 0.4f;
+ } else {
+ this->actor.speedXZ -= 0.2f;
+ }
+ this->unk_394 &= ~1;
+ }
+ } else if (sp68 >= this->curRaceWaypoint) {
+ if (this->actor.speedXZ < this->unk_398) {
+ this->actor.speedXZ += 0.5f;
+ } else {
+ this->actor.speedXZ -= 0.5f;
+ }
+ this->unk_394 |= 1;
+ } else if ((sp68 + 1) == this->curRaceWaypoint) {
+ s16 sp48 = Actor_YawBetweenActors(&this->actor, &GET_PLAYER(globalCtx)->actor) - this->actor.world.rot.y;
+
+ if ((fabsf(Math_SinS(sp48)) < 0.9f) && (Math_CosS(sp48) > 0.0f)) {
+ if (this->actor.speedXZ < this->unk_398) {
+ this->actor.speedXZ += 0.5f;
+ } else {
+ this->actor.speedXZ -= 0.25f;
+ }
+ this->unk_394 |= 1;
+ } else {
+ if (this->actor.speedXZ < 12.0f) {
+ this->actor.speedXZ += 0.4f;
+ } else {
+ this->actor.speedXZ -= 0.2f;
+ }
+ this->unk_394 &= ~1;
+ }
+ } else {
+ if (this->actor.speedXZ < 13.0f) {
+ this->actor.speedXZ += 0.4f;
+ } else {
+ this->actor.speedXZ -= 0.2f;
+ }
+ this->unk_394 &= ~1;
+ }
+}
+
+void EnHorse_PlayWalkingSound(EnHorse* this) {
+ if (sAnimSoundFrames[this->soundTimer] < this->curFrame) {
+ if ((this->soundTimer == 0) && (sAnimSoundFrames[1] < this->curFrame)) {
+ return;
+ }
+
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_WALK);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_WALK);
+ }
+
+ this->soundTimer++;
+ if (this->soundTimer > 1) {
+ this->soundTimer = 0;
+ }
+ }
+}
+
+void func_8087C178(EnHorse* this) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
+ }
+}
+
+void func_8087C1C0(EnHorse* this) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
+ }
+}
+
+f32 EnHorse_SlopeSpeedMultiplier(EnHorse* this, GlobalContext* globalCtx) {
+ f32 multiplier = 1.0f;
+
+ if ((Math_CosS(this->actor.shape.rot.x) < 0.939262f) && (Math_SinS(this->actor.shape.rot.x) < 0.0f)) {
+ multiplier = 0.7f;
+ }
+ return multiplier;
+}
+
+void func_8087C288(GlobalContext* globalCtx, Vec3f* arg1, Vec3f* arg2, f32* arg3) {
+ SkinMatrix_Vec3fMtxFMultXYZW(&globalCtx->viewProjectionMtxF, arg1, arg2, arg3);
+}
+
+s32 func_8087C2B8(GlobalContext* globalCtx, EnHorse* this, Vec3f* arg2, f32 arg3) {
+ f32 phi_f14;
+
+ if ((arg2->z > 0.0f) && (arg2->z < (this->actor.uncullZoneForward + this->actor.uncullZoneScale))) {
+ if (arg3 < 1.0f) {
+ phi_f14 = 1.0f;
+ } else {
+ phi_f14 = 1.0f / arg3;
+ }
+
+ if (((fabsf(arg2->x) * phi_f14) < 1.0f) && (((arg2->y + this->actor.uncullZoneDownward) * phi_f14) > -1.0f) &&
+ (((arg2->y - this->actor.uncullZoneScale) * phi_f14) < 1.0f)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+s32 func_8087C38C(GlobalContext* globalCtx, EnHorse* this, Vec3f* arg2) {
+ Vec3f sp24;
+ f32 sp20;
+ f32 eyeDist;
+
+ func_8087C288(globalCtx, arg2, &sp24, &sp20);
+
+ if (fabsf(sp20) < 0.008f) {
+ return false;
+ }
+
+ eyeDist = Math3D_Distance(arg2, &globalCtx->view.eye);
+
+ return func_8087C2B8(globalCtx, this, &sp24, sp20) || (eyeDist < 100.0f);
+}
+
+void EnHorse_IdleAnimSounds(EnHorse* this, GlobalContext* globalCtx) {
+ 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->stateFlags & ENHORSE_SANDDUST_SOUND)) {
+ this->stateFlags |= ENHORSE_SANDDUST_SOUND;
+ if (this->type == HORSE_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) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
+ }
+ }
+}
+
+s32 EnHorse_Spawn(EnHorse* this, GlobalContext* globalCtx) {
+ s32 i;
+ f32 dist;
+ Path* path;
+ s32 spawn = false;
+ f32 minDist = 1.0e+38;
+ Player* player = GET_PLAYER(globalCtx);
+ Vec3f spawnPos;
+ s32 pathIdx = func_800F3940(globalCtx);
+ s32 pathCount;
+ Vec3s* pathPoints;
+
+ if (pathIdx == -1) {
+ return false;
+ }
+
+ path = &globalCtx->setupPathList[pathIdx];
+ pathCount = path->count;
+ pathPoints = Lib_SegmentedToVirtual(path->points);
+
+ for (i = 0; i < pathCount; i++) {
+ spawnPos.x = pathPoints[i].x;
+ spawnPos.y = pathPoints[i].y;
+ spawnPos.z = pathPoints[i].z;
+ dist = Math3D_Distance(&player->actor.world.pos, &spawnPos);
+
+ if ((minDist < dist) || func_8087C38C(globalCtx, this, &spawnPos)) {
+ continue;
+ }
+
+ minDist = dist;
+ this->actor.world.pos.x = spawnPos.x;
+ this->actor.world.pos.y = spawnPos.y;
+ this->actor.world.pos.z = spawnPos.z;
+ this->actor.prevPos = this->actor.world.pos;
+ this->actor.world.rot.y = 0;
+ this->actor.shape.rot.y = Actor_YawBetweenActors(&this->actor, &GET_PLAYER(globalCtx)->actor);
+ spawn = true;
+ SkinMatrix_Vec3fMtxFMultXYZW(&globalCtx->viewProjectionMtxF, &this->actor.world.pos, &this->actor.projectedPos,
+ &this->actor.projectedW);
+ }
+
+ if (spawn == true) {
+ return true;
+ }
+
+ for (i = 0; i < pathCount; i++) {
+ spawnPos.x = pathPoints[i].x;
+ spawnPos.y = pathPoints[i].y;
+ spawnPos.z = pathPoints[i].z;
+ dist = Math3D_Distance(&player->actor.world.pos, &spawnPos);
+
+ if (minDist < dist) {
+ continue;
+ }
+
+ minDist = dist;
+ this->actor.world.pos.x = spawnPos.x;
+ this->actor.world.pos.y = spawnPos.y;
+ this->actor.world.pos.z = spawnPos.z;
+ this->actor.prevPos = this->actor.world.pos;
+ this->actor.world.rot.y = 0;
+ this->actor.shape.rot.y = Actor_YawBetweenActors(&this->actor, &GET_PLAYER(globalCtx)->actor);
+ spawn = true;
+ SkinMatrix_Vec3fMtxFMultXYZW(&globalCtx->viewProjectionMtxF, &this->actor.world.pos, &this->actor.projectedPos,
+ &this->actor.projectedW);
+ }
+
+ return spawn;
+}
+
+void EnHorse_ResetCutscene(EnHorse* this, GlobalContext* globalCtx) {
+ this->cutsceneAction = -1;
+ this->cutsceneFlags = 0;
+}
+
+void EnHorse_ResetRace(EnHorse* this, GlobalContext* globalCtx) {
+ this->inRace = false;
+}
+
+s32 EnHorse_PlayerCanMove(EnHorse* this, GlobalContext* globalCtx) {
+ Player* player = GET_PLAYER(globalCtx);
+
+ if ((player->stateFlags1 & 1) || (func_800B7128(GET_PLAYER(globalCtx)) == true) ||
+ (player->stateFlags1 & 0x100000) ||
+ (((this->stateFlags & ENHORSE_FLAG_19) || (this->stateFlags & ENHORSE_FLAG_29)) && !this->inRace) ||
+ (this->action == 19) || (player->actor.flags & ACTOR_FLAG_100) || (globalCtx->csCtx.state != 0) ||
+ (ActorCutscene_GetCurrentIndex() != -1) || (player->stateFlags1 & 0x20) || (player->csMode != 0)) {
+ return false;
+ }
+ return true;
+}
+
+void EnHorse_ResetHorsebackArchery(EnHorse* this, GlobalContext* globalCtx) {
+ this->unk_39C = 0;
+ this->hbaStarted = 0;
+ this->hbaFlags = 0;
+}
+
+void EnHorse_ClearDustFlags(u16* dustFlags) {
+ *dustFlags = 0;
+}
+
+void func_8087C9F8(EnHorse* this) {
+}
+
+void func_8087CA04(EnHorse* this, GlobalContext* globalCtx) {
+}
+
+#ifdef NON_MATCHING
+void EnHorse_Init(Actor* thisx, GlobalContext* globalCtx2) {
+ GlobalContext* globalCtx = globalCtx2;
+ EnHorse* this = THIS;
+
+ Actor_ProcessInitChain(&this->actor, sInitChain);
+ EnHorse_ClearDustFlags(&this->dustFlags);
+ D_801BDAA4 = 0;
+ Skin_Setup(&this->skin);
+ this->riderPos = this->actor.world.pos;
+ this->unk_52C = 0;
+ this->noInputTimer = 0;
+ this->riderPos.y += 70.0f;
+ this->noInputTimerMax = 0;
+ this->unk_1EC = 0;
+ this->unk_58C = 0;
+ this->unk_590 = 0;
+ this->unk_3E8 = 0.0f;
+ this->unk_528 = 100.0f;
+
+ if (ENHORSE_GET_8000(&this->actor)) {
+ this->type = HORSE_4;
+ this->unk_528 = 80.0f;
+ this->boostSpeed = 12;
+ if ((this->bankIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_HA)) < 0) {
+ Actor_MarkForDeath(&this->actor);
+ return;
+ }
+ this->unk_1EC |= 1;
+ this->actor.update = func_8087D540;
+ } else if (ENHORSE_GET_4000(&this->actor)) {
+ this->type = HORSE_2;
+ this->unk_528 = 64.8f;
+ this->boostSpeed = 15;
+ if ((this->bankIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_HORSE_LINK_CHILD)) < 0) {
+ this->actor.objBankIndex = Object_Spawn(&globalCtx->objectCtx, OBJECT_HORSE_LINK_CHILD);
+ Actor_SetObjectDependency(globalCtx, &this->actor);
+ Skin_Init(&globalCtx->state, &this->skin, sSkeletonHeaders[this->type], sAnimationHeaders[this->type][0]);
+ Animation_PlayOnce(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx]);
+ this->unk_1EC |= 0x200;
+ } else {
+ this->actor.update = func_8087D540;
+ }
+ } else if (ENHORSE_GET_2000(&this->actor)) {
+ this->type = HORSE_3;
+ this->boostSpeed = 12;
+ if ((this->bankIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_HA)) < 0) {
+ Actor_MarkForDeath(&this->actor);
+ return;
+ }
+ this->unk_1EC |= 1;
+ this->actor.update = func_8087D540;
+ } else {
+ this->type = HORSE_EPONA;
+ this->boostSpeed = 15;
+ Actor_MarkForDeath(&this->actor);
+ }
+
+ this->actor.params &= ~0xE000;
+ if (this->actor.params == 0x1FFF) {
+ this->actor.params = ENHORSE_1;
+ }
+
+ if (this->actor.params == ENHORSE_3) {
+ this->stateFlags = ENHORSE_FLAG_19 | ENHORSE_CANT_JUMP | ENHORSE_UNRIDEABLE;
+ } else if (this->actor.params == ENHORSE_8) {
+ this->stateFlags = ENHORSE_FLAG_19 | ENHORSE_CANT_JUMP;
+ if (CHECK_QUEST_ITEM(14)) {
+ this->stateFlags &= ~ENHORSE_CANT_JUMP;
+ this->stateFlags |= ENHORSE_FLAG_26;
+ }
+ } else if (this->actor.params == ENHORSE_13) {
+ this->stateFlags = ENHORSE_FLAG_29;
+ this->unk_1EC |= 0x10;
+ } else if (this->actor.params == ENHORSE_4) {
+ this->stateFlags = ENHORSE_FLAG_29 | ENHORSE_CANT_JUMP;
+ this->actor.flags |= ACTOR_FLAG_80000000;
+ } else if (this->actor.params == ENHORSE_5) {
+ this->stateFlags = ENHORSE_FLAG_29 | ENHORSE_CANT_JUMP;
+ this->actor.flags |= ACTOR_FLAG_80000000;
+ } else if (this->actor.params == ENHORSE_15) {
+ this->stateFlags = ENHORSE_UNRIDEABLE | ENHORSE_FLAG_7;
+ } else if (this->actor.params == ENHORSE_17) {
+ this->stateFlags = 0;
+ this->unk_1EC |= 8;
+ } else if (this->actor.params == ENHORSE_18) {
+ this->stateFlags = ENHORSE_FLAG_29 | ENHORSE_CANT_JUMP;
+ this->actor.flags |= ACTOR_FLAG_80000000;
+ } else if (this->actor.params == ENHORSE_1) {
+ this->stateFlags = ENHORSE_FLAG_7;
+ } else if ((this->actor.params == ENHORSE_19) || (this->actor.params == ENHORSE_20)) {
+ this->stateFlags = ENHORSE_CANT_JUMP | ENHORSE_UNRIDEABLE;
+ } else {
+ this->stateFlags = 0;
+ }
+
+ if (((globalCtx->sceneNum == SCENE_KOEPONARACE) && ((gSaveContext.save.weekEventReg[92] & (1 | 2 | 4)) == 1)) ||
+ ((gSaveContext.save.entranceIndex == 0x6400) && Cutscene_GetSceneSetupIndex(globalCtx))) {
+ this->stateFlags |= ENHORSE_FLAG_25;
+ }
+
+ this->actor.gravity = -3.5f;
+ ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawHorse, 20.0f);
+ this->action = ENHORSE_ACT_IDLE;
+ this->actor.speedXZ = 0.0f;
+
+ if (this->type == HORSE_2) {
+ sJntSphInit.elements[0].dim.limb = 13;
+ } else if ((this->type == HORSE_3) || (this->type == HORSE_4)) {
+ sJntSphInit.elements[0].dim.limb = 10;
+ }
+
+ Collider_InitCylinder(globalCtx, &this->colliderCylinder1);
+ Collider_SetCylinder(globalCtx, &this->colliderCylinder1, &this->actor, &sCylinderInit1);
+ Collider_InitCylinder(globalCtx, &this->colliderCylinder2);
+ Collider_SetCylinder(globalCtx, &this->colliderCylinder2, &this->actor, &sCylinderInit2);
+ Collider_InitJntSph(globalCtx, &this->colliderJntSph);
+ Collider_SetJntSph(globalCtx, &this->colliderJntSph, &this->actor, &sJntSphInit, this->colliderJntSphElements);
+
+ if (this->type == HORSE_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) {
+ this->colliderCylinder1.dim.radius = 50;
+ }
+
+ CollisionCheck_SetInfo(&this->actor.colChkInfo, NULL, &sColChkInfoInit);
+
+ if (this->type == HORSE_2) {
+ Actor_SetScale(&this->actor, 0.00648f);
+ } else if (this->type == HORSE_4) {
+ Actor_SetScale(&this->actor, 0.008f);
+ } else {
+ Actor_SetScale(&this->actor, 0.01f);
+ }
+
+ this->actor.focus.pos = this->actor.world.pos;
+ this->playerControlled = false;
+ this->actor.focus.pos.y += 70.0f;
+
+ if (!(this->unk_1EC & 1) && !(this->unk_1EC & 0x200) && (this->actor.update == EnHorse_Update)) {
+ Skin_Init(&globalCtx->state, &this->skin, sSkeletonHeaders[this->type], sAnimationHeaders[this->type][0]);
+ }
+
+ this->animationIdx = 0;
+ this->numBoosts = 6;
+ this->boostRegenTime = 0;
+ this->postDrawFunc = NULL;
+ this->blinkTimer = 0;
+
+ EnHorse_ResetCutscene(this, globalCtx);
+ EnHorse_ResetRace(this, globalCtx);
+ EnHorse_ResetHorsebackArchery(this, globalCtx);
+
+ if (this->actor.params == ENHORSE_2) {
+ this->unk_53C = 0;
+ EnHorse_InitInactive(this);
+ } else if (this->actor.params == ENHORSE_3) {
+ EnHorse_InitIngoHorse(this);
+ this->rider = (EnIn*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_IN, this->actor.world.pos.x,
+ this->actor.world.pos.y, this->actor.world.pos.z, this->actor.shape.rot.x,
+ this->actor.shape.rot.y, 1, 1);
+ this->unk_398 = 14.34f;
+ } else if (this->actor.params == ENHORSE_4) {
+ func_80881634(this);
+ this->unk_398 = 14.34f;
+ this->rider = (EnIn*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_IN, this->actor.world.pos.x,
+ this->actor.world.pos.y, this->actor.world.pos.z, this->actor.shape.rot.x,
+ this->actor.shape.rot.y, 1, 1);
+ this->unk_1EC |= 0x100;
+ } else if (this->actor.params == ENHORSE_5) {
+ func_80881634(this);
+ this->unk_398 = 14.525f;
+ this->rider = (EnIn*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_IN, this->actor.world.pos.x,
+ this->actor.world.pos.y, this->actor.world.pos.z, this->actor.shape.rot.x,
+ this->actor.shape.rot.y, 1, 2);
+ this->unk_1EC |= 0x100;
+ } else if (this->actor.params == ENHORSE_9) {
+ EnHorse_InitCutscene(this, globalCtx);
+ } else if (this->actor.params == ENHORSE_10) {
+ EnHorse_InitHorsebackArchery(this);
+ func_80112AFC(globalCtx);
+ } else if (this->actor.params == ENHORSE_14) {
+ func_808846F0(this, globalCtx);
+ if ((globalCtx->sceneNum == SCENE_LOST_WOODS) && !Cutscene_IsPlaying(globalCtx)) {
+ Actor_MarkForDeath(&this->actor);
+ }
+ } else if (this->actor.params == ENHORSE_16) {
+ func_8087C9F8(this);
+ } else if (this->actor.params == ENHORSE_15) {
+ EnHorse_ResetIdleAnimation(this);
+ } else if (this->actor.params == ENHORSE_18) {
+ func_80884994(this);
+ } else if (this->actor.params == ENHORSE_19) {
+ EnIn* in;
+
+ func_80884D04(this, globalCtx);
+ in = (EnIn*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_IN, this->actor.world.pos.x,
+ this->actor.world.pos.y, this->actor.world.pos.z, this->actor.shape.rot.x,
+ this->actor.shape.rot.y, 1, 1);
+ this->rider = in;
+ in->unk4AC |= (0x20 | 0x4);
+ } else if (this->actor.params == ENHORSE_20) {
+ EnIn* in;
+
+ func_80884D04(this, globalCtx);
+ in = (EnIn*)Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_IN, this->actor.world.pos.x,
+ this->actor.world.pos.y, this->actor.world.pos.z, this->actor.shape.rot.x,
+ this->actor.shape.rot.y, 1, 1);
+ this->rider = in;
+ in->unk4AC |= (0x20 | 0x8 | 0x4);
+ } else {
+ EnHorse_StartIdleRidable(this);
+ }
+
+ this->actor.shape.rot.z = 0;
+ this->actor.world.rot.z = this->actor.shape.rot.z;
+ this->actor.home.rot.z = this->actor.shape.rot.z;
+ this->unk_3EC = this->actor.world.rot.y;
+ this->unk_538 = 0;
+
+ if (this->unk_1EC & 0x100) {
+ this->colliderCylinder1.base.colType = COLTYPE_HIT3;
+ this->colliderCylinder1.base.acFlags |= (AC_TYPE_PLAYER | AC_ON);
+ this->colliderCylinder1.info.bumperFlags |= BUMP_ON;
+ this->colliderCylinder1.info.bumper.dmgFlags = 0x10000 | 0x2000 | 0x1000 | 0x800 | 0x20;
+ this->colliderCylinder2.base.colType = COLTYPE_HIT3;
+ this->colliderCylinder2.base.acFlags |= (AC_TYPE_PLAYER | AC_ON);
+ this->colliderCylinder2.info.bumperFlags |= BUMP_ON;
+ this->colliderCylinder2.info.bumper.dmgFlags = 0x10000 | 0x2000 | 0x1000 | 0x800 | 0x20;
+ }
+}
+#else
+#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/EnHorse_Init.s")
#endif
-extern ColliderCylinderInit D_80888F74;
-extern ColliderCylinderInit D_80888FA0;
-extern ColliderJntSphElementInit D_80888FCC[1];
-extern ColliderJntSphInit D_80888FF0;
-extern CollisionCheckInfoInit D_80889000;
-extern InitChainEntry D_80889010[];
-
-extern UNK_TYPE D_06008C68;
-extern UNK_TYPE D_0600A8DC;
-extern UNK_TYPE D_0600AD08;
-extern UNK_TYPE D_0600B3E0;
-extern UNK_TYPE D_0600BDE0;
-extern UNK_TYPE D_0600D178;
-extern UNK_TYPE D_0600D4E8;
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087B730.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087B784.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087B7C0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C0AC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C178.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C1C0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C208.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C288.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C2B8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C38C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C43C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C590.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C8B8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C8D0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C8E0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C9D4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C9EC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087C9F8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087CA04.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/EnHorse_Init.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087D540.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/EnHorse_Destroy.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087D70C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087D75C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087D814.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087D988.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087DDEC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087DE28.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087DF64.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E080.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E0A4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E18C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E2A8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E350.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E564.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E5B4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E5D8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E684.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E6D8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E92C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087E9D0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087EA1C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087EB54.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087EB78.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087EC20.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087EC78.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087ED10.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087EEC4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087F078.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087F1FC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087F39C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087F590.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087F5B4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087F658.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087F9A0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087F9C4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087FB08.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087FB14.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087FD94.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087FDB8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087FF08.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8087FF14.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808801A8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808801F8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808802D0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808804A4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808804CC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80880500.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80880534.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808806DC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80880844.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80880978.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80880D50.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80880DA8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80880E00.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80881128.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8088126C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80881290.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80881398.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8088159C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80881634.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8088168C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808819D8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80881BDC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80881C54.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80881DA4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80881DC8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80881F10.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80881F48.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808821C8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808822CC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8088247C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80882564.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808826B4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80882820.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808829D0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808829F4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80882A44.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80882B9C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80882D8C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80882DC0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80883104.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80883308.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80883B70.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80883BEC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80883CB0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80883D64.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80883DE0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80883E10.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80883EA0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80883F18.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80883F98.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884010.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808840C4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884194.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8088424C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884314.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808843B4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884444.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808844E0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884564.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884604.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808846B4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808846DC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808846F0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884718.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884868.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808848C8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884994.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884A40.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884D04.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80884E0C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80885060.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808850DC.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80885220.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808853E0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_8088598C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80885A80.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80885AF4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80885B4C.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80885C90.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80885DA4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80886C00.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80886DC4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80886FA8.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808870A4.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_808871A0.s")
-
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80887270.s")
-
+void func_8087D540(Actor* thisx, GlobalContext* globalCtx) {
+ EnHorse* this = THIS;
+
+ if (Object_IsLoaded(&globalCtx->objectCtx, this->bankIndex)) {
+ this->actor.objBankIndex = this->bankIndex;
+ Actor_SetObjectDependency(globalCtx, &this->actor);
+ this->actor.update = EnHorse_Update;
+ if (this->unk_1EC & 1) {
+ if (this->type == HORSE_3) {
+ SkelAnime_InitFlex(globalCtx, &this->skin.skelAnime, &object_ha_Skel_008C68, NULL, this->jointTable,
+ this->morphTable, OBJECT_HA_1_LIMB_MAX);
+ } else {
+ SkelAnime_InitFlex(globalCtx, &this->skin.skelAnime, &object_ha_Skel_0150D8, NULL, this->jointTable,
+ this->morphTable, OBJECT_HA_2_LIMB_MAX);
+ }
+ } else {
+ Skin_Init(&globalCtx->state, &this->skin, sSkeletonHeaders[this->type], sAnimationHeaders[this->type][0]);
+ }
+ Animation_PlayOnce(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx]);
+ }
+}
+
+void EnHorse_Destroy(Actor* thisx, GlobalContext* globalCtx) {
+ EnHorse* this = THIS;
+
+ if (this->stateFlags & ENHORSE_DRAW) {
+ Audio_StopSfxByPos(&this->unk_218);
+ }
+ Skin_Free(&globalCtx->state, &this->skin);
+ Collider_DestroyCylinder(globalCtx, &this->colliderCylinder1);
+ Collider_DestroyCylinder(globalCtx, &this->colliderCylinder2);
+ Collider_DestroyJntSph(globalCtx, &this->colliderJntSph);
+}
+
+void EnHorse_RotateToPlayer(EnHorse* this, GlobalContext* globalCtx) {
+ EnHorse_RotateToPoint(this, globalCtx, &GET_PLAYER(globalCtx)->actor.world.pos, 0x320);
+ if (this->stateFlags & ENHORSE_OBSTACLE) {
+ this->actor.world.rot.y += 1600;
+ }
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+}
+
+void EnHorse_Freeze(EnHorse* this, GlobalContext* globalCtx) {
+ if ((this->action != ENHORSE_ACT_HBA) && (this->action != ENHORSE_ACT_21) &&
+ (this->action != ENHORSE_ACT_FLEE_PLAYER)) {
+ if (sResetNoInput[this->actor.params] && (this->actor.params != ENHORSE_6)) {
+ Player* player = GET_PLAYER(globalCtx);
+
+ this->noInputTimerMax = 0;
+ this->noInputTimer = 0;
+ player->actor.world.pos = this->actor.world.pos;
+ player->actor.world.pos.y += 70.0f;
+ }
+ this->prevAction = this->action;
+ this->action = ENHORSE_ACT_FROZEN;
+ this->colliderCylinder1.base.ocFlags1 &= ~OC1_ON;
+ this->colliderCylinder2.base.ocFlags1 &= ~OC1_ON;
+ this->colliderJntSph.base.ocFlags1 &= ~OC1_ON;
+ this->animationIdx = ENHORSE_ANIM_IDLE;
+ }
+}
+
+void EnHorse_Frozen(EnHorse* this, GlobalContext* globalCtx) {
+ this->actor.speedXZ = 0.0f;
+ this->noInputTimer--;
+ if (this->noInputTimer < 0) {
+ this->colliderCylinder1.base.ocFlags1 |= OC1_ON;
+ this->colliderCylinder2.base.ocFlags1 |= OC1_ON;
+ this->colliderJntSph.base.ocFlags1 |= OC1_ON;
+ if (this->playerControlled == true) {
+ this->stateFlags &= ~ENHORSE_FLAG_7;
+ if (this->actor.params == ENHORSE_6) {
+ EnHorse_StartMountedIdleResetAnim(this);
+ } else if (this->actor.params == ENHORSE_11) {
+ this->actor.params = ENHORSE_7;
+ if (globalCtx->csCtx.state != 0) {
+ EnHorse_StartMountedIdle(this);
+ } else {
+ this->actor.speedXZ = 8.0f;
+ EnHorse_StartGalloping(this);
+ }
+ } else if (this->prevAction == ENHORSE_ACT_IDLE) {
+ EnHorse_StartMountedIdle(this);
+ } else {
+ EnHorse_StartMountedIdleResetAnim(this);
+ }
+
+ if (this->actor.params != ENHORSE_0) {
+ this->actor.params = ENHORSE_0;
+ }
+ } else if (this->prevAction == ENHORSE_ACT_MOUNTED_TURN) {
+ EnHorse_ChangeIdleAnimation(this, 0, 0.0f);
+ } else if (this->prevAction == ENHORSE_ACT_MOUNTED_WALK) {
+ EnHorse_ChangeIdleAnimation(this, 0, 0.0f);
+ } else {
+ EnHorse_ChangeIdleAnimation(this, 0, 0.0f);
+ }
+ }
+}
+
+void EnHorse_UpdateSpeed(EnHorse* this, GlobalContext* globalCtx, f32 brakeDecel, f32 brakeAngle, f32 minStickMag,
+ f32 decel, f32 baseSpeed, s16 turnSpeed) {
+ f32 phi_f0;
+ f32 stickMag;
+ s16 stickAngle;
+ s16 turn;
+ f32 temp_f12;
+
+ if (!EnHorse_PlayerCanMove(this, globalCtx)) {
+ if (this->actor.speedXZ > 8.0f) {
+ this->actor.speedXZ -= decel;
+ } else if (this->actor.speedXZ < 0.0f) {
+ this->actor.speedXZ = 0.0f;
+ }
+ return;
+ }
+
+ baseSpeed *= EnHorse_SlopeSpeedMultiplier(this, globalCtx);
+ EnHorse_StickDirection(&this->curStick, &stickMag, &stickAngle);
+
+ if (Math_CosS(stickAngle) <= brakeAngle) {
+ this->actor.speedXZ -= brakeDecel;
+ this->actor.speedXZ = CLAMP_MIN(this->actor.speedXZ, 0.0f);
+ return;
+ }
+
+ if (stickMag < minStickMag) {
+ this->stateFlags &= ~ENHORSE_BOOST;
+ this->stateFlags &= ~ENHORSE_BOOST_DECEL;
+ this->actor.speedXZ -= decel;
+ if (this->actor.speedXZ < 0.0f) {
+ this->actor.speedXZ = 0.0f;
+ }
+ return;
+ }
+
+ if (this->stateFlags & ENHORSE_BOOST) {
+ if ((16 - this->boostTimer) > 0) {
+ this->actor.speedXZ =
+ (((EnHorse_SlopeSpeedMultiplier(this, globalCtx) * this->boostSpeed) - this->actor.speedXZ) /
+ (16.0f - this->boostTimer)) +
+ this->actor.speedXZ;
+ } else {
+ this->actor.speedXZ = EnHorse_SlopeSpeedMultiplier(this, globalCtx) * this->boostSpeed;
+ }
+
+ if ((EnHorse_SlopeSpeedMultiplier(this, globalCtx) * this->boostSpeed) <= this->actor.speedXZ) {
+ this->stateFlags &= ~ENHORSE_BOOST;
+ this->stateFlags |= ENHORSE_BOOST_DECEL;
+ }
+ } else if (this->stateFlags & ENHORSE_BOOST_DECEL) {
+ if (this->actor.speedXZ > baseSpeed) {
+ this->actor.speedXZ -= 0.06f;
+ } else if (this->actor.speedXZ < baseSpeed) {
+ this->actor.speedXZ = baseSpeed;
+ this->stateFlags &= ~ENHORSE_BOOST_DECEL;
+ }
+ } else {
+ if (this->actor.speedXZ <= (baseSpeed * (1.0f / 54.0f) * stickMag)) {
+ phi_f0 = 1.0f;
+ } else {
+ phi_f0 = -1.0f;
+ }
+
+ this->actor.speedXZ += phi_f0 * 50.0f * 0.01f;
+
+ if (this->actor.speedXZ > baseSpeed) {
+ this->actor.speedXZ -= decel;
+ if (this->actor.speedXZ < baseSpeed) {
+ this->actor.speedXZ = baseSpeed;
+ }
+ }
+ }
+
+ temp_f12 = stickAngle * (1 / 32236.f);
+ turn = stickAngle * temp_f12 * temp_f12 * (2.2f - (this->actor.speedXZ * (1.0f / this->boostSpeed)));
+ turn = CLAMP(turn, -turnSpeed * (2.2f - (1.7f * this->actor.speedXZ * (1.0f / this->boostSpeed))),
+ turnSpeed * (2.2f - (1.7f * this->actor.speedXZ * (1.0f / this->boostSpeed))));
+ this->actor.world.rot.y += turn;
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+}
+
+void EnHorse_StartMountedIdleResetAnim(EnHorse* this) {
+ this->skin.skelAnime.curFrame = 0.0f;
+ EnHorse_StartMountedIdle(this);
+ this->stateFlags &= ~ENHORSE_SANDDUST_SOUND;
+}
+
+void EnHorse_StartMountedIdle(EnHorse* this) {
+ f32 curFrame;
+
+ 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->stateFlags & ENHORSE_SANDDUST_SOUND)) {
+ this->stateFlags |= ENHORSE_SANDDUST_SOUND;
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
+ }
+ }
+ }
+ curFrame = this->skin.skelAnime.curFrame;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, curFrame,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+}
+
+void EnHorse_MountedIdle(EnHorse* this, GlobalContext* globalCtx) {
+ f32 mag;
+ s16 angle = 0;
+
+ this->actor.speedXZ = 0.0f;
+ EnHorse_StickDirection(&this->curStick, &mag, &angle);
+ if (mag > 10.0f) {
+ if (EnHorse_PlayerCanMove(this, globalCtx) == true) {
+ if (Math_CosS(angle) <= -0.5f) {
+ EnHorse_StartReversingInterruptable(this);
+ } else if (Math_CosS(angle) <= 0.7071f) {
+ EnHorse_StartTurning(this);
+ } else {
+ EnHorse_StartWalkingFromIdle(this);
+ }
+ } else if (this->unk_3EC != this->actor.world.rot.y) {
+ EnHorse_StartTurning(this);
+ }
+ }
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ EnHorse_MountedIdleAnim(this);
+ }
+}
+
+void EnHorse_MountedIdleAnim(EnHorse* this) {
+ this->skin.skelAnime.curFrame = 0.0f;
+ EnHorse_MountedIdleWhinney(this);
+}
+
+void EnHorse_MountedIdleWhinney(EnHorse* this) {
+ f32 curFrame;
+
+ this->action = ENHORSE_ACT_MOUNTED_WALK;
+ this->animationIdx = ENHORSE_ANIM_WHINNEY;
+ curFrame = this->skin.skelAnime.curFrame;
+ 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) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_GROAN);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_GROAN);
+ }
+ }
+}
+
+void EnHorse_MountedIdleWhinneying(EnHorse* this, GlobalContext* globalCtx) {
+ f32 stickMag;
+ s16 stickAngle = 0;
+
+ this->actor.speedXZ = 0.0f;
+ EnHorse_StickDirection(&this->curStick, &stickMag, &stickAngle);
+ if (stickMag > 10.0f) {
+ if (EnHorse_PlayerCanMove(this, globalCtx) == true) {
+ if (Math_CosS(stickAngle) <= -0.5f) {
+ EnHorse_StartReversingInterruptable(this);
+ } else if (Math_CosS(stickAngle) <= 0.7071f) {
+ EnHorse_StartTurning(this);
+ } else {
+ EnHorse_StartWalkingFromIdle(this);
+ }
+ } else if (this->unk_3EC != this->actor.world.rot.y) {
+ EnHorse_StartTurning(this);
+ }
+ }
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ EnHorse_StartMountedIdleResetAnim(this);
+ }
+}
+
+void EnHorse_StartTurning(EnHorse* this) {
+ this->action = ENHORSE_ACT_MOUNTED_TROT;
+ this->soundTimer = 0;
+ this->animationIdx = ENHORSE_ANIM_WALK;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][4]), ANIMMODE_ONCE, -3.0f);
+}
+
+void EnHorse_MountedTurn(EnHorse* this, GlobalContext* globalCtx) {
+ f32 stickMag;
+ s16 clampedYaw;
+ s16 stickAngle;
+
+ this->actor.speedXZ = 0.0f;
+ EnHorse_PlayWalkingSound(this);
+ if (EnHorse_PlayerCanMove(this, globalCtx) == true) {
+ EnHorse_StickDirection(&this->curStick, &stickMag, &stickAngle);
+ if (stickMag > 10.0f) {
+ if (!EnHorse_PlayerCanMove(this, globalCtx)) {
+ EnHorse_StartMountedIdleResetAnim(this);
+ } else if (Math_CosS(stickAngle) <= -0.5f) {
+ EnHorse_StartReversingInterruptable(this);
+ } else if (Math_CosS(stickAngle) <= 0.7071f) {
+ clampedYaw = CLAMP(stickAngle, -1600.0f, 1600.0f);
+ this->actor.world.rot.y += clampedYaw;
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+ } else {
+ EnHorse_StartWalkingInterruptable(this);
+ }
+ }
+ }
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ if (EnHorse_PlayerCanMove(this, globalCtx) == true) {
+ if (Math_CosS(stickAngle) <= 0.7071f) {
+ EnHorse_StartTurning(this);
+ } else {
+ EnHorse_StartMountedIdleResetAnim(this);
+ }
+ } else if (this->unk_3EC != this->actor.world.rot.y) {
+ EnHorse_StartTurning(this);
+ } else {
+ EnHorse_StartMountedIdleResetAnim(this);
+ }
+ }
+}
+
+void EnHorse_StartWalkingFromIdle(EnHorse* this) {
+ EnHorse_StartWalkingInterruptable(this);
+ if (!(this->stateFlags & ENHORSE_FLAG_8) && !(this->stateFlags & ENHORSE_FLAG_9)) {
+ this->stateFlags |= ENHORSE_FLAG_9;
+ this->waitTimer = 8;
+ } else {
+ this->waitTimer = 0;
+ }
+}
+
+void EnHorse_StartWalkingInterruptable(EnHorse* this) {
+ this->noInputTimer = 0;
+ this->noInputTimerMax = 0;
+ EnHorse_StartWalking(this);
+}
+
+void EnHorse_StartWalking(EnHorse* this) {
+ this->action = ENHORSE_ACT_MOUNTED_GALLOP;
+ this->soundTimer = 0;
+ this->animationIdx = ENHORSE_ANIM_WALK;
+ this->waitTimer = 0;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][4]), ANIMMODE_ONCE, -3.0f);
+}
+
+void EnHorse_MountedWalkingReset(EnHorse* this) {
+ this->action = ENHORSE_ACT_MOUNTED_GALLOP;
+ this->soundTimer = 0;
+ this->animationIdx = ENHORSE_ANIM_WALK;
+ this->waitTimer = 0;
+ Animation_PlayOnce(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx]);
+}
+
+void EnHorse_MountedWalk(EnHorse* this, GlobalContext* globalCtx) {
+ f32 stickMag;
+ s16 stickAngle;
+
+ EnHorse_PlayWalkingSound(this);
+ EnHorse_StickDirection(&this->curStick, &stickMag, &stickAngle);
+
+ if ((this->noInputTimerMax == 0) ||
+ ((this->noInputTimer > 0) && (this->noInputTimer < (this->noInputTimerMax - 20)))) {
+ EnHorse_UpdateSpeed(this, globalCtx, 0.3f, -0.5f, 10.0f, 0.06f, 3.0f, 0x320);
+ } else {
+ this->actor.speedXZ = 3.0f;
+ }
+
+ if (this->actor.speedXZ == 0.0f) {
+ this->stateFlags &= ~ENHORSE_FLAG_9;
+ EnHorse_StartMountedIdleResetAnim(this);
+ this->noInputTimer = 0;
+ this->noInputTimerMax = 0;
+ } else if (this->actor.speedXZ > 3.0f) {
+ this->stateFlags &= ~ENHORSE_FLAG_9;
+ EnHorse_StartTrotting(this);
+ this->noInputTimer = 0;
+ this->noInputTimerMax = 0;
+ }
+
+ if (this->noInputTimer > 0) {
+ this->noInputTimer--;
+ if (this->noInputTimer <= 0) {
+ this->noInputTimerMax = 0;
+ }
+ }
+
+ if (this->waitTimer <= 0) {
+ this->stateFlags &= ~ENHORSE_FLAG_9;
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.75f;
+ if ((SkelAnime_Update(&this->skin.skelAnime) || (this->actor.speedXZ == 0.0f)) && (this->noInputTimer <= 0)) {
+ if (this->actor.speedXZ > 3.0f) {
+ EnHorse_StartTrotting(this);
+ this->noInputTimer = 0;
+ this->noInputTimerMax = 0;
+ } else if ((stickMag < 10.0f) || (Math_CosS(stickAngle) <= -0.5f)) {
+ EnHorse_StartMountedIdleResetAnim(this);
+ this->noInputTimer = 0;
+ this->noInputTimerMax = 0;
+ } else {
+ EnHorse_MountedWalkingReset(this);
+ }
+ }
+ } else {
+ this->waitTimer--;
+ this->actor.speedXZ = 0.0f;
+ }
+}
+
+void EnHorse_StartTrotting(EnHorse* this) {
+ this->action = ENHORSE_ACT_MOUNTED_REARING;
+ this->animationIdx = ENHORSE_ANIM_TROT;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+}
+
+void EnHorse_MountedTrotReset(EnHorse* this) {
+ this->action = ENHORSE_ACT_MOUNTED_REARING;
+ this->animationIdx = ENHORSE_ANIM_TROT;
+ Animation_PlayOnce(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx]);
+}
+
+void EnHorse_MountedTrot(EnHorse* this, GlobalContext* globalCtx) {
+ f32 stickMag;
+ s16 stickAngle;
+
+ EnHorse_UpdateSpeed(this, globalCtx, 0.3f, -0.5f, 10.0f, 0.06f, 6.0f, 800);
+ EnHorse_StickDirection(&this->curStick, &stickMag, &stickAngle);
+ if (this->actor.speedXZ < 3.0f) {
+ EnHorse_StartWalkingInterruptable(this);
+ }
+
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.375f;
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ func_8087C178(this);
+ func_8013ECE0(0.0f, 60, 8, 255);
+ if (this->actor.speedXZ >= 6.0f) {
+ EnHorse_StartGallopingInterruptable(this);
+ } else if (this->actor.speedXZ < 3.0f) {
+ EnHorse_StartWalkingInterruptable(this);
+ } else {
+ EnHorse_MountedTrotReset(this);
+ }
+ }
+}
+
+void EnHorse_StartGallopingInterruptable(EnHorse* this) {
+ this->noInputTimer = 0;
+ this->noInputTimerMax = 0;
+ EnHorse_StartGalloping(this);
+}
+
+void EnHorse_StartGalloping(EnHorse* this) {
+ this->action = ENHORSE_ACT_STOPPING;
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ this->unk_230 = 0;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+}
+
+void EnHorse_MountedGallopReset(EnHorse* this) {
+ this->noInputTimer = 0;
+ this->noInputTimerMax = 0;
+ this->action = ENHORSE_ACT_STOPPING;
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ this->unk_230 = 0;
+ Animation_PlayOnce(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx]);
+}
+
+void EnHorse_JumpLanding(EnHorse* this, GlobalContext* globalCtx) {
+ Vec3s* jointTable;
+ f32 y;
+
+ this->action = ENHORSE_ACT_STOPPING;
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ Animation_PlayOnce(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx]);
+ jointTable = this->skin.skelAnime.jointTable;
+ y = jointTable->y;
+ this->riderPos.y += y * 0.01f * this->unk_528 * 0.01f;
+ this->postDrawFunc = NULL;
+}
+
+void EnHorse_MountedGallop(EnHorse* this, GlobalContext* globalCtx) {
+ f32 stickMag;
+ s16 stickAngle;
+
+ EnHorse_StickDirection(&this->curStick, &stickMag, &stickAngle);
+
+ if (this->noInputTimer <= 0) {
+ EnHorse_UpdateSpeed(this, globalCtx, 0.3f, -0.5f, 10.0f, 0.06f, 8.0f, 800);
+ } else if (this->noInputTimer > 0) {
+ this->noInputTimer--;
+ this->actor.speedXZ = 8.0f;
+ }
+
+ if (this->actor.speedXZ < 6.0f) {
+ EnHorse_StartTrotting(this);
+ }
+
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.3f;
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ func_8087C1C0(this);
+ func_8013ECE0(0.0f, 120, 8, 255);
+ if (EnHorse_PlayerCanMove(this, globalCtx) == true) {
+ if ((stickMag >= 10.0f) && (Math_CosS(stickAngle) <= -0.5f)) {
+ EnHorse_StartBraking(this, globalCtx);
+ } else if (this->actor.speedXZ < 6.0f) {
+ EnHorse_StartTrotting(this);
+ } else {
+ EnHorse_MountedGallopReset(this);
+ }
+ } else {
+ EnHorse_MountedGallopReset(this);
+ }
+ }
+}
+
+void EnHorse_StartRearing(EnHorse* this) {
+ this->action = ENHORSE_ACT_REVERSE;
+ this->animationIdx = ENHORSE_ANIM_REARING;
+
+ if (sAnimationHeaders[this->type][this->animationIdx] == NULL) {
+ if (Rand_ZeroOne() > 0.5f) {
+ if (this->stateFlags & ENHORSE_DRAW) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+ func_8013ECE0(0.0f, 180, 20, 100);
+ this->stateFlags &= ~ENHORSE_STOPPING_NEIGH_SOUND;
+ }
+ EnHorse_StartMountedIdleResetAnim(this);
+ }
+
+ this->stateFlags &= ~ENHORSE_LAND2_SOUND;
+ if (this->stateFlags & ENHORSE_DRAW) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+
+ func_8013ECE0(0.0f, 180, 20, 100);
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+}
+
+void EnHorse_MountedRearing(EnHorse* this, GlobalContext* globalCtx) {
+ f32 stickMag;
+ s16 stickAngle;
+
+ this->actor.speedXZ = 0.0f;
+ if (this->curFrame > 25.0f) {
+ if (!(this->stateFlags & ENHORSE_LAND2_SOUND)) {
+ this->stateFlags |= ENHORSE_LAND2_SOUND;
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
+ }
+ func_8013ECE0(0.0f, 180, 20, 100);
+ }
+ }
+
+ EnHorse_StickDirection(&this->curStick, &stickMag, &stickAngle);
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ if (EnHorse_PlayerCanMove(this, globalCtx) == true) {
+ if (this->stateFlags & ENHORSE_FORCE_REVERSING) {
+ this->noInputTimer = 100;
+ this->noInputTimerMax = 100;
+ this->stateFlags &= ~ENHORSE_FORCE_REVERSING;
+ EnHorse_StartReversing(this);
+ } else if (this->stateFlags & ENHORSE_FORCE_WALKING) {
+ this->noInputTimer = 100;
+ this->noInputTimerMax = 100;
+ this->stateFlags &= ~ENHORSE_FORCE_WALKING;
+ EnHorse_StartWalking(this);
+ } else if (Math_CosS(stickAngle) <= -0.5f) {
+ EnHorse_StartReversingInterruptable(this);
+ } else {
+ EnHorse_StartMountedIdleResetAnim(this);
+ }
+ } else {
+ EnHorse_StartMountedIdleResetAnim(this);
+ }
+ }
+}
+
+void EnHorse_StartBraking(EnHorse* this, GlobalContext* globalCtx) {
+ this->action = ENHORSE_ACT_LOW_JUMP;
+ this->animationIdx = ENHORSE_ANIM_STOPPING;
+ if (sAnimationHeaders[this->type][this->animationIdx] == NULL) {
+ if (Rand_ZeroOne() > 0.5f) {
+ if (this->stateFlags & ENHORSE_DRAW) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+ func_8013ECE0(0.0f, 180, 20, 100);
+ this->stateFlags &= ~ENHORSE_STOPPING_NEIGH_SOUND;
+ }
+ EnHorse_StartMountedIdleResetAnim(this);
+ }
+
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_SLIP);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_SLIP);
+ }
+
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.5f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+ this->stateFlags |= ENHORSE_STOPPING_NEIGH_SOUND;
+ this->stateFlags &= ~ENHORSE_BOOST;
+}
+
+void EnHorse_Stopping(EnHorse* this, GlobalContext* globalCtx) {
+ if (this->actor.speedXZ > 0.0f) {
+ this->actor.speedXZ -= 0.6f;
+ if (this->actor.speedXZ < 0.0f) {
+ this->actor.speedXZ = 0.0f;
+ }
+ }
+
+ if ((this->stateFlags & ENHORSE_STOPPING_NEIGH_SOUND) && (this->skin.skelAnime.curFrame > 29.0f)) {
+ this->actor.speedXZ = 0.0f;
+ if ((Rand_ZeroOne() > 0.5f) &&
+ ((gSaveContext.save.entranceIndex != 0x6400) || !Cutscene_GetSceneSetupIndex(globalCtx))) {
+ if (this->stateFlags & ENHORSE_DRAW) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+ func_8013ECE0(0.0f, 180, 20, 100);
+ this->stateFlags &= ~ENHORSE_STOPPING_NEIGH_SOUND;
+ } else {
+ EnHorse_StartMountedIdleResetAnim(this);
+ }
+ }
+
+ if (this->skin.skelAnime.curFrame > 29.0f) {
+ this->actor.speedXZ = 0.0f;
+ } else if ((this->actor.speedXZ > 3.0f) && (this->stateFlags & ENHORSE_FORCE_REVERSING)) {
+ this->actor.speedXZ = 3.0f;
+ }
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ if (this->stateFlags & ENHORSE_FORCE_REVERSING) {
+ this->noInputTimer = 100;
+ this->noInputTimerMax = 100;
+ EnHorse_StartReversing(this);
+ this->stateFlags &= ~ENHORSE_FORCE_REVERSING;
+ } else {
+ EnHorse_StartMountedIdleResetAnim(this);
+ }
+ }
+}
+
+void EnHorse_StartReversingInterruptable(EnHorse* this) {
+ this->noInputTimer = 0;
+ this->noInputTimerMax = 0;
+ EnHorse_StartReversing(this);
+}
+
+void EnHorse_StartReversing(EnHorse* this) {
+ this->action = ENHORSE_ACT_HIGH_JUMP;
+ this->animationIdx = ENHORSE_ANIM_WALK;
+ this->soundTimer = 0;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_LOOP, -3.0f);
+}
+
+void EnHorse_Reverse(EnHorse* this, GlobalContext* globalCtx) {
+ f32 stickMag;
+ s16 stickAngle;
+ s16 turnAmount;
+ Player* player = GET_PLAYER(globalCtx);
+
+ EnHorse_PlayWalkingSound(this);
+ EnHorse_StickDirection(&this->curStick, &stickMag, &stickAngle);
+ if (EnHorse_PlayerCanMove(this, globalCtx) == true) {
+ if ((this->noInputTimerMax == 0) ||
+ ((this->noInputTimer > 0) && (this->noInputTimer < (this->noInputTimerMax - 20)))) {
+ if ((stickMag < 10.0f) && (this->noInputTimer <= 0)) {
+ EnHorse_StartMountedIdleResetAnim(this);
+ this->actor.speedXZ = 0.0f;
+ return;
+ } else if (stickMag < 10.0f) {
+ stickAngle = -0x7FFF;
+ } else if (Math_CosS(stickAngle) > -0.5f) {
+ this->noInputTimerMax = 0;
+ EnHorse_StartMountedIdleResetAnim(this);
+ this->actor.speedXZ = 0.0f;
+ return;
+ }
+ } else if (stickMag < 10.0f) {
+ stickAngle = -0x7FFF;
+ }
+ } else if ((player->actor.flags & ACTOR_FLAG_100) || (globalCtx->csCtx.state != 0) ||
+ (ActorCutscene_GetCurrentIndex() != -1) || (player->stateFlags1 & 0x20)) {
+ EnHorse_StartMountedIdleResetAnim(this);
+ this->actor.speedXZ = 0.0f;
+ return;
+ } else {
+ stickAngle = -0x7FFF;
+ }
+
+ this->actor.speedXZ = -2.0f;
+ turnAmount = -0x8000 - stickAngle;
+ turnAmount = CLAMP(turnAmount, -2400.0f, 2400.0f);
+ this->actor.world.rot.y += turnAmount;
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+
+ if (this->noInputTimer > 0) {
+ this->noInputTimer--;
+ if (this->noInputTimer <= 0) {
+ this->noInputTimerMax = 0;
+ }
+ }
+
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.5f * 1.5f;
+
+ if (SkelAnime_Update(&this->skin.skelAnime) && (this->noInputTimer <= 0) &&
+ (EnHorse_PlayerCanMove(this, globalCtx) == true)) {
+ if ((stickMag > 10.0f) && (Math_CosS(stickAngle) <= -0.5f)) {
+ this->noInputTimerMax = 0;
+ EnHorse_StartReversingInterruptable(this);
+ } else if (stickMag < 10.0f) {
+ this->noInputTimerMax = 0;
+ EnHorse_StartMountedIdleResetAnim(this);
+ } else {
+ EnHorse_StartReversing(this);
+ }
+ }
+}
+
+void EnHorse_LowJumpInit(EnHorse* this, GlobalContext* globalCtx) {
+ this->skin.skelAnime.curFrame = 0.0f;
+ EnHorse_StartLowJump(this, globalCtx);
+}
+
+void EnHorse_StartLowJump(EnHorse* this, GlobalContext* globalCtx) {
+ f32 curFrame;
+ Vec3s* jointTable;
+ f32 y;
+
+ this->action = ENHORSE_ACT_BRIDGE_JUMP;
+ this->animationIdx = ENHORSE_ANIM_LOW_JUMP;
+ curFrame = this->skin.skelAnime.curFrame;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.5f, curFrame,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+ this->postDrawFunc = NULL;
+ this->jumpStartY = this->actor.world.pos.y;
+ this->actor.gravity = 0.0f;
+ this->actor.velocity.y = 0.0f;
+
+ jointTable = this->skin.skelAnime.jointTable;
+ y = jointTable->y;
+ this->riderPos.y -= ((y * 0.01f) * this->unk_528) * 0.01f;
+
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
+ }
+ func_8013ECE0(0.0f, 170, 10, 10);
+}
+
+void EnHorse_Stub1(EnHorse* this) {
+}
+
+void EnHorse_LowJump(EnHorse* this, GlobalContext* globalCtx) {
+ Vec3f pad;
+ f32 temp_f0;
+ f32 curFrame;
+ Vec3s* jointTable;
+
+ this->stateFlags |= ENHORSE_JUMPING;
+
+ if (this->actor.speedXZ < 12.0f) {
+ this->actor.speedXZ = 12.0f;
+ }
+
+ if (this->actor.floorHeight != BGCHECK_Y_MIN) {
+ CollisionPoly* colPoly;
+ s32 floorBgId;
+ Vec3f pos = this->actor.world.pos;
+
+ pos.y = this->actor.floorHeight - 5.0f;
+ temp_f0 =
+ BgCheck_EntityRaycastFloor5_2(globalCtx, &globalCtx->colCtx, &colPoly, &floorBgId, &this->actor, &pos);
+ if ((this->actor.floorHeight - 120.0f) < temp_f0) {
+ this->actor.floorHeight = temp_f0;
+ this->actor.floorPoly = colPoly;
+ this->actor.floorBgId = floorBgId;
+ }
+ }
+
+ curFrame = this->skin.skelAnime.curFrame;
+
+ if (curFrame > 17.0f) {
+ this->actor.gravity = -3.5f;
+ if (this->actor.velocity.y == 0.0f) {
+ this->actor.velocity.y = -6.0f;
+ }
+ if (this->actor.world.pos.y < (this->actor.floorHeight + 90.0f)) {
+ this->skin.skelAnime.playSpeed = 1.5f;
+ } else {
+ this->skin.skelAnime.playSpeed = 0.0f;
+ }
+ } else {
+ jointTable = this->skin.skelAnime.jointTable;
+ temp_f0 = jointTable->y;
+
+ this->actor.world.pos.y = this->jumpStartY + (temp_f0 * 0.01f * this->unk_528 * 0.01f);
+ }
+
+ 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) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
+ }
+ func_8013ECE0(0.0f, 255, 10, 80);
+ this->stateFlags &= ~ENHORSE_JUMPING;
+ this->actor.gravity = -3.5f;
+ this->actor.world.pos.y = this->actor.floorHeight;
+ EnHorse_JumpLanding(this, globalCtx);
+ }
+}
+
+void EnHorse_HighJumpInit(EnHorse* this, GlobalContext* globalCtx) {
+ this->skin.skelAnime.curFrame = 0.0f;
+ EnHorse_StartHighJump(this, globalCtx);
+}
+
+void EnHorse_StartHighJump(EnHorse* this, GlobalContext* globalCtx) {
+ f32 curFrame;
+ Vec3s* jointTable;
+ f32 y;
+
+ this->action = ENHORSE_ACT_CS_UPDATE;
+ this->animationIdx = ENHORSE_ANIM_HIGH_JUMP;
+ curFrame = this->skin.skelAnime.curFrame;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.5f, curFrame,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+
+ this->postDrawFunc = NULL;
+ this->jumpStartY = this->actor.world.pos.y;
+ this->actor.gravity = 0.0f;
+ this->actor.velocity.y = 0.0f;
+
+ jointTable = this->skin.skelAnime.jointTable;
+ y = jointTable->y;
+ this->riderPos.y -= ((y * 0.01f) * this->unk_528) * 0.01f;
+
+ this->stateFlags |= ENHORSE_CALC_RIDER_POS;
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
+ }
+ func_8013ECE0(0.0f, 170, 10, 10);
+}
+
+void EnHorse_Stub2(EnHorse* this) {
+}
+
+void EnHorse_HighJump(EnHorse* this, GlobalContext* globalCtx) {
+ Vec3f pad;
+ f32 temp_f0;
+ f32 curFrame;
+ Vec3s* jointTable;
+
+ this->stateFlags |= ENHORSE_JUMPING;
+
+ if (this->actor.speedXZ < 13.0f) {
+ this->actor.speedXZ = 13.0f;
+ }
+
+ if (this->actor.floorHeight != BGCHECK_Y_MIN) {
+ CollisionPoly* colPoly;
+ s32 floorBgId;
+ Vec3f pos = this->actor.world.pos;
+
+ pos.y = this->actor.floorHeight - 5.0f;
+ temp_f0 =
+ BgCheck_EntityRaycastFloor5_2(globalCtx, &globalCtx->colCtx, &colPoly, &floorBgId, &this->actor, &pos);
+ if ((this->actor.floorHeight - 120.0f) < temp_f0) {
+ this->actor.floorHeight = temp_f0;
+ this->actor.floorPoly = colPoly;
+ this->actor.floorBgId = floorBgId;
+ }
+ }
+
+ curFrame = this->skin.skelAnime.curFrame;
+
+ if (curFrame > 23.0f) {
+ this->actor.gravity = -3.5f;
+ if (this->actor.velocity.y == 0.0f) {
+ this->actor.velocity.y = -10.5f;
+ }
+ if (this->actor.world.pos.y < (this->actor.floorHeight + 90.0f)) {
+ this->skin.skelAnime.playSpeed = 1.5f;
+ } else {
+ this->skin.skelAnime.playSpeed = 0.0f;
+ }
+ } else {
+ jointTable = this->skin.skelAnime.jointTable;
+ temp_f0 = jointTable->y;
+ this->actor.world.pos.y = this->jumpStartY + (temp_f0 * 0.01f * this->unk_528 * 0.01f);
+ }
+
+ 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) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
+ }
+ func_8013ECE0(0.0f, 255, 10, 80);
+ this->stateFlags &= ~ENHORSE_JUMPING;
+ this->actor.gravity = -3.5f;
+ this->actor.world.pos.y = this->actor.floorHeight;
+ func_800B1598(globalCtx, 25.0f, &this->actor.world.pos);
+ EnHorse_JumpLanding(this, globalCtx);
+ }
+}
+
+void EnHorse_InitInactive(EnHorse* this) {
+ this->colliderCylinder1.base.ocFlags1 &= ~OC1_ON;
+ this->colliderCylinder2.base.ocFlags1 &= ~OC1_ON;
+ this->colliderJntSph.base.ocFlags1 &= ~OC1_ON;
+ this->action = ENHORSE_ACT_INACTIVE;
+ this->animationIdx = ENHORSE_ANIM_WALK;
+ this->stateFlags |= ENHORSE_INACTIVE;
+ this->followTimer = 0;
+}
+
+void EnHorse_Inactive(EnHorse* this, GlobalContext* globalCtx) {
+ if ((D_801BDAA4 != 0) && (this->type == HORSE_2)) {
+ D_801BDAA4 = 0;
+ if (EnHorse_Spawn(this, globalCtx)) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_NEIGH);
+ }
+ this->stateFlags &= ~ENHORSE_INACTIVE;
+ }
+ }
+
+ if (!(this->stateFlags & ENHORSE_INACTIVE)) {
+ this->followTimer = 0;
+ EnHorse_SetFollowAnimation(this, globalCtx);
+ this->actor.params = ENHORSE_0;
+ this->colliderCylinder1.base.ocFlags1 |= OC1_ON;
+ this->colliderCylinder2.base.ocFlags1 |= OC1_ON;
+ this->colliderJntSph.base.ocFlags1 |= OC1_ON;
+ }
+}
+
+void EnHorse_PlayIdleAnimation(EnHorse* this, s32 anim, f32 morphFrames, f32 startFrames) {
+ this->action = ENHORSE_ACT_IDLE;
+ this->actor.speedXZ = 0.0f;
+
+ if ((anim != ENHORSE_ANIM_IDLE) && (anim != ENHORSE_ANIM_WHINNEY) && (anim != ENHORSE_ANIM_REARING)) {
+ anim = ENHORSE_ANIM_IDLE;
+ }
+
+ if (sAnimationHeaders[this->type][anim] == NULL) {
+ anim = ENHORSE_ANIM_IDLE;
+ }
+
+ if (anim != this->animationIdx) {
+ this->animationIdx = anim;
+ if (anim == ENHORSE_ANIM_IDLE) {
+ this->stateFlags &= ~ENHORSE_SANDDUST_SOUND;
+ } else {
+ if (this->animationIdx == ENHORSE_ANIM_WHINNEY) {
+ if (this->stateFlags & ENHORSE_DRAW) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_GROAN);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_GROAN);
+ }
+ }
+ } else if (this->animationIdx == ENHORSE_ANIM_REARING) {
+ if (this->stateFlags & ENHORSE_DRAW) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+ this->stateFlags &= ~ENHORSE_LAND2_SOUND;
+ }
+ }
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, startFrames,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ morphFrames);
+ }
+}
+
+void EnHorse_ChangeIdleAnimation(EnHorse* this, s32 anim, f32 morphFrames) {
+ EnHorse_PlayIdleAnimation(this, anim, morphFrames, this->curFrame);
+}
+
+void EnHorse_ResetIdleAnimation(EnHorse* this) {
+ this->animationIdx = ENHORSE_ANIM_WALK;
+ EnHorse_PlayIdleAnimation(this, this->animationIdx, 0.0f, 0.0f);
+}
+
+void EnHorse_StartIdleRidable(EnHorse* this) {
+ EnHorse_ResetIdleAnimation(this);
+ this->stateFlags &= ~ENHORSE_UNRIDEABLE;
+}
+
+void EnHorse_Idle(EnHorse* this, GlobalContext* globalCtx) {
+ this->actor.speedXZ = 0.0f;
+ EnHorse_IdleAnimSounds(this, globalCtx);
+
+ if ((D_801BDAA4 != 0) && (this->type == HORSE_2)) {
+ D_801BDAA4 = 0;
+ if (!func_8087C38C(globalCtx, this, &this->actor.world.pos)) {
+ if (EnHorse_Spawn(this, globalCtx)) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_NEIGH);
+ }
+ this->followTimer = 0;
+ EnHorse_SetFollowAnimation(this, globalCtx);
+ }
+ } else {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_NEIGH);
+ }
+ this->followTimer = 0;
+ EnHorse_StartMovingAnimation(this, 6, -3.0f, 0.0f);
+ }
+ }
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ s32 idleAnimIdx = 0;
+
+ if (this->animationIdx != 0) {
+ if (this->animationIdx == 1) {
+ idleAnimIdx = 1;
+ } else if (this->animationIdx == 3) {
+ idleAnimIdx = 2;
+ }
+ }
+ // Play one of the two other idle animations
+ EnHorse_PlayIdleAnimation(this, sIdleAnimIds[((Rand_ZeroOne() > 0.5f) ? 0 : 1) + idleAnimIdx * 2], 0.0f, 0.0f);
+ }
+}
+
+void EnHorse_StartMovingAnimation(EnHorse* this, s32 anim, f32 morphFrames, f32 startFrames) {
+ this->action = ENHORSE_ACT_FOLLOW_PLAYER;
+ this->stateFlags &= ~ENHORSE_TURNING_TO_PLAYER;
+
+ if ((anim != ENHORSE_ANIM_TROT) && (anim != ENHORSE_ANIM_GALLOP) && (anim != ENHORSE_ANIM_WALK)) {
+ anim = ENHORSE_ANIM_WALK;
+ }
+
+ if (anim != this->animationIdx) {
+ this->animationIdx = anim;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, startFrames,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ morphFrames);
+ } else {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, startFrames,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ 0.0f);
+ }
+}
+
+void EnHorse_SetFollowAnimation(EnHorse* this, GlobalContext* globalCtx) {
+ s32 anim = ENHORSE_ANIM_WALK;
+ f32 distToPlayer = Actor_XZDistanceBetweenActors(&this->actor, &GET_PLAYER(globalCtx)->actor);
+
+ if (distToPlayer > 400.0f) {
+ anim = ENHORSE_ANIM_GALLOP;
+ } else if (!(distToPlayer <= 300.0f) && (distToPlayer <= 400.0f)) {
+ anim = ENHORSE_ANIM_TROT;
+ }
+
+ if (this->animationIdx == ENHORSE_ANIM_GALLOP) {
+ if (distToPlayer > 400.0f) {
+ anim = ENHORSE_ANIM_GALLOP;
+ } else {
+ anim = ENHORSE_ANIM_TROT;
+ }
+ } else if (this->animationIdx == ENHORSE_ANIM_TROT) {
+ if (distToPlayer > 400.0f) {
+ anim = ENHORSE_ANIM_GALLOP;
+ } else if (distToPlayer < 300.0f) {
+ anim = ENHORSE_ANIM_WALK;
+ } else {
+ anim = ENHORSE_ANIM_TROT;
+ }
+ } else if (this->animationIdx == ENHORSE_ANIM_WALK) {
+ if (distToPlayer > 300.0f) {
+ anim = ENHORSE_ANIM_TROT;
+ } else {
+ anim = ENHORSE_ANIM_WALK;
+ }
+ }
+
+ EnHorse_StartMovingAnimation(this, anim, -3.0f, 0.0f);
+}
+
+void EnHorse_FollowPlayer(EnHorse* this, GlobalContext* globalCtx) {
+ f32 distToPlayer;
+
+ D_801BDAA4 = 0;
+ distToPlayer = Actor_XZDistanceBetweenActors(&this->actor, &GET_PLAYER(globalCtx)->actor);
+
+ if (((this->playerDir == PLAYER_DIR_BACK_R) || (this->playerDir == PLAYER_DIR_BACK_L)) && (distToPlayer > 300.0f) &&
+ !(this->stateFlags & ENHORSE_TURNING_TO_PLAYER)) {
+ f32 angleDiff;
+
+ this->animationIdx = ENHORSE_ANIM_REARING;
+ this->stateFlags |= ENHORSE_TURNING_TO_PLAYER;
+ this->angleToPlayer = Actor_YawBetweenActors(&this->actor, &GET_PLAYER(globalCtx)->actor);
+
+ angleDiff = (f32)this->angleToPlayer - this->actor.world.rot.y;
+ if (angleDiff > 0x7FFF) {
+ angleDiff -= 0x7FFF;
+ } else if (angleDiff < -0x7FFF) {
+ angleDiff += 0x7FFF;
+ }
+
+ this->followPlayerTurnSpeed =
+ angleDiff / Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]);
+
+ Animation_PlayOnce(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx]);
+ this->skin.skelAnime.playSpeed = 1.0f;
+ this->stateFlags &= ~ENHORSE_LAND2_SOUND;
+ } else if (this->stateFlags & ENHORSE_TURNING_TO_PLAYER) {
+ this->actor.world.rot.y += this->followPlayerTurnSpeed;
+ 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) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
+ }
+ }
+ } else {
+ EnHorse_RotateToPlayer(this, globalCtx);
+ }
+
+ if (this->animationIdx == ENHORSE_ANIM_GALLOP) {
+ this->actor.speedXZ = 8.0f;
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.3f;
+ } else {
+ if (this->animationIdx == ENHORSE_ANIM_TROT) {
+ this->actor.speedXZ = 6.0f;
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.375f;
+ } else if (this->animationIdx == ENHORSE_ANIM_WALK) {
+ this->actor.speedXZ = 3.0f;
+ EnHorse_PlayWalkingSound(this);
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.75f;
+ } else {
+ this->actor.speedXZ = 0.0f;
+ this->skin.skelAnime.playSpeed = 1.0f;
+ }
+ }
+
+ if (!(this->stateFlags & ENHORSE_TURNING_TO_PLAYER)) {
+ this->followTimer++;
+ if (this->followTimer > 300) {
+ EnHorse_StartIdleRidable(this);
+ if (this->stateFlags & ENHORSE_DRAW) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+ }
+ }
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ if (this->animationIdx == ENHORSE_ANIM_GALLOP) {
+ func_8087C1C0(this);
+ } else if (this->animationIdx == ENHORSE_ANIM_TROT) {
+ func_8087C178(this);
+ }
+
+ this->stateFlags &= ~ENHORSE_TURNING_TO_PLAYER;
+
+ if (distToPlayer < 100.0f) {
+ EnHorse_StartIdleRidable(this);
+ } else {
+ EnHorse_SetFollowAnimation(this, globalCtx);
+ }
+ }
+}
+
+void EnHorse_InitIngoHorse(EnHorse* this) {
+ this->curRaceWaypoint = 0;
+ this->soundTimer = 0;
+ this->actor.speedXZ = 0.0f;
+ EnHorse_UpdateIngoHorseAnim(this);
+ if (this->stateFlags & ENHORSE_DRAW) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_IT_INGO_HORSE_NEIGH);
+ }
+}
+
+void EnHorse_SetIngoAnimation(s32 anim, f32 curFrame, s32 arg2, s16* animIdxOut) {
+ *animIdxOut = sIngoAnimations[anim];
+ if (arg2 == 1) {
+ if (anim == 5) {
+ *animIdxOut = 4;
+ } else if (anim == 6) {
+ *animIdxOut = 3;
+ }
+ }
+}
+
+void EnHorse_UpdateIngoHorseAnim(EnHorse* this) {
+ s32 animChanged = false;
+ f32 animSpeed;
+
+ this->action = ENHORSE_ACT_INGO_RACE;
+ this->stateFlags &= ~ENHORSE_SANDDUST_SOUND;
+
+ if (this->actor.speedXZ == 0.0f) {
+ if (this->animationIdx != ENHORSE_ANIM_IDLE) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_IDLE;
+ } else if (this->actor.speedXZ <= 3.0f) {
+ if (this->animationIdx != ENHORSE_ANIM_WALK) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_WALK;
+ } else if (this->actor.speedXZ <= 6.0f) {
+ if (this->animationIdx != ENHORSE_ANIM_TROT) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_TROT;
+ } else {
+ if (this->animationIdx != ENHORSE_ANIM_GALLOP) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ }
+
+ if (this->animationIdx == ENHORSE_ANIM_WALK) {
+ animSpeed = this->actor.speedXZ * 0.5f;
+ } else if (this->animationIdx == ENHORSE_ANIM_TROT) {
+ animSpeed = this->actor.speedXZ * 0.25f;
+ if (this->type == HORSE_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) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
+ }
+ } else {
+ animSpeed = 1.0f;
+ }
+
+ if (animChanged == true) {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ sPlaybackSpeeds[this->animationIdx] * animSpeed * 1.5f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ -3.0f);
+ } else {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ sPlaybackSpeeds[this->animationIdx] * animSpeed * 1.5f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ 0.0f);
+ }
+}
+
+void EnHorse_UpdateIngoRace(EnHorse* this, GlobalContext* globalCtx) {
+ f32 playSpeed;
+
+ if ((this->animationIdx == ENHORSE_ANIM_IDLE) || (this->animationIdx == ENHORSE_ANIM_WHINNEY)) {
+ EnHorse_IdleAnimSounds(this, globalCtx);
+ } else if (this->animationIdx == ENHORSE_ANIM_WALK) {
+ EnHorse_PlayWalkingSound(this);
+ }
+
+ if (!this->inRace) {
+ this->actor.speedXZ = 0.0f;
+ this->rider->actor.speedXZ = 0.0f;
+ if (this->animationIdx != ENHORSE_ANIM_IDLE) {
+ EnHorse_UpdateIngoHorseAnim(this);
+ }
+ }
+
+ if (this->animationIdx == ENHORSE_ANIM_WALK) {
+ playSpeed = this->actor.speedXZ * 0.5f;
+ } else if (this->animationIdx == 5) {
+ playSpeed = this->actor.speedXZ * 0.25f;
+ } else if (this->animationIdx == 6) {
+ playSpeed = this->actor.speedXZ * 0.2f;
+ } else {
+ playSpeed = 1.0f;
+ }
+ this->skin.skelAnime.playSpeed = playSpeed;
+
+ if (SkelAnime_Update(&this->skin.skelAnime) ||
+ ((this->animationIdx == ENHORSE_ANIM_IDLE) && (this->actor.speedXZ != 0.0f))) {
+ EnHorse_UpdateIngoHorseAnim(this);
+ }
+}
+
+void func_8088126C(EnHorse* this, GlobalContext* globalCtx) {
+ this->skin.skelAnime.curFrame = 0.0f;
+ func_80881290(this, globalCtx);
+}
+
+void func_80881290(EnHorse* this, GlobalContext* globalCtx) {
+ f32 curFrame;
+
+ this->action = ENHORSE_ACT_MOUNTED_IDLE_WHINNEYING;
+ this->animationIdx = ENHORSE_ANIM_HIGH_JUMP;
+ curFrame = this->skin.skelAnime.curFrame;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.5f, curFrame,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+ this->postDrawFunc = NULL;
+ this->actor.gravity = 0.0f;
+ this->actor.velocity.y = 0.0f;
+ this->jumpStartY = this->actor.world.pos.y;
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
+ }
+ func_8013ECE0(0.0f, 170, 10, 10);
+}
+
+void func_80881398(EnHorse* this, GlobalContext* globalCtx) {
+ Vec3s* jointTable;
+ f32 y;
+ s32 animeUpdated;
+ f32 curFrame;
+
+ this->stateFlags |= ENHORSE_JUMPING;
+ if (this->actor.speedXZ < 14.0f) {
+ this->actor.speedXZ = 14.0f;
+ }
+
+ animeUpdated = SkelAnime_Update(&this->skin.skelAnime);
+ curFrame = this->skin.skelAnime.curFrame;
+
+ if (curFrame > 23.0f) {
+ this->actor.gravity = -3.5f;
+ if (this->actor.velocity.y == 0.0f) {
+ this->actor.velocity.y = -10.5f;
+ }
+ if (this->actor.world.pos.y < (this->actor.floorHeight + 90.0f)) {
+ this->skin.skelAnime.playSpeed = 1.5f;
+ } else {
+ this->skin.skelAnime.playSpeed = 0.0f;
+ }
+ } else {
+ jointTable = this->skin.skelAnime.jointTable;
+ y = jointTable->y;
+ this->actor.world.pos.y = this->jumpStartY + (y * 0.01f * this->unk_528 * 0.01f);
+ }
+
+ if (animeUpdated || ((curFrame > 17.0f) &&
+ (this->actor.world.pos.y < ((this->actor.floorHeight - this->actor.velocity.y) + 80.0f)))) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
+ }
+ func_8013ECE0(0.0f, 255, 10, 80);
+ this->stateFlags &= ~ENHORSE_JUMPING;
+ this->stateFlags &= ~ENHORSE_FLAG_30;
+ this->actor.gravity = -3.5f;
+ this->actor.world.pos.y = this->actor.floorHeight;
+ func_800B1598(globalCtx, 25.0f, &this->actor.world.pos);
+ func_8088159C(this, globalCtx);
+ }
+}
+
+void func_8088159C(EnHorse* this, GlobalContext* globalCtx) {
+ Vec3s* jointTable;
+ f32 y;
+
+ this->action = ENHORSE_ACT_MOUNTED_IDLE;
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ Animation_PlayOnce(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx]);
+ jointTable = this->skin.skelAnime.jointTable;
+ y = jointTable->y;
+ this->riderPos.y += y * 0.01f * this->unk_528 * 0.01f;
+ this->postDrawFunc = NULL;
+}
+
+void func_80881634(EnHorse* this) {
+ this->curRaceWaypoint = 0;
+ this->soundTimer = 0;
+ this->actor.speedXZ = 0.0f;
+ func_8088168C(this);
+ if (this->stateFlags & ENHORSE_DRAW) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_IT_INGO_HORSE_NEIGH);
+ }
+}
+
+void func_8088168C(EnHorse* this) {
+ s32 animChanged = false;
+ f32 animSpeed;
+ f32 finalAnimSpeed;
+
+ this->action = ENHORSE_ACT_MOUNTED_IDLE;
+ this->stateFlags &= ~ENHORSE_SANDDUST_SOUND;
+
+ if (this->actor.speedXZ == 0.0f) {
+ if (this->animationIdx != ENHORSE_ANIM_IDLE) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_IDLE;
+ } else if (this->actor.speedXZ <= 3.0f) {
+ if (this->animationIdx != ENHORSE_ANIM_WALK) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_WALK;
+ } else if (this->actor.speedXZ <= 6.0f) {
+ if (this->animationIdx != ENHORSE_ANIM_TROT) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_TROT;
+ } else {
+ if (this->animationIdx != ENHORSE_ANIM_GALLOP) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ }
+
+ if (this->animationIdx == ENHORSE_ANIM_WALK) {
+ animSpeed = this->actor.speedXZ * 0.5f;
+ } else if (this->animationIdx == ENHORSE_ANIM_TROT) {
+ animSpeed = this->actor.speedXZ * 0.25f;
+ if (this->type == HORSE_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) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
+ }
+ } else {
+ animSpeed = 1.0f;
+ }
+
+ finalAnimSpeed = sPlaybackSpeeds[this->animationIdx] * animSpeed * 1.5f;
+ if (finalAnimSpeed < 1.0f) {
+ finalAnimSpeed = 1.0f;
+ }
+
+ if (animChanged == true) {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], finalAnimSpeed, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ -3.0f);
+ } else {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], finalAnimSpeed, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ 0.0f);
+ }
+}
+
+void func_808819D8(EnHorse* this, GlobalContext* globalCtx) {
+ Path* path;
+ f32 animSpeed;
+
+ if ((this->animationIdx == ENHORSE_ANIM_IDLE) || (this->animationIdx == ENHORSE_ANIM_WHINNEY)) {
+ EnHorse_IdleAnimSounds(this, globalCtx);
+ } else if (this->animationIdx == ENHORSE_ANIM_WALK) {
+ EnHorse_PlayWalkingSound(this);
+ }
+
+ if (!this->inRace) {
+ this->actor.speedXZ = 0.0f;
+ this->rider->actor.speedXZ = 0.0f;
+ if (this->animationIdx != ENHORSE_ANIM_IDLE) {
+ EnHorse_UpdateIngoHorseAnim(this);
+ }
+ }
+
+ if (this->actor.params == ENHORSE_4) {
+ path = &globalCtx->setupPathList[0];
+ func_8087B7C0(this, globalCtx, path);
+ } else if (this->actor.params == ENHORSE_5) {
+ path = &globalCtx->setupPathList[1];
+ func_8087B7C0(this, globalCtx, path);
+ }
+
+ if (!this->inRace) {
+ this->actor.speedXZ = 0.0f;
+ if (this->animationIdx != ENHORSE_ANIM_IDLE) {
+ func_8088168C(this);
+ }
+ }
+
+ if (this->animationIdx == ENHORSE_ANIM_WALK) {
+ animSpeed = this->actor.speedXZ * 0.5f;
+ } else if (this->animationIdx == ENHORSE_ANIM_TROT) {
+ animSpeed = this->actor.speedXZ * 0.25f;
+ } else if (this->animationIdx == ENHORSE_ANIM_GALLOP) {
+ animSpeed = this->actor.speedXZ * 0.2f;
+ } else {
+ animSpeed = 1.0f;
+ }
+ this->skin.skelAnime.playSpeed = animSpeed;
+
+ if (SkelAnime_Update(&this->skin.skelAnime) ||
+ ((this->animationIdx == ENHORSE_ANIM_IDLE) && (this->actor.speedXZ != 0.0f))) {
+ func_8088168C(this);
+ }
+
+ if ((gSaveContext.save.weekEventReg[92] & (1 | 2 | 4)) == 3) {
+ this->rider->unk488 = 7;
+ } else {
+ EnHorse_SetIngoAnimation(this->animationIdx, this->skin.skelAnime.curFrame, this->unk_394 & 1,
+ &this->rider->unk488);
+ }
+}
+
+void EnHorse_CsMoveInit(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ this->cutsceneAction = 1;
+ Animation_PlayOnceSetSpeed(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ this->actor.speedXZ * 0.2f * 1.5f);
+}
+
+void EnHorse_CsMoveToPoint(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ Vec3f endPos;
+ s32 pad;
+
+ endPos.x = action->endPos.x;
+ endPos.y = action->endPos.y;
+ endPos.z = action->endPos.z;
+
+ if (Math3D_Distance(&endPos, &this->actor.world.pos) > 8.0f) {
+ EnHorse_RotateToPoint(this, globalCtx, &endPos, 0x320);
+ this->actor.speedXZ = 8.0f;
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.3f;
+ } else {
+ this->actor.world.pos = endPos;
+ this->actor.speedXZ = 0.0f;
+ }
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ func_8087C1C0(this);
+ func_8013ECE0(0.0f, 120, 8, 255);
+ Animation_PlayOnceSetSpeed(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ this->actor.speedXZ * 0.3f);
+ }
+}
+
+void EnHorse_CsSetAnimHighJump(EnHorse* this, GlobalContext* globalCtx) {
+ this->skin.skelAnime.curFrame = 0.0f;
+ EnHorse_CsPlayHighJumpAnim(this, globalCtx);
+}
+
+void EnHorse_CsPlayHighJumpAnim(EnHorse* this, GlobalContext* globalCtx) {
+ f32 curFrame;
+ f32 y;
+ Vec3s* jointTable;
+
+ this->animationIdx = ENHORSE_ANIM_HIGH_JUMP;
+ curFrame = this->skin.skelAnime.curFrame;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.5f, curFrame,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+ this->postDrawFunc = NULL;
+ this->jumpStartY = this->actor.world.pos.y;
+ this->actor.gravity = 0.0f;
+ this->actor.velocity.y = 0.0f;
+
+ jointTable = this->skin.skelAnime.jointTable;
+ y = jointTable->y;
+ this->riderPos.y -= y * 0.01f * this->unk_528 * 0.01f;
+
+ this->stateFlags |= ENHORSE_ANIM_HIGH_JUMP;
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_JUMP);
+ }
+ func_8013ECE0(0.0f, 170, 10, 10);
+}
+
+void EnHorse_CsJumpInit(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ EnHorse_CsSetAnimHighJump(this, globalCtx);
+ this->cutsceneAction = 2;
+ this->cutsceneFlags &= ~1;
+}
+
+void EnHorse_CsJump(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ f32 curFrame;
+ f32 y;
+ Vec3s* jointTable;
+ s32 pad[2];
+
+ if (this->cutsceneFlags & 1) {
+ EnHorse_CsMoveToPoint(this, globalCtx, action);
+ return;
+ }
+
+ curFrame = this->skin.skelAnime.curFrame;
+ this->actor.speedXZ = 13.0f;
+ this->stateFlags |= ENHORSE_JUMPING;
+
+ if (curFrame > 19.0f) {
+ this->actor.gravity = -3.5f;
+ if (this->actor.velocity.y == 0.0f) {
+ this->actor.velocity.y = -10.5f;
+ }
+ if (this->actor.world.pos.y < (this->actor.floorHeight + 90.0f)) {
+ this->skin.skelAnime.playSpeed = 1.5f;
+ } else {
+ this->skin.skelAnime.playSpeed = 0.0f;
+ }
+ } else {
+ jointTable = this->skin.skelAnime.jointTable;
+ y = jointTable->y;
+
+ this->actor.world.pos.y = this->jumpStartY + (y * 0.01f * this->unk_528 * 0.01f);
+ }
+
+ if (SkelAnime_Update(&this->skin.skelAnime) ||
+ ((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) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_LAND);
+ }
+ func_8013ECE0(0.0f, 255, 10, 80);
+ this->stateFlags &= ~ENHORSE_JUMPING;
+ this->actor.gravity = -3.5f;
+ this->actor.velocity.y = 0.0f;
+ this->actor.world.pos.y = this->actor.floorHeight;
+ func_800B1598(globalCtx, 25.0f, &this->actor.world.pos);
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ Animation_PlayOnceSetSpeed(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ sPlaybackSpeeds[6]);
+
+ jointTable = this->skin.skelAnime.jointTable;
+ y = jointTable->y;
+ this->riderPos.y += y * 0.01f * this->unk_528 * 0.01f;
+
+ this->postDrawFunc = NULL;
+ }
+}
+
+void EnHorse_CsRearingInit(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ this->animationIdx = ENHORSE_ANIM_REARING;
+ this->cutsceneAction = 3;
+ this->cutsceneFlags &= ~4;
+ this->stateFlags &= ~ENHORSE_LAND2_SOUND;
+ if (this->stateFlags & ENHORSE_DRAW) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+}
+
+void EnHorse_CsRearing(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ this->actor.speedXZ = 0.0f;
+ if (this->curFrame > 25.0f) {
+ if (!(this->stateFlags & ENHORSE_LAND2_SOUND)) {
+ this->stateFlags |= ENHORSE_LAND2_SOUND;
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
+ }
+ }
+ }
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ this->animationIdx = ENHORSE_ANIM_IDLE;
+ if (!(this->cutsceneFlags & 4)) {
+ this->cutsceneFlags |= 4;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ -3.0f);
+ } else {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_LOOP,
+ 0.0f);
+ }
+ }
+}
+
+void EnHorse_WarpMoveInit(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ this->actor.world.pos.x = action->startPos.x;
+ this->actor.world.pos.y = action->startPos.y;
+ this->actor.world.pos.z = action->startPos.z;
+ this->actor.prevPos = this->actor.world.pos;
+
+ this->actor.world.rot.y = action->urot.y;
+ this->actor.shape.rot = this->actor.world.rot;
+
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ this->cutsceneAction = 4;
+ Animation_PlayOnceSetSpeed(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ this->actor.speedXZ * 0.3f);
+}
+
+void EnHorse_CsWarpMoveToPoint(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ Vec3f endPos;
+ s32 pad;
+
+ endPos.x = action->endPos.x;
+ endPos.y = action->endPos.y;
+ endPos.z = action->endPos.z;
+
+ if (Math3D_Distance(&endPos, &this->actor.world.pos) > 8.0f) {
+ EnHorse_RotateToPoint(this, globalCtx, &endPos, 0x320);
+ this->actor.speedXZ = 8.0f;
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.3f;
+ } else {
+ this->actor.world.pos = endPos;
+ this->actor.speedXZ = 0.0f;
+ }
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ func_8087C1C0(this);
+ func_8013ECE0(0.0f, 120, 8, 255);
+ Animation_PlayOnceSetSpeed(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ this->actor.speedXZ * 0.3f);
+ }
+}
+
+void EnHorse_CsWarpRearingInit(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ this->actor.world.pos.x = action->startPos.x;
+ this->actor.world.pos.y = action->startPos.y;
+ this->actor.world.pos.z = action->startPos.z;
+ this->actor.prevPos = this->actor.world.pos;
+
+ this->actor.world.rot.y = action->urot.y;
+ this->actor.shape.rot = this->actor.world.rot;
+
+ this->animationIdx = ENHORSE_ANIM_REARING;
+ this->cutsceneAction = 5;
+ this->cutsceneFlags &= ~4;
+ this->stateFlags &= ~ENHORSE_LAND2_SOUND;
+
+ if (this->stateFlags & ENHORSE_DRAW) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+}
+
+void EnHorse_CsWarpRearing(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ this->actor.speedXZ = 0.0f;
+ if (this->curFrame > 25.0f) {
+ if (!(this->stateFlags & ENHORSE_LAND2_SOUND)) {
+ this->stateFlags |= ENHORSE_LAND2_SOUND;
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
+ }
+ }
+ }
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ this->animationIdx = ENHORSE_ANIM_IDLE;
+ if (!(this->cutsceneFlags & 4)) {
+ this->cutsceneFlags |= 4;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ -3.0f);
+ } else {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_LOOP,
+ 0.0f);
+ }
+ }
+}
+
+void EnHorse_InitCutscene(EnHorse* this, GlobalContext* globalCtx) {
+ this->playerControlled = false;
+ this->action = ENHORSE_ACT_HBA;
+ this->cutsceneAction = 0;
+ this->actor.speedXZ = 0.0f;
+}
+
+s32 EnHorse_GetCutsceneFunctionIndex(s32 csAction) {
+ s32 numActions = ARRAY_COUNT(sCsActionTable); // prevents unrolling
+ s32 i;
+
+ for (i = 0; i < numActions; i++) {
+ if (csAction == sCsActionTable[i].csAction) {
+ return sCsActionTable[i].csFuncIdx;
+ }
+
+ if (csAction < sCsActionTable[i].csAction) {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+void EnHorse_CutsceneUpdate(EnHorse* this, GlobalContext* globalCtx) {
+ s32 csFunctionIdx;
+ CsCmdActorAction* playerAction = globalCtx->csCtx.playerAction;
+
+ if (globalCtx->csCtx.state == 3) {
+ this->playerControlled = true;
+ this->actor.params = ENHORSE_12;
+ this->action = ENHORSE_ACT_IDLE;
+ EnHorse_Freeze(this, globalCtx);
+ return;
+ }
+
+ if (playerAction != NULL) {
+ csFunctionIdx = EnHorse_GetCutsceneFunctionIndex(playerAction->action);
+ if (csFunctionIdx != 0) {
+ if (csFunctionIdx != this->cutsceneAction) {
+ if (this->cutsceneAction == 0) {
+ this->actor.world.pos.x = playerAction->startPos.x;
+ this->actor.world.pos.y = playerAction->startPos.y;
+ this->actor.world.pos.z = playerAction->startPos.z;
+
+ this->actor.world.rot.y = playerAction->urot.y;
+ this->actor.shape.rot = this->actor.world.rot;
+ this->actor.prevPos = this->actor.world.pos;
+ }
+ this->cutsceneAction = csFunctionIdx;
+ sCutsceneInitFuncs[csFunctionIdx](this, globalCtx, playerAction);
+ }
+ sCutsceneActionFuncs[this->cutsceneAction](this, globalCtx, playerAction);
+ }
+ }
+}
+
+s32 EnHorse_UpdateHbaRaceInfo(EnHorse* this, GlobalContext* globalCtx, RaceInfo* raceInfo) {
+ Vec3f pos;
+ f32 px;
+ f32 pz;
+ f32 d;
+
+ EnHorse_RaceWaypointPos(raceInfo->waypoints, this->curRaceWaypoint, &pos);
+ func_8017B7F8(&pos, raceInfo->waypoints[this->curRaceWaypoint].angle, &px, &pz, &d);
+
+ if ((this->curRaceWaypoint >= (raceInfo->numWaypoints - 1)) &&
+ (Math3D_Distance(&pos, &this->actor.world.pos) < DREG(8))) {
+ this->hbaFlags |= 2;
+ }
+
+ if (((this->actor.world.pos.x * px) + (pz * this->actor.world.pos.z) + d) > 0.0f) {
+ this->curRaceWaypoint++;
+ if (this->curRaceWaypoint >= raceInfo->numWaypoints) {
+ this->hbaFlags |= 1;
+ return true;
+ }
+ }
+
+ if (!(this->hbaFlags & 1)) {
+ EnHorse_RotateToPoint(this, globalCtx, &pos, 0x640);
+ }
+
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+ if ((this->actor.speedXZ < raceInfo->waypoints[this->curRaceWaypoint].speed) && !(this->hbaFlags & 1)) {
+ this->actor.speedXZ += 0.4f;
+ } else {
+ this->actor.speedXZ -= 0.4f;
+ if (this->actor.speedXZ < 0.0f) {
+ this->actor.speedXZ = 0.0f;
+ }
+ }
+ return false;
+}
+
+void EnHorse_InitHorsebackArchery(EnHorse* this) {
+ this->hbaStarted = 0;
+ this->soundTimer = 0;
+ this->curRaceWaypoint = 0;
+ this->hbaTimer = 0;
+ this->actor.speedXZ = 0.0f;
+ EnHorse_UpdateHbaAnim(this);
+}
+
+void EnHorse_UpdateHbaAnim(EnHorse* this) {
+ s32 animChanged = false;
+ f32 animSpeed;
+
+ this->action = ENHORSE_ACT_FLEE_PLAYER;
+ if (this->actor.speedXZ == 0.0f) {
+ if (this->animationIdx != ENHORSE_ANIM_IDLE) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_IDLE;
+ } else if (this->actor.speedXZ <= 3.0f) {
+ if (this->animationIdx != ENHORSE_ANIM_WALK) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_WALK;
+ } else if (this->actor.speedXZ <= 6.0f) {
+ if (this->animationIdx != ENHORSE_ANIM_TROT) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_TROT;
+ } else {
+ if (this->animationIdx != ENHORSE_ANIM_GALLOP) {
+ animChanged = true;
+ }
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ }
+
+ if (this->animationIdx == ENHORSE_ANIM_WALK) {
+ animSpeed = this->actor.speedXZ * 0.5f;
+ } else if (this->animationIdx == ENHORSE_ANIM_TROT) {
+ animSpeed = this->actor.speedXZ * 0.25f;
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
+ }
+ func_8013ECE0(0.0f, 60, 8, 255);
+ } else if (this->animationIdx == ENHORSE_ANIM_GALLOP) {
+ animSpeed = this->actor.speedXZ * 0.2f;
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_RUN);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
+ }
+ func_8013ECE0(0.0f, 120, 8, 255);
+ } else {
+ animSpeed = 1.0f;
+ }
+
+ if (animChanged == true) {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ sPlaybackSpeeds[this->animationIdx] * animSpeed * 1.5f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ -3.0f);
+ } else {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ sPlaybackSpeeds[this->animationIdx] * animSpeed * 1.5f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ 0.0f);
+ }
+}
+
+void EnHorse_UpdateHorsebackArchery(EnHorse* this, GlobalContext* globalCtx) {
+ f32 playSpeed;
+ s32 sp28;
+
+ if (this->animationIdx == ENHORSE_ANIM_WALK) {
+ EnHorse_PlayWalkingSound(this);
+ }
+
+ if (globalCtx->interfaceCtx.hbaAmmo == 0) {
+ this->hbaTimer++;
+ }
+
+ sp28 = Audio_IsSequencePlaying(0x41);
+ EnHorse_UpdateHbaRaceInfo(this, globalCtx, &sHbaInfo);
+
+ if (((this->hbaFlags & 1) || (this->hbaTimer > 45)) && (sp28 != 1) && (gSaveContext.minigameState != 3)) {
+ gSaveContext.save.cutscene = 0;
+ globalCtx->sceneLoadFlag = 0x14;
+ globalCtx->unk_1887F = 0x40;
+ }
+
+ if (globalCtx->interfaceCtx.hbaAmmo) {}
+
+ if (((globalCtx->interfaceCtx.hbaAmmo == 0) || (this->hbaFlags & 2)) && (this->hbaFlags & 4)) {
+ this->hbaFlags &= ~4;
+ Audio_QueueSeqCmd(0x8041);
+ }
+
+ if (this->hbaStarted == 0) {
+ this->actor.speedXZ = 0.0f;
+ if (this->animationIdx != ENHORSE_ANIM_IDLE) {
+ EnHorse_UpdateHbaAnim(this);
+ }
+ }
+
+ if (this->animationIdx == ENHORSE_ANIM_WALK) {
+ playSpeed = this->actor.speedXZ * 0.5f;
+ } else if (this->animationIdx == ENHORSE_ANIM_TROT) {
+ playSpeed = this->actor.speedXZ * 0.25f;
+ } else if (this->animationIdx == ENHORSE_ANIM_GALLOP) {
+ playSpeed = this->actor.speedXZ * 0.2f;
+ } else {
+ playSpeed = 1.0f;
+ }
+ this->skin.skelAnime.playSpeed = playSpeed;
+
+ if (SkelAnime_Update(&this->skin.skelAnime) ||
+ ((this->animationIdx == ENHORSE_ANIM_IDLE) && (this->actor.speedXZ != 0.0f))) {
+ EnHorse_UpdateHbaAnim(this);
+ }
+}
+
+#ifdef NON_MATCHING
+void EnHorse_FleePlayer(EnHorse* this, GlobalContext* globalCtx) {
+ Player* player = GET_PLAYER(globalCtx);
+ f32 distToHome;
+ f32 playerDistToHome;
+ f32 distToPlayer;
+ s32 nextAnim;
+ s32 animFinished;
+ s16 yaw;
+
+ if ((D_801BDAA4 != 0) || (this->type == HORSE_HNI)) {
+ EnHorse_StartIdleRidable(this);
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+
+ distToHome = Math3D_Distance(&this->actor.home.pos, &this->actor.world.pos);
+ playerDistToHome = Math3D_Distance(&player->actor.world.pos, &this->actor.home.pos);
+ distToPlayer = Math3D_Distance(&player->actor.world.pos, &this->actor.world.pos);
+
+ if (playerDistToHome > 300.0f) {
+ if (distToHome > 150.0f) {
+ this->actor.speedXZ += 0.4f;
+ if (this->actor.speedXZ > 8.0f) {
+ this->actor.speedXZ = 8.0f;
+ }
+ } else {
+ this->actor.speedXZ -= 0.5f;
+ if (this->actor.speedXZ < 0.0f) {
+ this->actor.speedXZ = 0.0f;
+ }
+ }
+ } else if (distToPlayer < 300.0f) {
+ this->actor.speedXZ += 0.4f;
+ if (this->actor.speedXZ > 8.0f) {
+ this->actor.speedXZ = 8.0f;
+ }
+ } else {
+ this->actor.speedXZ -= 0.5f;
+ if (this->actor.speedXZ < 0.0f) {
+ this->actor.speedXZ = 0.0f;
+ }
+ }
+
+ if (this->actor.speedXZ >= 6.0f) {
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.3f;
+ nextAnim = ENHORSE_ANIM_GALLOP;
+ } else if (this->actor.speedXZ >= 3.0f) {
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.375f;
+ nextAnim = ENHORSE_ANIM_TROT;
+ } else if (this->actor.speedXZ > 0.1f) {
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.75f;
+ nextAnim = ENHORSE_ANIM_WALK;
+ EnHorse_PlayWalkingSound(this);
+ } else {
+ if (Rand_ZeroOne() > 0.5f) {
+ nextAnim = ENHORSE_ANIM_WHINNEY;
+ } else {
+ nextAnim = ENHORSE_ANIM_IDLE;
+ }
+ EnHorse_IdleAnimSounds(this, globalCtx);
+ this->skin.skelAnime.playSpeed = 1.0f;
+ }
+
+ if ((nextAnim == ENHORSE_ANIM_GALLOP) || (nextAnim == ENHORSE_ANIM_TROT) || (nextAnim == ENHORSE_ANIM_WALK)) {
+ if (playerDistToHome < 300.0f) {
+ yaw = player->actor.shape.rot.y;
+ yaw += ((Actor_YawBetweenActors(&this->actor, &player->actor) > 0) ? 1 : -1) * 0x3FFF;
+ } else {
+ yaw = Math_Vec3f_Yaw(&this->actor.world.pos, &this->actor.home.pos) - this->actor.world.rot.y;
+ }
+
+ if (yaw > 800.0f) {
+ this->actor.world.rot.y += 0x320;
+ } else if (yaw < -800.0f) {
+ this->actor.world.rot.y += -0x320;
+ } else {
+ this->actor.world.rot.y += yaw;
+ }
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+ }
+
+ animFinished = SkelAnime_Update(&this->skin.skelAnime);
+
+ if (((this->animationIdx == ENHORSE_ANIM_IDLE) || (this->animationIdx == ENHORSE_ANIM_WHINNEY)) &&
+ ((nextAnim == ENHORSE_ANIM_GALLOP) || (nextAnim == ENHORSE_ANIM_TROT) || (nextAnim == ENHORSE_ANIM_WALK))) {
+ this->animationIdx = nextAnim;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][nextAnim]), ANIMMODE_ONCE, -3.0f);
+ if (this->animationIdx == ENHORSE_ANIM_GALLOP) {
+ func_8087C1C0(this);
+ } else if (this->animationIdx == ENHORSE_ANIM_TROT) {
+ func_8087C178(this);
+ }
+ } else if (animFinished) {
+ if (nextAnim == ENHORSE_ANIM_GALLOP) {
+ func_8087C1C0(this);
+ } else if (nextAnim == ENHORSE_ANIM_TROT) {
+ func_8087C178(this);
+ }
+
+ if ((this->animationIdx == ENHORSE_ANIM_IDLE) || (this->animationIdx == ENHORSE_ANIM_WHINNEY)) {
+ if (nextAnim != this->animationIdx) {
+ this->animationIdx = nextAnim;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]),
+ ANIMMODE_ONCE, -3.0f);
+ } else {
+ if (Rand_ZeroOne() > 0.5f) {
+ this->animationIdx = ENHORSE_ANIM_IDLE;
+ this->stateFlags &= ~ENHORSE_SANDDUST_SOUND;
+ } else {
+ this->animationIdx = ENHORSE_ANIM_WHINNEY;
+ if (this->stateFlags & ENHORSE_DRAW) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_GROAN);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_GROAN);
+ }
+ }
+ }
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]),
+ ANIMMODE_ONCE, -3.0f);
+ }
+ } else if (nextAnim != this->animationIdx) {
+ this->animationIdx = nextAnim;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ -3.0f);
+ } else {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ 0.0f);
+ }
+ } else if ((this->animationIdx == ENHORSE_ANIM_WALK) &&
+ ((nextAnim == ENHORSE_ANIM_IDLE) || (nextAnim == ENHORSE_ANIM_WHINNEY))) {
+ this->animationIdx = nextAnim;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ -3.0f);
+ }
+}
+#else
+void EnHorse_FleePlayer(EnHorse* this, GlobalContext* globalCtx);
+#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/EnHorse_FleePlayer.s")
+#endif
+
+void func_80883B70(EnHorse* this, CsCmdActorAction* action) {
+ this->actor.world.pos.x = action->startPos.x;
+ this->actor.world.pos.y = action->startPos.y;
+ this->actor.world.pos.z = action->startPos.z;
+
+ this->actor.world.rot.y = action->urot.y;
+ this->actor.shape.rot = this->actor.world.rot;
+
+ this->actor.prevPos = this->actor.world.pos;
+}
+
+void func_80883BEC(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ func_80883B70(this, action);
+ this->animationIdx = ENHORSE_ANIM_IDLE;
+ this->unk_3E0 = 1;
+ this->stateFlags &= ~ENHORSE_SANDDUST_SOUND;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, 0.0f);
+ this->stateFlags |= ENHORSE_SANDDUST_SOUND;
+}
+
+void func_80883CB0(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ EnHorse_IdleAnimSounds(this, globalCtx);
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ this->animationIdx = ENHORSE_ANIM_IDLE;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ 0.0f);
+ }
+}
+
+void func_80883D64(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ func_80883B70(this, action);
+ this->unk_3E0 = 2;
+ Animation_Change(&this->skin.skelAnime, &object_horse_link_child_Anim_00A8DC, 0.0f, 0.0f,
+ Animation_GetLastFrame(&object_horse_link_child_Anim_00A8DC), ANIMMODE_ONCE, 0.0f);
+}
+
+void func_80883DE0(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ SkelAnime_Update(&this->skin.skelAnime);
+}
+
+void func_80883E10(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ func_80883B70(this, action);
+ this->unk_3E0 = 3;
+ Animation_Change(&this->skin.skelAnime, &object_horse_link_child_Anim_00A8DC, 1.0f, 0.0f,
+ Animation_GetLastFrame(&object_horse_link_child_Anim_00A8DC), ANIMMODE_ONCE, -3.0f);
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+}
+
+void func_80883EA0(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ Animation_Change(&this->skin.skelAnime, &object_horse_link_child_Anim_00B3E0, 1.0f, 11.0f,
+ Animation_GetLastFrame(&object_horse_link_child_Anim_00B3E0), ANIMMODE_ONCE, 0.0f);
+ }
+}
+
+void func_80883F18(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ func_80883B70(this, action);
+ this->unk_3E0 = 4;
+ Animation_Change(&this->skin.skelAnime, &object_horse_link_child_Anim_00AD08, 1.0f, 0.0f,
+ Animation_GetLastFrame(&object_horse_link_child_Anim_00AD08), ANIMMODE_ONCE, -3.0f);
+}
+
+void func_80883F98(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ if (Animation_OnFrame(&this->skin.skelAnime, Animation_GetLastFrame(&object_horse_link_child_Anim_00AD08) - 1.0f)) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_LAND2);
+ }
+ SkelAnime_Update(&this->skin.skelAnime);
+}
+
+void func_80884010(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ func_80883B70(this, action);
+ this->unk_3E0 = 5;
+ this->animationIdx = ENHORSE_ANIM_WALK;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+}
+
+void func_808840C4(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ EnHorse_PlayWalkingSound(this);
+ Cutscene_ActorTranslateAndYaw(&this->actor, globalCtx, this->unk_530);
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ 0.0f);
+ }
+}
+
+void func_80884194(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ func_80883B70(this, action);
+ this->unk_3E0 = 6;
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+ func_8087C1C0(this);
+}
+
+void func_8088424C(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ Cutscene_ActorTranslateAndYaw(&this->actor, globalCtx, this->unk_530);
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 1.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ 0.0f);
+ func_8087C1C0(this);
+ }
+}
+
+void func_80884314(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ ActorShape_Init(&this->actor.shape, 0.0f, NULL, 20.0f);
+ func_80883B70(this, action);
+ this->unk_3E0 = 7;
+ Animation_Change(&this->skin.skelAnime, &object_horse_link_child_Anim_00D178, 1.0f, 0.0f,
+ Animation_GetLastFrame(&object_horse_link_child_Anim_00D178), ANIMMODE_ONCE, 0.0f);
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+}
+
+void func_808843B4(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ SkelAnime_Update(&this->skin.skelAnime);
+ if (this->curFrame > 42.0f) {
+ if (((s32)this->curFrame % 11) == 0) {
+ func_8087C1C0(this);
+ }
+ Cutscene_ActorTranslateAndYaw(&this->actor, globalCtx, this->unk_530);
+ }
+}
+
+void func_80884444(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ ActorShape_Init(&this->actor.shape, 0.0f, NULL, 20.0f);
+ func_80883B70(this, action);
+ this->cutsceneAction = 8;
+ Animation_Change(&this->skin.skelAnime, &object_horse_link_child_Anim_00D4E8, 1.0f, 0.0f,
+ Animation_GetLastFrame(&object_horse_link_child_Anim_00D4E8), ANIMMODE_ONCE, 0.0f);
+ func_8087C1C0(this);
+}
+
+void func_808844E0(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ Cutscene_ActorTranslateAndYaw(&this->actor, globalCtx, this->unk_530);
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ Animation_Change(&this->skin.skelAnime, &object_horse_link_child_Anim_00D4E8, 1.0f, 0.0f,
+ Animation_GetLastFrame(&object_horse_link_child_Anim_00D4E8), ANIMMODE_ONCE, 0.0f);
+ func_8087C1C0(this);
+ }
+}
+
+void func_80884564(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ ActorShape_Init(&this->actor.shape, 0.0f, NULL, 20.0f);
+ func_80883B70(this, action);
+ this->cutsceneAction = 8;
+ Animation_Change(&this->skin.skelAnime, &object_horse_link_child_Anim_00BDE0, 1.0f, 0.0f,
+ Animation_GetLastFrame(&object_horse_link_child_Anim_00BDE0), ANIMMODE_ONCE, -3.0f);
+ func_8087C1C0(this);
+}
+
+void func_80884604(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ Cutscene_ActorTranslateAndYaw(&this->actor, globalCtx, this->unk_530);
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ Animation_Change(&this->skin.skelAnime, &object_horse_link_child_Anim_00BDE0, 1.0f, 0.0f,
+ Animation_GetLastFrame(&object_horse_link_child_Anim_00BDE0), ANIMMODE_ONCE, 0.0f);
+ }
+
+ if (((s32)this->curFrame % 11) == 0) {
+ func_8087C1C0(this);
+ }
+}
+
+void func_808846B4(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+ Actor_MarkForDeath(&this->actor);
+}
+
+void func_808846DC(EnHorse* this, GlobalContext* globalCtx, CsCmdActorAction* action) {
+}
+
+void func_808846F0(EnHorse* this, GlobalContext* globalCtx) {
+ this->playerControlled = false;
+ this->action = ENHORSE_ACT_21;
+ this->unk_3E0 = -1;
+ this->actor.speedXZ = 0.0f;
+}
+
+void func_80884718(EnHorse* this, GlobalContext* globalCtx) {
+ CsCmdActorAction* action;
+
+ if (Cutscene_CheckActorAction(globalCtx, 0x70)) {
+ this->unk_530 = Cutscene_GetActorActionIndex(globalCtx, 0x70);
+ action = globalCtx->csCtx.actorActions[this->unk_530];
+
+ this->unk_1EC |= 0x20;
+ if (this->unk_3E0 != action->action) {
+ if (this->unk_3E0 == -1) {
+ this->actor.world.pos.x = action->startPos.x;
+ this->actor.world.pos.y = action->startPos.y;
+ this->actor.world.pos.z = action->startPos.z;
+
+ this->actor.world.rot.y = action->urot.y;
+ this->actor.shape.rot = this->actor.world.rot;
+
+ this->actor.prevPos = this->actor.world.pos;
+ }
+
+ this->unk_3E0 = action->action;
+ if (D_808890F0[this->unk_3E0] != NULL) {
+ D_808890F0[this->unk_3E0](this, globalCtx, action);
+ }
+ }
+
+ if (D_8088911C[this->unk_3E0] != NULL) {
+ D_8088911C[this->unk_3E0](this, globalCtx, action);
+ }
+ }
+}
+
+void func_80884868(EnHorse* this) {
+ this->action = ENHORSE_ACT_23;
+ this->animationIdx = ENHORSE_ANIM_WALK;
+ Animation_PlayLoop(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx]);
+ this->stateFlags |= ENHORSE_UNRIDEABLE;
+}
+
+void func_808848C8(EnHorse* this, GlobalContext* globalCtx) {
+ Vec3f sp24 = { -1916.0f, -106.0f, -523.0f };
+
+ EnHorse_PlayWalkingSound(this);
+ this->actor.speedXZ = 4.0f;
+ func_800F415C(&this->actor, &sp24, 2000);
+ this->skin.skelAnime.playSpeed = this->actor.speedXZ * 0.75f;
+ SkelAnime_Update(&this->skin.skelAnime);
+ if (Math3D_Distance(&sp24, &this->actor.world.pos) < 30.0f) {
+ this->stateFlags &= ~ENHORSE_UNRIDEABLE;
+ EnHorse_StartIdleRidable(this);
+ }
+}
+
+void func_80884994(EnHorse* this) {
+ this->unk_534 = -1;
+ this->animationIdx = ENHORSE_ANIM_TROT;
+ this->action = ENHORSE_ACT_24;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 2.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, -3.0f);
+}
+
+void func_80884A40(EnHorse* this, GlobalContext* globalCtx) {
+ s32 sp44[] = { 5, 6, 0 };
+ s32 sp40;
+ s32 temp_v0;
+
+ if (this->animationIdx == ENHORSE_ANIM_WHINNEY) {
+ temp_v0 = 0;
+ } else {
+ temp_v0 = this->animationIdx;
+ }
+
+ sp40 = sp44[this->unk_538] != temp_v0;
+
+ if (SkelAnime_Update(&this->skin.skelAnime) || sp40) {
+ this->animationIdx = sp44[this->unk_538];
+ if ((this->animationIdx == ENHORSE_ANIM_IDLE) && (Rand_ZeroOne() < 0.5f)) {
+ this->animationIdx = ENHORSE_ANIM_WHINNEY;
+ }
+
+ if (sp40) {
+ if (this->animationIdx == ENHORSE_ANIM_IDLE) {
+ Animation_MorphToPlayOnce(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ -3.0f);
+ } else {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 2.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]),
+ ANIMMODE_ONCE, -3.0f);
+ }
+ } else if (this->animationIdx == ENHORSE_ANIM_IDLE) {
+ Animation_PlayOnce(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx]);
+ } else {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx], 2.0f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ 0.0f);
+ }
+
+ if ((this->unk_538 == 0) || (this->unk_538 == 1)) {
+ Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_HORSE_RUN);
+ } else if (this->unk_538 == 2) {
+ if (this->animationIdx == ENHORSE_ANIM_IDLE) {
+ EnHorse_IdleAnimSounds(this, globalCtx);
+ } else if (this->animationIdx == ENHORSE_ANIM_WHINNEY) {
+ Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_HORSE_GROAN);
+ }
+ }
+ }
+}
+
+void func_80884D04(EnHorse* this, GlobalContext* globalCtx) {
+ f32 playSpeed;
+
+ this->actor.speedXZ = 10.0f;
+ this->action = ENHORSE_ACT_25;
+ this->unk_540 = this->actor.world.pos;
+ Actor_PlaySfxAtPos(&this->actor, NA_SE_IT_INGO_HORSE_NEIGH);
+ this->animationIdx = ENHORSE_ANIM_GALLOP;
+ playSpeed = this->actor.speedXZ * 0.2f;
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ sPlaybackSpeeds[this->animationIdx] * playSpeed * 2.5f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE, 0.0f);
+}
+
+void func_80884E0C(EnHorse* this, GlobalContext* globalCtx) {
+ f32 playSpeed = (this->unk_56C * 0.2f * 0.5f) + 1.0f;
+ Vec3f pos;
+ CollisionPoly* sp3C;
+
+ this->skin.skelAnime.playSpeed = playSpeed;
+
+ if (SkelAnime_Update(&this->skin.skelAnime)) {
+ Animation_Change(&this->skin.skelAnime, sAnimationHeaders[this->type][this->animationIdx],
+ sPlaybackSpeeds[this->animationIdx] * playSpeed * 2.5f, 0.0f,
+ Animation_GetLastFrame(sAnimationHeaders[this->type][this->animationIdx]), ANIMMODE_ONCE,
+ 0.0f);
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_HORSE_RUN);
+ }
+
+ 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->unk_56C = Math3D_Distance(&this->actor.world.pos, &this->actor.prevPos);
+ if (((this->unk_550 == 5) || (this->unk_550 == 7)) && (Player_GetMask(globalCtx) != PLAYER_MASK_CIRCUS_LEADER)) {
+ this->rider->unk488 = 7;
+ } else {
+ EnHorse_SetIngoAnimation(this->animationIdx, this->skin.skelAnime.curFrame, this->unk_394 & 1,
+ &this->rider->unk488);
+ }
+
+ pos = this->actor.world.pos;
+ pos.y += 10.0f;
+
+ if (BgCheck_EntityRaycastFloor1(&globalCtx->colCtx, &sp3C, &pos) != BGCHECK_Y_MIN) {
+ this->actor.velocity.y += this->actor.gravity;
+ if (this->actor.velocity.y < this->actor.terminalVelocity) {
+ this->actor.velocity.y = this->actor.terminalVelocity;
+ }
+ this->actor.world.pos.y += this->actor.velocity.y * 0.5f;
+ } else {
+ this->actor.world.pos.y = this->unk_570.y;
+ }
+}
+
+void EnHorse_Vec3fOffset(Vec3f* src, s16 yaw, f32 dist, f32 height, Vec3f* dst) {
+ dst->x = (Math_SinS(yaw) * dist) + src->x;
+ dst->y = src->y + height;
+ dst->z = (Math_CosS(yaw) * dist) + src->z;
+}
+
+s32 EnHorse_CalcFloorHeight(EnHorse* this, GlobalContext* globalCtx, Vec3f* pos, CollisionPoly** polyFloor,
+ f32* floorHeight, s32* bgId) {
+ f32 waterY;
+ WaterBox* waterbox;
+
+ *polyFloor = NULL;
+ *floorHeight = BgCheck_EntityRaycastFloor3(&globalCtx->colCtx, polyFloor, bgId, pos);
+ if (*floorHeight == BGCHECK_Y_MIN) {
+ return 1; // No floor
+ }
+
+ if ((WaterBox_GetSurface1_2(globalCtx, &globalCtx->colCtx, pos->x, pos->z, &waterY, &waterbox) == 1) &&
+ (*floorHeight < waterY)) {
+ return 2; // Water
+ }
+
+ if ((COLPOLY_GET_NORMAL((*polyFloor)->normal.y) < 0.81915206f) ||
+ SurfaceType_IsHorseBlocked(&globalCtx->colCtx, *polyFloor, *bgId) ||
+ (func_800C99D4(&globalCtx->colCtx, *polyFloor, *bgId) == 7)) {
+ return 3; // Horse blocked surface
+ }
+
+ return 0;
+}
+
+/**
+ * obstacleType:
+ * 1: Water in front
+ * 2: Water behind?
+ * 3: ?
+ * 4: Obstructed in front
+ * 5: Obstructed behind
+ */
+void EnHorse_ObstructMovement(EnHorse* this, GlobalContext* globalCtx, s32 obstacleType, s32 galloping) {
+ if (this->action != ENHORSE_ACT_HBA) {
+ if ((this->action == ENHORSE_ACT_MOUNTED_IDLE) || (this->action == ENHORSE_ACT_MOUNTED_IDLE_WHINNEYING)) {
+ this->actor.world.pos = this->actor.prevPos;
+ this->actor.world.rot.y -= 0x640;
+ this->actor.speedXZ = 0.0f;
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+ this->unk_1EC |= 4;
+ } else if (this->action == ENHORSE_ACT_25) {
+ this->unk_1EC |= 0x80;
+ this->actor.world.pos = this->actor.prevPos;
+ this->actor.speedXZ = 0.0f;
+ } else if ((globalCtx->sceneNum != SCENE_KOEPONARACE) || (this->unk_1EC & 2)) {
+ this->unk_1EC &= ~2;
+ this->actor.world.pos = this->lastPos;
+ this->stateFlags |= ENHORSE_OBSTACLE;
+ if (this->playerControlled == 0) {
+ if (this->animationIdx != 3) {}
+ } else if (this->action != ENHORSE_ACT_REVERSE) {
+ if (this->stateFlags & ENHORSE_JUMPING) {
+ this->stateFlags &= ~ENHORSE_JUMPING;
+ this->actor.gravity = -3.5f;
+ this->actor.world.pos.y = this->actor.floorHeight;
+ }
+
+ if ((obstacleType == 1) || (obstacleType == 4)) {
+ this->stateFlags |= ENHORSE_FORCE_REVERSING;
+ } else if ((obstacleType == 2) || (obstacleType == 5)) {
+ this->stateFlags |= ENHORSE_FORCE_WALKING;
+ }
+
+ if (galloping == true) {
+ EnHorse_StartRearing(this);
+ }
+ }
+ }
+ }
+}
+
+void EnHorse_CheckFloors(EnHorse* this, GlobalContext* globalCtx) {
+ s32 pad;
+ CollisionPoly* frontFloor;
+ CollisionPoly* backFloor;
+ s32 bgId;
+ s16 floorSlope;
+ Vec3f frontPos;
+ Vec3f backPos;
+ Vec3f pos;
+ f32 nx;
+ f32 ny;
+ f32 nz;
+ s32 galloping = this->actor.speedXZ > 8.0f;
+ s32 status;
+ f32 waterHeight;
+ WaterBox* waterbox;
+ f32 dist;
+
+ if ((WaterBox_GetSurface1_2(globalCtx, &globalCtx->colCtx, this->actor.world.pos.x, this->actor.world.pos.z,
+ &waterHeight, &waterbox) == true) &&
+ (this->actor.floorHeight < waterHeight)) {
+ EnHorse_ObstructMovement(this, globalCtx, 1, galloping);
+ return;
+ }
+
+ if (this->type != HORSE_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);
+ }
+
+ status = EnHorse_CalcFloorHeight(this, globalCtx, &frontPos, &frontFloor, &this->yFront, &this->unk_24C);
+ if (status == 1) {
+ this->actor.shape.rot.x = 0;
+ EnHorse_ObstructMovement(this, globalCtx, 4, galloping);
+ return;
+ }
+
+ if (status == 3) {
+ this->unk_1EC |= 2;
+ EnHorse_ObstructMovement(this, globalCtx, 4, galloping);
+ return;
+ }
+
+ if (this->type != HORSE_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);
+ }
+
+ status = EnHorse_CalcFloorHeight(this, globalCtx, &backPos, &backFloor, &this->yBack, &bgId);
+ if (status == 1) {
+ this->actor.shape.rot.x = 0;
+ EnHorse_ObstructMovement(this, globalCtx, 5, galloping);
+ return;
+ }
+
+ if (status == 3) {
+ this->unk_1EC |= 2;
+ EnHorse_ObstructMovement(this, globalCtx, 5, galloping);
+ return;
+ }
+
+ floorSlope = Math_Atan2S(this->yBack - this->yFront, 60.0f);
+ if (this->actor.floorPoly != NULL) {
+ nx = COLPOLY_GET_NORMAL(this->actor.floorPoly->normal.x);
+ ny = COLPOLY_GET_NORMAL(this->actor.floorPoly->normal.y);
+ nz = COLPOLY_GET_NORMAL(this->actor.floorPoly->normal.z);
+
+ pos = frontPos;
+ pos.y = this->yFront;
+
+ dist = Math3D_DistPlaneToPos(nx, ny, nz, this->actor.floorPoly->dist, &pos);
+ if ((frontFloor != this->actor.floorPoly) && (this->actor.speedXZ >= 0.0f) &&
+ ((!(this->stateFlags & ENHORSE_JUMPING) && (dist < -40.0f)) ||
+ ((this->stateFlags & ENHORSE_JUMPING) && (dist < -200.0f)))) {
+ EnHorse_ObstructMovement(this, globalCtx, 4, galloping);
+ return;
+ }
+
+ pos = backPos;
+ pos.y = this->yBack;
+
+ dist = Math3D_DistPlaneToPos(nx, ny, nz, this->actor.floorPoly->dist, &pos);
+ if ((backFloor != this->actor.floorPoly) && (this->actor.speedXZ <= 0.0f) &&
+ ((!(this->stateFlags & ENHORSE_JUMPING) && (dist < -40.0f)) ||
+ ((this->stateFlags & ENHORSE_JUMPING) && (dist < -200.0f)))) {
+ EnHorse_ObstructMovement(this, globalCtx, 5, galloping);
+ return;
+ }
+
+ if ((ny < 0.81915206f) ||
+ SurfaceType_IsHorseBlocked(&globalCtx->colCtx, this->actor.floorPoly, this->actor.floorBgId) ||
+ (func_800C99D4(&globalCtx->colCtx, this->actor.floorPoly, this->actor.floorBgId) == 7)) {
+ if (this->actor.speedXZ >= 0.0f) {
+ EnHorse_ObstructMovement(this, globalCtx, 4, galloping);
+ } else {
+ EnHorse_ObstructMovement(this, globalCtx, 5, galloping);
+ }
+ } else if (this->stateFlags & 4) {
+ this->actor.shape.rot.x = 0;
+ } else if ((this->actor.floorHeight + 4.0f) < this->actor.world.pos.y) {
+ this->actor.shape.rot.x = 0;
+ } else if (!(fabsf(floorSlope) > 0x1FFF)) {
+ this->actor.shape.rot.x = floorSlope;
+ this->actor.shape.yOffset =
+ ((this->yFront + (((this->yBack - this->yFront) * 20.0f) / 45.0f)) - this->actor.floorHeight) +
+ this->unk_3E8;
+ }
+ }
+}
+
+void EnHorse_MountDismount(EnHorse* this, GlobalContext* globalCtx) {
+ s32 mountSide = EnHorse_GetMountSide(this, globalCtx);
+
+ if ((mountSide != 0) && !(this->stateFlags & ENHORSE_UNRIDEABLE)) {
+ Actor_SetRideActor(globalCtx, &this->actor, mountSide);
+ }
+
+ if ((this->playerControlled == false) && (Actor_HasRider(globalCtx, &this->actor) == true)) {
+ this->noInputTimer = 26;
+ this->noInputTimerMax = 26;
+ this->playerControlled = true;
+ EnHorse_Freeze(this, globalCtx);
+ } else if ((this->playerControlled == true) && (Actor_HasNoRider(globalCtx, &this->actor) == true)) {
+ this->noInputTimer = 35;
+ this->noInputTimerMax = 35;
+ this->stateFlags &= ~ENHORSE_UNRIDEABLE;
+ this->playerControlled = false;
+ EnHorse_Freeze(this, globalCtx);
+ }
+}
+
+void EnHorse_StickDirection(Vec2f* curStick, f32* stickMag, s16* angle) {
+ *stickMag = sqrtf(SQ(curStick->x) + SQ(curStick->z));
+ *stickMag = CLAMP_MAX(*stickMag, 60.0f);
+ *angle = Math_Atan2S(-curStick->x, curStick->z);
+}
+
+void EnHorse_UpdateStick(EnHorse* this, GlobalContext* globalCtx) {
+ Input* input = &globalCtx->state.input[this->unk_52C];
+
+ this->lastStick = this->curStick;
+ this->curStick.x = input->rel.stick_x;
+ this->curStick.z = input->rel.stick_y;
+}
+
+void EnHorse_ResolveCollision(EnHorse* this, GlobalContext* globalCtx, CollisionPoly* colPoly) {
+ f32 dist;
+ f32 nx;
+ f32 ny;
+ f32 nz;
+ f32 offset;
+
+ nx = COLPOLY_GET_NORMAL(colPoly->normal.x);
+ ny = COLPOLY_GET_NORMAL(colPoly->normal.y);
+ nz = COLPOLY_GET_NORMAL(colPoly->normal.z);
+
+ if (!(Math_CosS(BINANG_ROT180(this->actor.world.rot.y - Math_Atan2S(colPoly->normal.x, colPoly->normal.z))) <
+ 0.7071f)) { // cos(45 degrees)
+ dist = Math3D_DistPlaneToPos(nx, ny, nz, colPoly->dist, &this->actor.world.pos);
+ offset = (1.0f / sqrtf(SQ(nx) + SQ(nz)));
+ offset = (30.0f - dist) * offset;
+ this->actor.world.pos.x += offset * nx;
+ this->actor.world.pos.z += offset * nz;
+ }
+}
+
+void EnHorse_BgCheckSlowMoving(EnHorse* this, GlobalContext* globalCtx) {
+ f32 yOffset = 40.0f;
+ Vec3f start;
+ Vec3f end;
+ Vec3f intersect;
+ CollisionPoly* colPoly;
+ s32 bgId;
+
+ Math_Vec3f_Copy(&start, &this->actor.world.pos);
+ start.y += yOffset;
+
+ Math_Vec3f_Copy(&end, &start);
+ end.x += 30.0f * Math_SinS(this->actor.world.rot.y);
+ end.y += 30.0f * Math_SinS(-this->actor.shape.rot.x);
+ end.z += 30.0f * Math_CosS(this->actor.world.rot.y);
+ if (BgCheck_EntityLineTest1(&globalCtx->colCtx, &start, &end, &intersect, &colPoly, true, false, false, true,
+ &bgId)) {
+ EnHorse_ResolveCollision(this, globalCtx, colPoly);
+ }
+}
+
+void EnHorse_UpdateBgCheckInfo(EnHorse* this, GlobalContext* globalCtx) {
+ s32 pad2[2];
+ Vec3f startPos;
+ Vec3f endPos;
+ Vec3f obstaclePos;
+ f32 temp_f0;
+ f32 intersectDist;
+ CollisionPoly* wall = NULL;
+ CollisionPoly* obstacleFloor = NULL;
+ s32 bgId;
+ f32 obstacleHeight;
+ f32 behindObstacleHeight;
+ DynaPolyActor* horseJump;
+ s32 movingFast;
+ s16 sp7E = 0;
+ DynaPolyActor* horseGameCheck = NULL;
+ s32 pad6;
+ s32 pad;
+ Vec3f intersect;
+ Vec3f obstacleTop;
+ s32 pad5;
+ s32 pad4;
+
+ if ((this->actor.params != ENHORSE_4) && (this->actor.params != ENHORSE_5) && (this->actor.params != ENHORSE_19) &&
+ (this->actor.params != ENHORSE_20) && (this->actor.params != ENHORSE_18)) {
+ Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 40.0f, 35.0f, 100.0f, 0x1D);
+ } else {
+ Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 40.0f, 35.0f, 100.0f, 0x1C);
+ }
+
+ 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) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
+ }
+ }
+ }
+
+ horseJump = DynaPoly_GetActor(&globalCtx->colCtx, this->actor.floorBgId);
+
+ if (!(this->stateFlags & ENHORSE_JUMPING)) {
+ if ((horseJump != NULL) && (horseJump->actor.id == ACTOR_EN_HORSE_GAME_CHECK) &&
+ ((horseJump->actor.params & 0xFF) == 5)) {
+ this->stateFlags |= ENHORSE_FLAG_28;
+ 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) {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
+ } else {
+ Audio_PlaySfxAtPos(&this->actor.projectedPos, NA_SE_EV_KID_HORSE_SANDDUST);
+ }
+ }
+ } else {
+ this->stateFlags &= ~ENHORSE_FLAG_28;
+ this->unk_3E8 *= 0.5f;
+ }
+ }
+
+ if ((this->stateFlags & ENHORSE_JUMPING) || (this->stateFlags & ENHORSE_FLAG_28) || (this->actor.speedXZ < 0.0f) ||
+ (this->action == ENHORSE_ACT_LOW_JUMP) || (this->action == ENHORSE_ACT_REVERSE)) {
+ return;
+ }
+
+ if (this->actor.speedXZ > 8.0f) {
+ if (this->actor.speedXZ < 12.8f) {
+ intersectDist = 160.0f;
+ movingFast = false;
+ } else {
+ intersectDist = 230.0f;
+ movingFast = true;
+ }
+ } else {
+ EnHorse_BgCheckSlowMoving(this, globalCtx);
+ return;
+ }
+
+ startPos = this->actor.world.pos;
+ startPos.y += 19.0f;
+
+ endPos = startPos;
+ endPos.x += intersectDist * Math_SinS(this->actor.world.rot.y);
+ endPos.y += intersectDist * Math_SinS(-this->actor.shape.rot.x);
+ endPos.z += intersectDist * Math_CosS(this->actor.world.rot.y);
+
+ intersect = endPos;
+ wall = NULL;
+
+ if (BgCheck_EntityLineTest1(&globalCtx->colCtx, &startPos, &endPos, &intersect, &wall, true, false, false, true,
+ &bgId) == true) {
+ intersectDist = sqrtf(Math3D_Vec3fDistSq(&startPos, &intersect));
+ this->stateFlags |= ENHORSE_OBSTACLE;
+ }
+
+ if (wall != NULL) {
+ if (intersectDist < 30.0f) {
+ EnHorse_ResolveCollision(this, globalCtx, wall);
+ }
+
+ sp7E = BINANG_ROT180(this->actor.world.rot.y - Math_Atan2S(wall->normal.x, wall->normal.z));
+
+ if ((Math_CosS(sp7E) < 0.5f) || SurfaceType_IsHorseBlocked(&globalCtx->colCtx, wall, bgId)) {
+ return;
+ }
+
+ if (((movingFast == false) && (intersectDist < 80.0f)) || ((movingFast == true) && (intersectDist < 150.0f))) {
+ if ((globalCtx->sceneNum != SCENE_KOEPONARACE) && (Math_CosS(sp7E) < 0.9f) &&
+ (this->playerControlled == true)) {
+ if (movingFast == false) {
+ this->stateFlags |= ENHORSE_FORCE_REVERSING;
+ } else if (movingFast == true) {
+ this->stateFlags |= ENHORSE_FORCE_REVERSING;
+ EnHorse_StartBraking(this, globalCtx);
+ }
+ }
+ return;
+ }
+
+ horseJump = DynaPoly_GetActor(&globalCtx->colCtx, bgId);
+ if ((this->stateFlags & ENHORSE_FLAG_26) &&
+ (((horseJump != NULL) && (horseJump->actor.id != ACTOR_BG_UMAJUMP)) || (horseJump == NULL))) {
+ if (this->playerControlled == true) {
+ if (movingFast == false) {
+ this->stateFlags |= ENHORSE_FORCE_REVERSING;
+ } else if (movingFast == true) {
+ this->stateFlags |= ENHORSE_FORCE_REVERSING;
+ EnHorse_StartBraking(this, globalCtx);
+ }
+ }
+ return;
+ }
+ }
+
+ intersectDist += 5.0f;
+ obstaclePos = startPos;
+
+ obstaclePos.x += intersectDist * Math_SinS(this->actor.world.rot.y);
+ obstaclePos.y = this->actor.world.pos.y + 120.0f;
+ obstaclePos.z += intersectDist * Math_CosS(this->actor.world.rot.y);
+
+ obstacleTop = obstaclePos;
+ obstacleTop.y = BgCheck_EntityRaycastFloor3(&globalCtx->colCtx, &obstacleFloor, &bgId, &obstaclePos);
+
+ if (obstacleTop.y == BGCHECK_Y_MIN) {
+ return;
+ }
+
+ obstacleHeight = obstacleTop.y - this->actor.world.pos.y;
+
+ if ((this->actor.floorPoly == NULL) || (obstacleFloor == NULL)) {
+ return;
+ }
+
+ if ((Math3D_DistPlaneToPos(COLPOLY_GET_NORMAL(this->actor.floorPoly->normal.x),
+ COLPOLY_GET_NORMAL(this->actor.floorPoly->normal.y),
+ COLPOLY_GET_NORMAL(this->actor.floorPoly->normal.z), this->actor.floorPoly->dist,
+ &obstacleTop) < -40.0f) &&
+ (Math3D_DistPlaneToPos(COLPOLY_GET_NORMAL(obstacleFloor->normal.x), COLPOLY_GET_NORMAL(obstacleFloor->normal.y),
+ COLPOLY_GET_NORMAL(obstacleFloor->normal.z), obstacleFloor->dist,
+ &this->actor.world.pos) > 40.0f)) {
+ if ((movingFast == true) && (this->playerControlled == true) && (this->action != ENHORSE_ACT_LOW_JUMP) &&
+ (globalCtx->sceneNum != SCENE_KOEPONARACE)) {
+ this->stateFlags |= ENHORSE_FORCE_REVERSING;
+ EnHorse_StartBraking(this, globalCtx);
+ }
+ this->stateFlags |= ENHORSE_OBSTACLE;
+ return;
+ }
+
+ temp_f0 = COLPOLY_GET_NORMAL(obstacleFloor->normal.y);
+ if ((temp_f0 < 0.81915206f) || SurfaceType_IsHorseBlocked(&globalCtx->colCtx, obstacleFloor, bgId) ||
+ (func_800C99D4(&globalCtx->colCtx, obstacleFloor, bgId) == 7)) {
+ if ((Math_CosS(sp7E) < 0.9f) && (movingFast == true) && (this->playerControlled == true) &&
+ (this->action != ENHORSE_ACT_LOW_JUMP) && (globalCtx->sceneNum != SCENE_KOEPONARACE)) {
+ this->stateFlags |= ENHORSE_FORCE_REVERSING;
+ EnHorse_StartBraking(this, globalCtx);
+ }
+ return;
+ }
+
+ if (wall == NULL) {
+ horseGameCheck = DynaPoly_GetActor(&globalCtx->colCtx, bgId);
+ if ((horseGameCheck == NULL) || (horseGameCheck->actor.id != ACTOR_EN_HORSE_GAME_CHECK) ||
+ ((horseGameCheck->actor.params & 0xFF) != 5)) {
+ return;
+ }
+ }
+
+ if (((obstacleTop.y < intersect.y) &&
+ ((horseGameCheck == NULL) || (horseGameCheck->actor.id != ACTOR_EN_HORSE_GAME_CHECK) ||
+ ((horseGameCheck->actor.params & 0xFF) != 5))) ||
+ ((this->stateFlags & ENHORSE_CANT_JUMP) && (this->action != ENHORSE_ACT_MOUNTED_IDLE))) {
+ return;
+ }
+
+ if ((this->action == ENHORSE_ACT_MOUNTED_IDLE) && !(this->stateFlags & ENHORSE_FLAG_30)) {
+ horseGameCheck = DynaPoly_GetActor(&globalCtx->colCtx, bgId);
+ if ((horseGameCheck != NULL) && (horseGameCheck->actor.id == ACTOR_EN_HORSE_GAME_CHECK) &&
+ ((horseGameCheck->actor.params & 0xFF) == 5)) {
+ this->stateFlags |= ENHORSE_FLAG_30;
+ this->postDrawFunc = func_8088126C;
+ }
+ }
+
+ if (this->playerControlled == false) {
+ return;
+ }
+
+ obstaclePos = startPos;
+ obstaclePos.y = this->actor.world.pos.y + 120.0f;
+
+ if (movingFast == false) {
+ obstaclePos.x += 276.0f * Math_SinS(this->actor.world.rot.y);
+ obstaclePos.z += 276.0f * Math_CosS(this->actor.world.rot.y);
+ } else {
+ obstaclePos.x += 390.0f * Math_SinS(this->actor.world.rot.y);
+ obstaclePos.z += 390.0f * Math_CosS(this->actor.world.rot.y);
+ }
+
+ obstacleTop = obstaclePos;
+ obstacleTop.y = BgCheck_EntityRaycastFloor3(&globalCtx->colCtx, &obstacleFloor, &bgId, &obstaclePos);
+
+ if (obstacleTop.y == BGCHECK_Y_MIN) {
+ return;
+ }
+
+ behindObstacleHeight = obstacleTop.y - this->actor.world.pos.y;
+
+ if (obstacleFloor == NULL) {
+ return;
+ }
+
+ temp_f0 = COLPOLY_GET_NORMAL(obstacleFloor->normal.y);
+ if ((temp_f0 < 0.81915206f) || SurfaceType_IsHorseBlocked(&globalCtx->colCtx, obstacleFloor, bgId) ||
+ (func_800C99D4(&globalCtx->colCtx, obstacleFloor, bgId) == 7)) {
+ if ((movingFast == true) && (this->playerControlled == true) && (this->action != ENHORSE_ACT_LOW_JUMP) &&
+ (globalCtx->sceneNum != SCENE_KOEPONARACE)) {
+ this->stateFlags |= ENHORSE_FORCE_REVERSING;
+ EnHorse_StartBraking(this, globalCtx);
+ }
+ } else if (behindObstacleHeight < -70.0f) {
+ if ((movingFast == true) && (this->playerControlled == true) && (this->action != ENHORSE_ACT_LOW_JUMP) &&
+ (globalCtx->sceneNum != SCENE_KOEPONARACE)) {
+ this->stateFlags |= ENHORSE_FORCE_REVERSING;
+ EnHorse_StartBraking(this, globalCtx);
+ }
+ } else {
+ temp_f0 = (this->actor.scale.y * 100.0f);
+
+ if ((horseGameCheck == NULL) || (horseGameCheck->actor.id != ACTOR_EN_HORSE_GAME_CHECK) ||
+ ((horseGameCheck->actor.params & 0xFF) != 5)) {
+ if ((movingFast == false) && ((19.0f * temp_f0) < obstacleHeight) &&
+ (obstacleHeight <= (40.0f * temp_f0))) {
+ EnHorse_Stub1(this);
+ this->postDrawFunc = EnHorse_LowJumpInit;
+ } else if ((movingFast == true) &&
+ (((this->actor.speedXZ < 13.8f) && ((19.0f * temp_f0) < obstacleHeight) &&
+ (obstacleHeight <= (72.0f * temp_f0))) ||
+ ((this->actor.speedXZ > 13.8f) && (obstacleHeight <= (112.0f * temp_f0))))) {
+ EnHorse_Stub2(this);
+ this->postDrawFunc = EnHorse_HighJumpInit;
+ }
+ } else if (movingFast == false) {
+ EnHorse_Stub1(this);
+ this->postDrawFunc = EnHorse_LowJumpInit;
+ } else if (movingFast == true) {
+ EnHorse_Stub2(this);
+ this->postDrawFunc = EnHorse_HighJumpInit;
+ }
+ }
+}
+
+void func_80886C00(EnHorse* this, GlobalContext* globalCtx) {
+ Input* input = &globalCtx->state.input[this->unk_52C];
+
+ if (((this->action == ENHORSE_ACT_MOUNTED_GALLOP) || (this->action == ENHORSE_ACT_MOUNTED_REARING) ||
+ (this->action == ENHORSE_ACT_STOPPING)) &&
+ (CHECK_BTN_ALL(input->press.button, BTN_A) || (func_801A5100() == 5)) &&
+ (globalCtx->interfaceCtx.unk_212 == 8) && !(this->stateFlags & ENHORSE_BOOST) &&
+ !(this->stateFlags & ENHORSE_FLAG_8) && !(this->stateFlags & ENHORSE_FLAG_9)) {
+ if (this->numBoosts > 0) {
+ func_8013ECE0(0.0f, 180, 20, 100);
+ this->stateFlags |= ENHORSE_BOOST;
+ this->stateFlags |= ENHORSE_FIRST_BOOST_REGEN;
+ this->stateFlags |= ENHORSE_FLAG_8;
+ this->numBoosts--;
+ this->boostTimer = 0;
+ if (this->numBoosts == 0) {
+ this->boostRegenTime = 140;
+ } else if (this->type == HORSE_EPONA) {
+ if (this->stateFlags & ENHORSE_FIRST_BOOST_REGEN) {
+ this->boostRegenTime = 60;
+ this->stateFlags &= ~ENHORSE_FIRST_BOOST_REGEN;
+ } else {
+ this->boostRegenTime = 8;
+ }
+ } else {
+ this->boostRegenTime = 70;
+ }
+ } else if ((this->stateFlags & ENHORSE_DRAW) && (Rand_ZeroOne() < 0.1f)) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+ }
+}
+
+void EnHorse_RegenBoost(EnHorse* this, GlobalContext* globalCtx) {
+ s32 playSfx;
+
+ if ((this->numBoosts < 6) && (this->numBoosts > 0)) {
+ this->boostRegenTime--;
+ this->boostTimer++;
+ if (this->boostRegenTime <= 0) {
+ this->numBoosts++;
+ if (((this->action == ENHORSE_ACT_MOUNTED_TURN) || (this->action == ENHORSE_ACT_FROZEN) ||
+ (this->action == ENHORSE_ACT_MOUNTED_WALK)) &&
+ !(this->stateFlags & ENHORSE_FLAG_19) && !(this->stateFlags & ENHORSE_FLAG_25)) {
+ playSfx = true;
+ } else {
+ playSfx = false;
+ }
+
+ if (!playSfx) {
+ play_sound(NA_SE_SY_CARROT_RECOVER);
+ }
+
+ if (this->numBoosts < 6) {
+ this->boostRegenTime = 11;
+ }
+ }
+ } else if (this->numBoosts == 0) {
+ this->boostRegenTime--;
+ this->boostTimer++;
+ if (this->boostRegenTime <= 0) {
+ this->boostRegenTime = 0;
+ this->numBoosts = 6;
+ if (((this->action == ENHORSE_ACT_MOUNTED_TURN) || (this->action == ENHORSE_ACT_FROZEN) ||
+ (this->action == ENHORSE_ACT_MOUNTED_WALK)) &&
+ !(this->stateFlags & ENHORSE_FLAG_19) && !(this->stateFlags & ENHORSE_FLAG_25)) {
+ playSfx = true;
+ } else {
+ playSfx = false;
+ }
+
+ if (!playSfx) {
+ play_sound(NA_SE_SY_CARROT_RECOVER);
+ }
+ }
+ }
+
+ if (this->boostTimer == 8) {
+ if ((Rand_ZeroOne() < 0.25f) && (this->stateFlags & ENHORSE_DRAW)) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+ }
+
+ globalCtx->interfaceCtx.numHorseBoosts = this->numBoosts;
+}
+
+void EnHorse_UpdatePlayerDir(EnHorse* this, GlobalContext* globalCtx) {
+ Player* player = GET_PLAYER(globalCtx);
+ s16 angle = Actor_YawBetweenActors(&this->actor, &player->actor) - this->actor.world.rot.y;
+ f32 s = Math_SinS(angle);
+ f32 c = Math_CosS(angle);
+
+ if (s > 0.8660254f) { // sin(60 degrees)
+ this->playerDir = PLAYER_DIR_SIDE_L;
+ } else if (s < -0.8660254f) { // -sin(60 degrees)
+ this->playerDir = PLAYER_DIR_SIDE_R;
+ } else if (c > 0.0f) {
+ if (s > 0.0f) {
+ this->playerDir = PLAYER_DIR_FRONT_L;
+ } else {
+ this->playerDir = PLAYER_DIR_FRONT_R;
+ }
+ } else if (s > 0.0f) {
+ this->playerDir = PLAYER_DIR_BACK_L;
+ } else {
+ this->playerDir = PLAYER_DIR_BACK_R;
+ }
+}
+
+void EnHorse_TiltBody(EnHorse* this, GlobalContext* globalCtx) {
+ f32 speed;
+ f32 rollDiff;
+ s32 targetRoll;
+ s16 turnVel;
+
+ speed = this->actor.speedXZ / this->boostSpeed;
+ turnVel = this->actor.shape.rot.y - this->lastYaw;
+ targetRoll = -((s16)((2730.0f * speed) * (turnVel / 960.00006f)));
+ rollDiff = targetRoll - this->actor.world.rot.z;
+
+ if (fabsf(targetRoll) < 100.0f) {
+ this->actor.world.rot.z = 0;
+ } else if (fabsf(rollDiff) < 100.0f) {
+ this->actor.world.rot.z = targetRoll;
+ } else if (rollDiff > 0.0f) {
+ this->actor.world.rot.z += 0x64;
+ } else {
+ this->actor.world.rot.z -= 0x64;
+ }
+
+ this->actor.shape.rot.z = this->actor.world.rot.z;
+}
+
+s32 EnHorse_UpdateConveyors(EnHorse* this, GlobalContext* globalCtx) {
+ Player* player = GET_PLAYER(globalCtx);
+ s16 conveyorDir;
+
+ if ((this->actor.floorPoly == NULL) || (&this->actor != player->rideActor) ||
+ !SurfaceType_GetConveyorSpeed(&globalCtx->colCtx, this->actor.floorPoly, this->actor.floorBgId)) {
+ return false;
+ }
+
+ conveyorDir = SurfaceType_GetConveyorDirection(&globalCtx->colCtx, this->actor.floorPoly, this->actor.floorBgId);
+ conveyorDir = (conveyorDir * 0x400) - this->actor.world.rot.y;
+ if (conveyorDir > 0x640) {
+ this->actor.world.rot.y += 0x640;
+ } else if (conveyorDir < -0x640) {
+ this->actor.world.rot.y -= 0x640;
+ } else {
+ this->actor.world.rot.y += conveyorDir;
+ }
+ this->actor.shape.rot.y = this->actor.world.rot.y;
+ return true;
+}
+
+s32 EnHorse_RandInt(f32 arg0) {
+ return Rand_ZeroOne() * arg0;
+}
+
+#ifdef NON_MATCHING
+void EnHorse_Update(Actor* thisx, GlobalContext* globalCtx) {
+ static EnHorseActionFunc sActionFuncs[] = {
+ EnHorse_Frozen,
+ EnHorse_Inactive,
+ EnHorse_Idle,
+ EnHorse_FollowPlayer,
+ EnHorse_UpdateIngoRace,
+ func_808819D8,
+ func_80881398,
+ EnHorse_MountedIdle,
+ EnHorse_MountedIdleWhinneying,
+ EnHorse_MountedTurn,
+ EnHorse_MountedWalk,
+ EnHorse_MountedTrot,
+ EnHorse_MountedGallop,
+ EnHorse_MountedRearing,
+ EnHorse_Stopping,
+ EnHorse_Reverse,
+ EnHorse_LowJump,
+ EnHorse_HighJump,
+ EnHorse_CutsceneUpdate,
+ EnHorse_UpdateHorsebackArchery,
+ EnHorse_FleePlayer,
+ func_80884718,
+ func_8087CA04,
+ func_808848C8,
+ func_80884A40,
+ func_80884E0C,
+ };
+ s32 pad;
+ EnHorse* this = THIS;
+ Vec3f dustAcc = { 0.0f, 0.0f, 0.0f };
+ Vec3f dustVel = { 0.0f, 1.0f, 0.0f };
+ Player* player = GET_PLAYER(globalCtx);
+
+ if (this->type == HORSE_2) {
+ Actor_SetScale(&this->actor, 0.00648f);
+ } else if (this->type == HORSE_4) {
+ Actor_SetScale(&this->actor, 0.008f);
+ } else {
+ Actor_SetScale(&this->actor, 0.01f);
+ }
+
+ this->lastYaw = this->actor.shape.rot.y;
+ EnHorse_UpdateStick(this, globalCtx);
+ EnHorse_UpdatePlayerDir(this, globalCtx);
+
+ if (!(this->stateFlags & ENHORSE_INACTIVE)) {
+ EnHorse_MountDismount(this, globalCtx);
+ }
+
+ if (this->stateFlags & ENHORSE_FLAG_19) {
+ if ((this->stateFlags & ENHORSE_FLAG_20) && (this->inRace == true)) {
+ this->stateFlags &= ~ENHORSE_FLAG_20;
+ EnHorse_StartRearing(this);
+ } else if (!(this->stateFlags & ENHORSE_FLAG_20) && (this->stateFlags & ENHORSE_FLAG_21) &&
+ (this->action != ENHORSE_ACT_REVERSE) && (this->inRace == true)) {
+ this->stateFlags &= ~ENHORSE_FLAG_21;
+ EnHorse_StartRearing(this);
+ }
+ }
+
+ sActionFuncs[this->action](this, globalCtx);
+
+ this->stateFlags &= ~ENHORSE_OBSTACLE;
+ this->unk_3EC = this->actor.world.rot.y;
+ if ((this->animationIdx == ENHORSE_ANIM_STOPPING) || (this->animationIdx == ENHORSE_ANIM_REARING)) {
+ this->skin.skelAnime.jointTable[0].y += 0x154;
+ }
+
+ this->curFrame = this->skin.skelAnime.curFrame;
+ this->lastPos = this->actor.world.pos;
+
+ if (!(this->stateFlags & ENHORSE_INACTIVE)) {
+ if ((this->action == ENHORSE_ACT_STOPPING) || (this->action == ENHORSE_ACT_MOUNTED_REARING) ||
+ (this->action == ENHORSE_ACT_MOUNTED_GALLOP)) {
+ func_80886C00(this, globalCtx);
+ }
+
+ if (this->playerControlled == true) {
+ EnHorse_RegenBoost(this, globalCtx);
+ }
+
+ if (ActorCutscene_GetCurrentIndex() != -1) {
+ this->actor.speedXZ = 0.0f;
+ }
+
+ if (this->action != ENHORSE_ACT_25) {
+ Actor_MoveWithGravity(&this->actor);
+ }
+
+ if (this->rider != NULL) {
+ if ((this->action == ENHORSE_ACT_INGO_RACE) || (this->action == ENHORSE_ACT_MOUNTED_IDLE) ||
+ (this->action == ENHORSE_ACT_25)) {
+ this->rider->actor.world.pos.x = this->actor.world.pos.x;
+ this->rider->actor.world.pos.y = this->actor.world.pos.y + 10.0f;
+ this->rider->actor.world.pos.z = this->actor.world.pos.z;
+ this->rider->actor.shape.rot.x = this->actor.shape.rot.x;
+ this->rider->actor.shape.rot.y = this->actor.shape.rot.y;
+ } else if (this->action == ENHORSE_ACT_MOUNTED_IDLE_WHINNEYING) {
+ EnIn* in = this->rider;
+ s16 jnt = in->jointTable[0].y;
+
+ in->actor.world.pos.x = this->riderPos.x;
+ in->actor.world.pos.y = this->riderPos.y - (jnt * 0.01f * this->unk_528 * 0.01f);
+ in->actor.world.pos.z = this->riderPos.z;
+ in->actor.shape.rot.x = this->actor.shape.rot.x;
+ in->actor.shape.rot.y = this->actor.shape.rot.y;
+ }
+ }
+
+ if (this->colliderJntSph.elements->info.ocElemFlags & OCELEM_HIT) {
+ if (this->actor.speedXZ > 10.0f) {
+ this->actor.speedXZ -= 1.0f;
+ }
+ }
+
+ if ((this->colliderJntSph.base.acFlags & AC_HIT) && (this->stateFlags & ENHORSE_DRAW)) {
+ if (this->type == HORSE_2) {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_KID_HORSE_NEIGH);
+ } else {
+ Audio_PlaySfxAtPos(&this->unk_218, NA_SE_EV_HORSE_NEIGH);
+ }
+ }
+
+ if ((this->action != ENHORSE_ACT_INGO_RACE) && (this->action != ENHORSE_ACT_MOUNTED_IDLE) &&
+ (this->action != ENHORSE_ACT_MOUNTED_IDLE_WHINNEYING)) {
+ EnHorse_TiltBody(this, globalCtx);
+ }
+
+ if ((this->playerControlled == false) && (this->unk_1EC & 8)) {
+ if ((this->colliderJntSph.elements->info.ocElemFlags & OCELEM_HIT) &&
+ (this->colliderJntSph.base.oc->id == ACTOR_EN_IN)) {
+ func_80884868(this);
+ }
+
+ if ((this->colliderCylinder1.base.ocFlags1 & OC1_HIT) &&
+ (this->colliderCylinder1.base.oc->id == ACTOR_EN_IN)) {
+ func_80884868(this);
+ }
+
+ if ((this->colliderCylinder2.base.ocFlags1 & OC1_HIT) &&
+ (this->colliderCylinder2.base.oc->id == ACTOR_EN_IN)) {
+ func_80884868(this);
+ }
+ }
+
+ Collider_UpdateCylinder(&this->actor, &this->colliderCylinder1);
+ Collider_UpdateCylinder(&this->actor, &this->colliderCylinder2);
+
+ if (this->type == HORSE_2) {
+ this->colliderCylinder1.dim.pos.x =
+ (s16)(Math_SinS(this->actor.shape.rot.y) * 11.0f) + this->colliderCylinder1.dim.pos.x;
+ this->colliderCylinder1.dim.pos.z =
+ (s16)(Math_CosS(this->actor.shape.rot.y) * 11.0f) + this->colliderCylinder1.dim.pos.z;
+ this->colliderCylinder2.dim.pos.x =
+ (s16)(Math_SinS(this->actor.shape.rot.y) * -18.0f) + this->colliderCylinder2.dim.pos.x;
+ this->colliderCylinder2.dim.pos.z =
+ (s16)(Math_CosS(this->actor.shape.rot.y) * -18.0f) + this->colliderCylinder2.dim.pos.z;
+ } else {
+ this->colliderCylinder1.dim.pos.x =
+ (s16)(Math_SinS(this->actor.shape.rot.y) * 6.6000004f) + this->colliderCylinder1.dim.pos.x;
+ this->colliderCylinder1.dim.pos.z =
+ (s16)(Math_CosS(this->actor.shape.rot.y) * 6.6000004f) + this->colliderCylinder1.dim.pos.z;
+ this->colliderCylinder2.dim.pos.x =
+ (s16)(Math_SinS(this->actor.shape.rot.y) * -10.8f) + this->colliderCylinder2.dim.pos.x;
+ this->colliderCylinder2.dim.pos.z =
+ (s16)(Math_CosS(this->actor.shape.rot.y) * -10.8f) + this->colliderCylinder2.dim.pos.z;
+ }
+
+ CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->colliderCylinder1.base);
+ if (!(this->stateFlags & ENHORSE_JUMPING) && !(this->unk_1EC & 0x20)) {
+ CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colliderCylinder1.base);
+ CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colliderCylinder2.base);
+ } else {
+ this->unk_1EC &= ~0x20;
+ }
+
+ if (this->unk_1EC & 0x100) {
+ CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderCylinder1.base);
+ CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->colliderCylinder2.base);
+ }
+
+ if ((player->stateFlags1 & ENHORSE_BOOST) && (player->rideActor != NULL)) {
+ EnHorse_UpdateConveyors(this, globalCtx);
+ }
+
+ EnHorse_UpdateBgCheckInfo(this, globalCtx);
+ EnHorse_CheckFloors(this, globalCtx);
+ if (this->actor.world.pos.y < this->yFront) {
+ if (this->actor.world.pos.y < this->yBack) {
+ if (this->yBack < this->yFront) {
+ this->actor.world.pos.y = this->yBack;
+ } else {
+ this->actor.world.pos.y = this->yFront;
+ }
+ }
+ }
+
+ this->actor.focus.pos = this->actor.world.pos;
+ this->actor.focus.pos.y += 70.0f;
+
+ if ((Rand_ZeroOne() < 0.025f) && (this->blinkTimer == 0)) {
+ this->blinkTimer++;
+ } else if (this->blinkTimer > 0) {
+ this->blinkTimer++;
+ if (this->blinkTimer > 3) {
+ this->blinkTimer = 0;
+ }
+ }
+
+ if ((this->actor.speedXZ == 0.0f) && !(this->stateFlags & ENHORSE_FLAG_19)) {
+ this->actor.colChkInfo.mass = MASS_IMMOVABLE;
+ } else {
+ this->actor.colChkInfo.mass = MASS_HEAVY;
+ }
+
+ if (this->actor.speedXZ >= 5.0f) {
+ this->colliderCylinder1.base.atFlags |= AT_ON;
+ } else {
+ this->colliderCylinder1.base.atFlags &= ~AT_ON;
+ }
+
+ if (this->dustFlags & 1) {
+ this->dustFlags &= ~1;
+ func_800B12F0(globalCtx, &this->frontRightHoof, &dustVel, &dustAcc, EnHorse_RandInt(100.0f) + 200,
+ EnHorse_RandInt(10.0f) + 30, EnHorse_RandInt(20.0f) + 30);
+ } else if (this->dustFlags & 2) {
+ this->dustFlags &= ~2;
+ func_800B12F0(globalCtx, &this->frontLeftHoof, &dustVel, &dustAcc, EnHorse_RandInt(100.0f) + 200,
+ EnHorse_RandInt(10.0f) + 30, EnHorse_RandInt(20.0f) + 30);
+ } else if (this->dustFlags & 4) {
+ this->dustFlags &= ~4;
+ func_800B12F0(globalCtx, &this->backRightHoof, &dustVel, &dustAcc, EnHorse_RandInt(100.0f) + 200,
+ EnHorse_RandInt(10.0f) + 30, EnHorse_RandInt(20.0f) + 30);
+ } else if (this->dustFlags & 8) {
+ this->dustFlags &= ~8;
+ func_800B12F0(globalCtx, &this->backLeftHoof, &dustVel, &dustAcc, EnHorse_RandInt(100.0f) + 200,
+ EnHorse_RandInt(10.0f) + 30, EnHorse_RandInt(20.0f) + 30);
+ }
+ this->stateFlags &= ~ENHORSE_DRAW;
+ }
+}
+#else
+EnHorseActionFunc sActionFuncs[] = {
+ EnHorse_Frozen,
+ EnHorse_Inactive,
+ EnHorse_Idle,
+ EnHorse_FollowPlayer,
+ EnHorse_UpdateIngoRace,
+ func_808819D8,
+ func_80881398,
+ EnHorse_MountedIdle,
+ EnHorse_MountedIdleWhinneying,
+ EnHorse_MountedTurn,
+ EnHorse_MountedWalk,
+ EnHorse_MountedTrot,
+ EnHorse_MountedGallop,
+ EnHorse_MountedRearing,
+ EnHorse_Stopping,
+ EnHorse_Reverse,
+ EnHorse_LowJump,
+ EnHorse_HighJump,
+ EnHorse_CutsceneUpdate,
+ EnHorse_UpdateHorsebackArchery,
+ EnHorse_FleePlayer,
+ func_80884718,
+ func_8087CA04,
+ func_808848C8,
+ func_80884A40,
+ func_80884E0C,
+};
+Vec3f D_808891C8 = { 0.0f, 0.0f, 0.0f };
+Vec3f D_808891D4 = { 0.0f, 1.0f, 0.0f };
#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/EnHorse_Update.s")
+#endif
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80887D20.s")
+s32 EnHorse_PlayerDirToMountSide(EnHorse* this, GlobalContext* globalCtx, Player* player) {
+ if (this->playerDir == PLAYER_DIR_SIDE_L) {
+ return -1;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80887D60.s")
+ if (this->playerDir == PLAYER_DIR_SIDE_R) {
+ return 1;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80887E64.s")
+ return 0;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80887EBC.s")
+s32 EnHorse_MountSideCheck(EnHorse* this, GlobalContext* globalCtx, Player* player) {
+ s32 mountSide;
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80887F58.s")
+ if (Actor_XZDistanceBetweenActors(&this->actor, &player->actor) > 75.0f) {
+ return 0;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80888C48.s")
+ if (fabsf(this->actor.world.pos.y - player->actor.world.pos.y) > 30.0f) {
+ return 0;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/func_80888D18.s")
+ if (Math_CosS(Actor_YawBetweenActors(&player->actor, &this->actor) - player->actor.world.rot.y) <
+ 0.17364818f) { // cos(80 degrees)
+ return 0;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_En_Horse/EnHorse_Draw.s")
+ mountSide = EnHorse_PlayerDirToMountSide(this, globalCtx, player);
+ if (mountSide == -1) {
+ return -1;
+ }
+
+ if (mountSide == 1) {
+ return 1;
+ }
+
+ return 0;
+}
+
+s32 EnHorse_GetMountSide(EnHorse* this, GlobalContext* globalCtx) {
+ if (this->action != ENHORSE_ACT_IDLE) {
+ return 0;
+ }
+
+ if ((this->animationIdx != ENHORSE_ANIM_IDLE) && (this->animationIdx != ENHORSE_ANIM_WHINNEY)) {
+ return 0;
+ }
+
+ return EnHorse_MountSideCheck(this, globalCtx, GET_PLAYER(globalCtx));
+}
+
+void EnHorse_RandomOffset(Vec3f* src, f32 dist, Vec3f* dst) {
+ dst->x = ((Rand_ZeroOne() * (2.0f * dist)) + src->x) - dist;
+ dst->y = ((Rand_ZeroOne() * (2.0f * dist)) + src->y) - dist;
+ dst->z = ((Rand_ZeroOne() * (2.0f * dist)) + src->z) - dist;
+}
+
+void EnHorse_PostDraw(Actor* thisx, GlobalContext* globalCtx, Skin* skin) {
+ s32 pad;
+ EnHorse* this = THIS;
+ Vec3f sp7C = { 0.0f, 0.0f, 0.0f };
+ Vec3f hoofOffset = { 5.0f, -4.0f, 5.0f };
+ Vec3f sp64;
+ f32 curFrame = this->skin.skelAnime.curFrame;
+ Vec3f center;
+ Vec3f newCenter;
+ s32 i;
+ Vec3f sp38;
+ f32 sp34;
+
+ if (!(this->stateFlags & ENHORSE_CALC_RIDER_POS)) {
+ if (this->type == HORSE_2) {
+ Skin_GetVertexPos(skin, 5, 120, &this->riderPos);
+ this->riderPos.y += 13.0f;
+ } else {
+ Vec3f riderOffset = { 600.0f, -1670.0f, 0.0f };
+
+ Skin_GetLimbPos(skin, 30, &riderOffset, &this->riderPos);
+ }
+ this->riderPos.x -= this->actor.world.pos.x;
+ this->riderPos.y -= this->actor.world.pos.y;
+ this->riderPos.z -= this->actor.world.pos.z;
+ } else {
+ this->stateFlags &= ~ENHORSE_CALC_RIDER_POS;
+ }
+
+ if (this->type == HORSE_2) {
+ Skin_GetLimbPos(skin, 13, &sp7C, &sp38);
+ } else {
+ Skin_GetLimbPos(skin, 13, &sp7C, &sp38);
+ }
+
+ SkinMatrix_Vec3fMtxFMultXYZW(&globalCtx->viewProjectionMtxF, &sp38, &this->unk_218, &sp34);
+
+ if ((this->animationIdx == ENHORSE_ANIM_IDLE) && (this->action != ENHORSE_ACT_FROZEN) &&
+ (((curFrame > 40.0f) && (curFrame < 45.0f) && (this->type == 0)) ||
+ ((curFrame > 28.0f) && (curFrame < 33.0f) && (this->type == 1)))) {
+ if (Rand_ZeroOne() < 0.02f) {
+ this->dustFlags |= 1;
+ Skin_GetLimbPos(skin, 28, &hoofOffset, &this->frontRightHoof);
+ this->frontRightHoof.y -= 5.0f;
+ }
+ } else {
+ if (this->action == ENHORSE_ACT_LOW_JUMP) {
+ 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) {
+ Skin_GetLimbPos(skin, 20, &hoofOffset, &sp64);
+ } else {
+ Skin_GetLimbPos(skin, 20, &hoofOffset, &sp64);
+ }
+ EnHorse_RandomOffset(&sp64, 10.0f, &this->frontLeftHoof);
+ }
+
+ if (Rand_ZeroOne() < 0.02f) {
+ this->dustFlags |= 1;
+ if (this->type == HORSE_2) {
+ Skin_GetLimbPos(skin, 28, &hoofOffset, &sp64);
+ } else {
+ curFrame = curFrame;
+ Skin_GetLimbPos(skin, 28, &hoofOffset, &sp64);
+ }
+ EnHorse_RandomOffset(&sp64, 10.0f, &this->frontRightHoof);
+ }
+ }
+
+ 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) {
+ Skin_GetLimbPos(skin, 36, &hoofOffset, &sp64);
+ } else {
+ Skin_GetLimbPos(skin, 37, &hoofOffset, &sp64);
+ }
+ EnHorse_RandomOffset(&sp64, 10.0f, &this->backLeftHoof);
+ }
+ }
+
+ 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) {
+ Skin_GetLimbPos(skin, 44, &hoofOffset, &sp64);
+ } else {
+ Skin_GetLimbPos(skin, 45, &hoofOffset, &sp64);
+ }
+ EnHorse_RandomOffset(&sp64, 10.0f, &this->backRightHoof);
+ }
+ } 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) {
+ Skin_GetLimbPos(skin, 28, &hoofOffset, &sp64);
+ } else {
+ Skin_GetLimbPos(skin, 28, &hoofOffset, &sp64);
+ }
+ 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) {
+ Skin_GetLimbPos(skin, 20, &hoofOffset, &sp64);
+ } else {
+ Skin_GetLimbPos(skin, 20, &hoofOffset, &sp64);
+ }
+ 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) {
+ Skin_GetLimbPos(skin, 44, &hoofOffset, &sp64);
+ } else {
+ Skin_GetLimbPos(skin, 45, &hoofOffset, &sp64);
+ }
+ 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) {
+ Skin_GetLimbPos(skin, 36, &hoofOffset, &sp64);
+ } else {
+ Skin_GetLimbPos(skin, 37, &hoofOffset, &sp64);
+ }
+ EnHorse_RandomOffset(&sp64, 10.0f, &this->backLeftHoof);
+ }
+ } else if ((this->action == ENHORSE_ACT_BRIDGE_JUMP) && (curFrame > 6.0f) &&
+ (Rand_ZeroOne() < (1.0f - ((curFrame - 6.0f) * (1.0f / 17.0f))))) {
+ if (Rand_ZeroOne() < 0.05f) {
+ this->dustFlags |= 8;
+ if (this->type == HORSE_2) {
+ Skin_GetLimbPos(skin, 36, &hoofOffset, &sp64);
+ } else {
+ Skin_GetLimbPos(skin, 37, &hoofOffset, &sp64);
+ }
+ EnHorse_RandomOffset(&sp64, 10.0f, &this->backLeftHoof);
+ }
+ if (Rand_ZeroOne() < 0.02f) {
+ this->dustFlags |= 4;
+ if (this->type == HORSE_2) {
+ Skin_GetLimbPos(skin, 44, &hoofOffset, &sp64);
+ } else {
+ Skin_GetLimbPos(skin, 45, &hoofOffset, &sp64);
+ }
+ EnHorse_RandomOffset(&sp64, 10.0f, &this->backRightHoof);
+ }
+ } else if ((this->action == ENHORSE_ACT_CS_UPDATE) && (curFrame > 5.0f)) {
+ if (Rand_ZeroOne() < (1.0f - ((curFrame - 5.0f) * 0.04f))) {
+ if (Rand_ZeroOne() < 0.05f) {
+ this->dustFlags |= 8;
+ if (this->type == HORSE_2) {
+ Skin_GetLimbPos(skin, 36, &hoofOffset, &sp64);
+ } else {
+ Skin_GetLimbPos(skin, 37, &hoofOffset, &sp64);
+ }
+ EnHorse_RandomOffset(&sp64, 10.0f, &this->backLeftHoof);
+ }
+
+ if (Rand_ZeroOne() < 0.02f) {
+ this->dustFlags |= 4;
+ if (this->type == HORSE_2) {
+ Skin_GetLimbPos(skin, 44, &hoofOffset, &sp64);
+ } else {
+ Skin_GetLimbPos(skin, 45, &hoofOffset, &sp64);
+ }
+ EnHorse_RandomOffset(&sp64, 10.0f, &this->backRightHoof);
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < this->colliderJntSph.count; i++) {
+ center.x = this->colliderJntSph.elements[i].dim.modelSphere.center.x;
+ center.y = this->colliderJntSph.elements[i].dim.modelSphere.center.y;
+ center.z = this->colliderJntSph.elements[i].dim.modelSphere.center.z;
+
+ Skin_GetLimbPos(skin, this->colliderJntSph.elements[i].dim.limb, ¢er, &newCenter);
+
+ this->colliderJntSph.elements[i].dim.worldSphere.center.x = newCenter.x;
+ this->colliderJntSph.elements[i].dim.worldSphere.center.y = newCenter.y;
+ this->colliderJntSph.elements[i].dim.worldSphere.center.z = newCenter.z;
+
+ this->colliderJntSph.elements[i].dim.worldSphere.radius =
+ this->colliderJntSph.elements[i].dim.modelSphere.radius * this->colliderJntSph.elements[i].dim.scale;
+ }
+
+ //! @bug Setting colliders in a draw function allows for duplicate entries to be added to their respective lists
+ //! under certain conditions, like when pausing and unpausing the game.
+ //! Actors will draw for a couple of frames between the pauses, but some important logic updates will not occur.
+ //! In the case of OC, this can cause unwanted effects such as a very large amount of displacement being applied to
+ //! a colliding actor.
+ if (!(this->stateFlags & ENHORSE_JUMPING)) {
+ CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->colliderJntSph.base);
+ }
+}
+
+s32 EnHorse_OverrideLimbDraw(Actor* thisx, GlobalContext* globalCtx, s32 limbIndex, Skin* skin) {
+ static TexturePtr D_80889204[] = {
+ object_horse_link_child_Tex_001D28,
+ object_horse_link_child_Tex_001928,
+ object_horse_link_child_Tex_001B28,
+ };
+ static u8 D_80889210[] = { 0, 1, 2, 1 };
+ EnHorse* this = THIS;
+ s32 drawOriginalLimb = true;
+
+ OPEN_DISPS(globalCtx->state.gfxCtx);
+
+ if ((limbIndex != 13) || (this->type != HORSE_EPONA)) {
+ if ((limbIndex == 13) && (this->type == HORSE_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)) {
+ drawOriginalLimb = false;
+ }
+ }
+
+ CLOSE_DISPS(globalCtx->state.gfxCtx);
+
+ return drawOriginalLimb;
+}
+
+s32 func_80888D18(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, Actor* thisx) {
+ Vec3f sp1C = { -98.0f, -1454.0f, 0.0f };
+ EnHorse* this = THIS;
+
+ if (limbIndex == 3) {
+ Matrix_MultiplyVector3fByState(&sp1C, &this->riderPos);
+ }
+ return false;
+}
+
+void EnHorse_Draw(Actor* thisx, GlobalContext* globalCtx) {
+ EnHorse* this = THIS;
+
+ if (!(this->stateFlags & ENHORSE_INACTIVE) && (this->actor.update != func_8087D540)) {
+ func_8012C28C(globalCtx->state.gfxCtx);
+ this->stateFlags |= ENHORSE_DRAW;
+ if (!(this->unk_1EC & 1)) {
+ if (this->stateFlags & ENHORSE_JUMPING) {
+ func_80138258(&this->actor, globalCtx, &this->skin, EnHorse_PostDraw, EnHorse_OverrideLimbDraw, false);
+ } else {
+ func_80138258(&this->actor, globalCtx, &this->skin, EnHorse_PostDraw, EnHorse_OverrideLimbDraw, true);
+ }
+ } else {
+ if (this->stateFlags & ENHORSE_JUMPING) {
+ this->skin.skelAnime.jointTable->x = 0;
+ this->skin.skelAnime.jointTable->y = 0;
+ this->skin.skelAnime.jointTable->z = 0;
+ }
+ SkelAnime_DrawFlexOpa(globalCtx, this->skin.skelAnime.skeleton, this->skin.skelAnime.jointTable,
+ this->skin.skelAnime.dListCount, func_80888D18, NULL, &this->actor);
+ }
+
+ if (this->postDrawFunc != NULL) {
+ this->postDrawFunc(this, globalCtx);
+ }
+ }
+}
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 d1eef6186a..2dc5e44f51 100644
--- a/src/overlays/actors/ovl_En_Horse/z_en_horse.h
+++ b/src/overlays/actors/ovl_En_Horse/z_en_horse.h
@@ -3,20 +3,217 @@
#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;
+typedef void (*EnHorseActionFunc)(struct EnHorse*, GlobalContext*);
+typedef void (*EnHorsePostdrawFunc)(struct EnHorse*, GlobalContext*);
+typedef void (*EnHorseCsFunc)(struct EnHorse*, GlobalContext*, CsCmdActorAction*);
+
+#define ENHORSE_BOOST (1 << 0) /* 0x1 */
+#define ENHORSE_BOOST_DECEL (1 << 1) /* 0x2 */
+#define ENHORSE_JUMPING (1 << 2) /* 0x4 */
+#define ENHORSE_CALC_RIDER_POS (1 << 3) /* 0x8 */
+#define ENHORSE_FORCE_REVERSING (1 << 4) /* 0x10 */
+#define ENHORSE_FORCE_WALKING (1 << 5) /* 0x20 */
+#define ENHORSE_FLAG_6 (1 << 6) /* 0x40 */
+#define ENHORSE_FLAG_7 (1 << 7) /* 0x80 */
+#define ENHORSE_FLAG_8 (1 << 8) /* 0x100 */
+#define ENHORSE_FLAG_9 (1 << 9) /* 0x200 */
+#define ENHORSE_STOPPING_NEIGH_SOUND (1 << 10) /* 0x400 */
+#define ENHORSE_LAND2_SOUND (1 << 11) /* 0x800 */
+#define ENHORSE_SANDDUST_SOUND (1 << 12) /* 0x1000 */
+#define ENHORSE_INACTIVE (1 << 13) /* 0x2000 */
+#define ENHORSE_OBSTACLE (1 << 14) /* 0x4000 */
+#define ENHORSE_TURNING_TO_PLAYER (1 << 15) /* 0x8000 */
+#define ENHORSE_UNRIDEABLE (1 << 16) /* 0x10000 */
+#define ENHORSE_CANT_JUMP (1 << 17) /* 0x20000 */
+#define ENHORSE_FLAG_18 (1 << 18) /* 0x40000 */
+#define ENHORSE_FLAG_19 (1 << 19) /* 0x80000 */
+#define ENHORSE_FLAG_20 (1 << 20) /* 0x100000 */
+#define ENHORSE_FLAG_21 (1 << 21) /* 0x200000 */
+#define ENHORSE_FIRST_BOOST_REGEN (1 << 22) /* 0x400000 */
+#define ENHORSE_INGO_WON (1 << 23) /* 0x800000 */
+#define ENHORSE_FLAG_24 (1 << 24) /* 0x1000000 */
+#define ENHORSE_FLAG_25 (1 << 25) /* 0x2000000 */
+#define ENHORSE_FLAG_26 (1 << 26) /* 0x4000000 */
+#define ENHORSE_DRAW (1 << 27) /* 0x8000000 */
+#define ENHORSE_FLAG_28 (1 << 28) /* 0x10000000 */
+#define ENHORSE_FLAG_29 (1 << 29) /* 0x20000000 */
+#define ENHORSE_FLAG_30 (1 << 30) /* 0x40000000 */
+#define ENHORSE_FLAG_31 (1 << 31) /* 0x80000000 */
+
+typedef enum {
+ /* 0 */ ENHORSE_ACT_FROZEN,
+ /* 1 */ ENHORSE_ACT_INACTIVE,
+ /* 2 */ ENHORSE_ACT_IDLE,
+ /* 3 */ ENHORSE_ACT_FOLLOW_PLAYER,
+ /* 4 */ ENHORSE_ACT_INGO_RACE,
+ /* 5 */ ENHORSE_ACT_MOUNTED_IDLE,
+ /* 6 */ ENHORSE_ACT_MOUNTED_IDLE_WHINNEYING,
+ /* 7 */ ENHORSE_ACT_MOUNTED_TURN,
+ /* 8 */ ENHORSE_ACT_MOUNTED_WALK,
+ /* 9 */ ENHORSE_ACT_MOUNTED_TROT,
+ /* 10 */ ENHORSE_ACT_MOUNTED_GALLOP,
+ /* 11 */ ENHORSE_ACT_MOUNTED_REARING,
+ /* 12 */ ENHORSE_ACT_STOPPING,
+ /* 13 */ ENHORSE_ACT_REVERSE,
+ /* 14 */ ENHORSE_ACT_LOW_JUMP,
+ /* 15 */ ENHORSE_ACT_HIGH_JUMP,
+ /* 16 */ ENHORSE_ACT_BRIDGE_JUMP,
+ /* 17 */ ENHORSE_ACT_CS_UPDATE,
+ /* 18 */ ENHORSE_ACT_HBA,
+ /* 19 */ ENHORSE_ACT_FLEE_PLAYER,
+ /* 20 */ ENHORSE_ACT_20,
+ /* 21 */ ENHORSE_ACT_21,
+ /* 22 */ ENHORSE_ACT_22,
+ /* 23 */ ENHORSE_ACT_23,
+ /* 24 */ ENHORSE_ACT_24,
+ /* 25 */ ENHORSE_ACT_25,
+} EnHorseAction;
+
+typedef enum {
+ /* 0 */ PLAYER_DIR_FRONT_R,
+ /* 1 */ PLAYER_DIR_FRONT_L,
+ /* 2 */ PLAYER_DIR_BACK_R,
+ /* 3 */ PLAYER_DIR_BACK_L,
+ /* 4 */ PLAYER_DIR_SIDE_R,
+ /* 5 */ PLAYER_DIR_SIDE_L
+} EnHorsePlayerDir;
+
+typedef enum {
+ /* 0 */ ENHORSE_ANIM_IDLE,
+ /* 1 */ ENHORSE_ANIM_WHINNEY,
+ /* 2 */ ENHORSE_ANIM_STOPPING,
+ /* 3 */ ENHORSE_ANIM_REARING,
+ /* 4 */ ENHORSE_ANIM_WALK,
+ /* 5 */ ENHORSE_ANIM_TROT,
+ /* 6 */ ENHORSE_ANIM_GALLOP,
+ /* 7 */ ENHORSE_ANIM_LOW_JUMP,
+ /* 8 */ ENHORSE_ANIM_HIGH_JUMP
+} EnHorseAnimationIndex;
+
+typedef enum {
+ /* 0 */ HORSE_EPONA,
+ /* 1 */ HORSE_HNI,
+ /* 2 */ HORSE_2,
+ /* 3 */ HORSE_3,
+ /* 4 */ HORSE_4
+} 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)
+
+enum {
+ /* 0 */ ENHORSE_0,
+ /* 1 */ ENHORSE_1,
+ /* 2 */ ENHORSE_2,
+ /* 3 */ ENHORSE_3,
+ /* 4 */ ENHORSE_4,
+ /* 5 */ ENHORSE_5,
+ /* 6 */ ENHORSE_6,
+ /* 7 */ ENHORSE_7,
+ /* 8 */ ENHORSE_8,
+ /* 9 */ ENHORSE_9,
+ /* 10 */ ENHORSE_10,
+ /* 11 */ ENHORSE_11,
+ /* 12 */ ENHORSE_12,
+ /* 13 */ ENHORSE_13,
+ /* 14 */ ENHORSE_14,
+ /* 15 */ ENHORSE_15,
+ /* 16 */ ENHORSE_16,
+ /* 17 */ ENHORSE_17,
+ /* 18 */ ENHORSE_18,
+ /* 19 */ ENHORSE_19,
+ /* 20 */ ENHORSE_20,
+};
+
typedef struct EnHorse {
/* 0x000 */ Actor actor;
- /* 0x144 */ char unk_144[0xC];
- /* 0x150 */ s32 unk_150;
- /* 0x154 */ char unk_154[0x98];
- /* 0x1EC */ UNK_TYPE4 unk_1EC;
- /* 0x1F0 */ char unk_1F0[0x5C];
- /* 0x24C */ u32 unk_24C;
- /* 0x250 */ char unk_250[0x138];
+ /* 0x144 */ s32 action;
+ /* 0x148 */ s32 noInputTimer;
+ /* 0x14C */ s32 noInputTimerMax;
+ /* 0x150 */ s32 type;
+ /* 0x154 */ s8 bankIndex;
+ /* 0x158 */ Skin skin;
+ /* 0x1E8 */ s32 stateFlags;
+ /* 0x1EC */ s32 unk_1EC;
+ /* 0x1F0 */ Vec3f lastPos;
+ /* 0x1FC */ s16 lastYaw;
+ /* 0x200 */ s32 curRaceWaypoint;
+ /* 0x204 */ s32 boostSpeed;
+ /* 0x208 */ s32 playerControlled;
+ /* 0x20C */ s32 animationIdx;
+ /* 0x210 */ f32 curFrame;
+ /* 0x214 */ s32 soundTimer;
+ /* 0x218 */ Vec3f unk_218;
+ /* 0x224 */ UNK_TYPE1 unk224[0xC];
+ /* 0x230 */ s32 unk_230;
+ /* 0x234 */ u8 numBoosts;
+ /* 0x238 */ s32 boostRegenTime;
+ /* 0x23C */ s32 boostTimer;
+ /* 0x240 */ EnHorsePostdrawFunc postDrawFunc;
+ /* 0x244 */ f32 yFront;
+ /* 0x248 */ f32 yBack;
+ /* 0x24C */ s32 unk_24C;
+ /* 0x250 */ s16 followTimer;
+ /* 0x254 */ s32 prevAction;
+ /* 0x258 */ Vec3f riderPos;
+ /* 0x264 */ Vec2f curStick;
+ /* 0x26C */ Vec2f lastStick;
+ /* 0x274 */ f32 jumpStartY;
+ /* 0x278 */ ColliderCylinder colliderCylinder1;
+ /* 0x2C4 */ ColliderCylinder colliderCylinder2;
+ /* 0x310 */ ColliderJntSph colliderJntSph;
+ /* 0x330 */ ColliderJntSphElement colliderJntSphElements[1];
+ /* 0x370 */ s32 playerDir;
+ /* 0x374 */ UNK_TYPE1 unk374[0x2];
+ /* 0x376 */ s16 angleToPlayer;
+ /* 0x378 */ s16 followPlayerTurnSpeed;
+ /* 0x37A */ u8 blinkTimer;
+ /* 0x37C */ s16 waitTimer;
+ /* 0x380 */ s32 cutsceneAction;
+ /* 0x384 */ u16 cutsceneFlags;
/* 0x388 */ s32 inRace;
- /* 0x38C */ char unk_38C[0x208];
+ /* 0x38C */ struct EnIn* rider;
+ /* 0x390 */ UNK_TYPE1 unk390[0x4];
+ /* 0x394 */ u16 unk_394;
+ /* 0x398 */ f32 unk_398;
+ /* 0x39C */ s32 unk_39C;
+ /* 0x3A0 */ s32 hbaStarted;
+ /* 0x3A4 */ s32 hbaFlags;
+ /* 0x3A8 */ s32 hbaTimer;
+ /* 0x3AC */ u16 dustFlags;
+ /* 0x3B0 */ Vec3f frontRightHoof;
+ /* 0x3BC */ Vec3f frontLeftHoof;
+ /* 0x3C8 */ Vec3f backRightHoof;
+ /* 0x3D4 */ Vec3f backLeftHoof;
+ /* 0x3E0 */ s32 unk_3E0;
+ /* 0x3E4 */ UNK_TYPE1 unk3E4[0x4];
+ /* 0x3E8 */ f32 unk_3E8;
+ /* 0x3EC */ s16 unk_3EC;
+ /* 0x3EE */ Vec3s jointTable[OBJECT_HA_1_LIMB_MAX];
+ /* 0x48A */ Vec3s morphTable[OBJECT_HA_1_LIMB_MAX];
+ /* 0x528 */ f32 unk_528;
+ /* 0x52C */ s32 unk_52C;
+ /* 0x530 */ s32 unk_530;
+ /* 0x534 */ s32 unk_534;
+ /* 0x538 */ s32 unk_538;
+ /* 0x53C */ s32 unk_53C;
+ /* 0x540 */ Vec3f unk_540;
+ /* 0x54C */ UNK_TYPE1 unk54C[0x4];
+ /* 0x550 */ s32 unk_550;
+ /* 0x554 */ UNK_TYPE1 unk554[0x18];
+ /* 0x56C */ f32 unk_56C;
+ /* 0x570 */ Vec3f unk_570;
+ /* 0x57C */ Vec3f unk_57C;
+ /* 0x588 */ UNK_TYPE1 unk588[0x4];
+ /* 0x58C */ s32 unk_58C;
+ /* 0x590 */ s32 unk_590;
} EnHorse; // size = 0x594
extern const ActorInit En_Horse_InitVars;
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 3d66872634..729a82a705 100644
--- a/src/overlays/actors/ovl_En_Test4/z_en_test4.c
+++ b/src/overlays/actors/ovl_En_Test4/z_en_test4.c
@@ -405,7 +405,7 @@ void func_80A42AB8(EnTest4* this, GlobalContext* globalCtx) {
if (player->stateFlags1 & 0x800000) {
EnHorse* rideActor = (EnHorse*)player->rideActor;
- if ((rideActor->unk_150 == 0) || (rideActor->unk_150 == 2)) {
+ if ((rideActor->type == HORSE_EPONA) || (rideActor->type == HORSE_2)) {
if (CURRENT_DAY < 3) {
D_801BDA9C = 1;
} else {
diff --git a/tools/actorfixer.py b/tools/actorfixer.py
index d7ffef8d16..0370f00439 100755
--- a/tools/actorfixer.py
+++ b/tools/actorfixer.py
@@ -505,11 +505,11 @@ animdict = {
"gSaveContext.weekEventReg": "gSaveContext.save.weekEventReg",
"gSaveContext.playerForm": "gSaveContext.save.playerForm",
"gSaveContext.day": "gSaveContext.save.day",
- # "gSaveContext.cutscene": "gSaveContext.save.cutscene",
+ "gSaveContext.cutscene": "gSaveContext.save.cutscene",
"gSaveContext.isNight": "gSaveContext.save.isNight",
"gSaveContext.naviTimer": "gSaveContext.save.playerData.tatlTimer",
"gSaveContext.tatlTimer": "gSaveContext.save.playerData.tatlTimer",
- # "gSaveContext.health": "gSaveContext.save.playerData.health",
+ "gSaveContext.health": "gSaveContext.save.playerData.health",
"gSaveContext.rupees": "gSaveContext.save.playerData.rupees",
"gSaveContext.magicAcquired": "gSaveContext.save.playerData.magicAcquired",
"gSaveContext.doubleMagic": "gSaveContext.save.playerData.doubleMagic",
diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt
index abfae35aa0..0ac959c7a1 100644
--- a/tools/disasm/functions.txt
+++ b/tools/disasm/functions.txt
@@ -5206,82 +5206,82 @@
0x8087AF48:("EnFirefly_OverrideLimbDraw",),
0x8087AF98:("EnFirefly_PostLimbDraw",),
0x8087B320:("EnFirefly_Draw",),
- 0x8087B730:("func_8087B730",),
- 0x8087B784:("func_8087B784",),
+ 0x8087B730:("EnHorse_RaceWaypointPos",),
+ 0x8087B784:("EnHorse_RotateToPoint",),
0x8087B7C0:("func_8087B7C0",),
- 0x8087C0AC:("func_8087C0AC",),
+ 0x8087C0AC:("EnHorse_PlayWalkingSound",),
0x8087C178:("func_8087C178",),
0x8087C1C0:("func_8087C1C0",),
- 0x8087C208:("func_8087C208",),
+ 0x8087C208:("EnHorse_SlopeSpeedMultiplier",),
0x8087C288:("func_8087C288",),
0x8087C2B8:("func_8087C2B8",),
0x8087C38C:("func_8087C38C",),
- 0x8087C43C:("func_8087C43C",),
- 0x8087C590:("func_8087C590",),
- 0x8087C8B8:("func_8087C8B8",),
- 0x8087C8D0:("func_8087C8D0",),
- 0x8087C8E0:("func_8087C8E0",),
- 0x8087C9D4:("func_8087C9D4",),
- 0x8087C9EC:("func_8087C9EC",),
+ 0x8087C43C:("EnHorse_IdleAnimSounds",),
+ 0x8087C590:("EnHorse_Spawn",),
+ 0x8087C8B8:("EnHorse_ResetCutscene",),
+ 0x8087C8D0:("EnHorse_ResetRace",),
+ 0x8087C8E0:("EnHorse_PlayerCanMove",),
+ 0x8087C9D4:("EnHorse_ResetHorsebackArchery",),
+ 0x8087C9EC:("EnHorse_ClearDustFlags",),
0x8087C9F8:("func_8087C9F8",),
0x8087CA04:("func_8087CA04",),
0x8087CA14:("EnHorse_Init",),
0x8087D540:("func_8087D540",),
0x8087D69C:("EnHorse_Destroy",),
- 0x8087D70C:("func_8087D70C",),
- 0x8087D75C:("func_8087D75C",),
- 0x8087D814:("func_8087D814",),
- 0x8087D988:("func_8087D988",),
- 0x8087DDEC:("func_8087DDEC",),
- 0x8087DE28:("func_8087DE28",),
- 0x8087DF64:("func_8087DF64",),
- 0x8087E080:("func_8087E080",),
- 0x8087E0A4:("func_8087E0A4",),
- 0x8087E18C:("func_8087E18C",),
- 0x8087E2A8:("func_8087E2A8",),
- 0x8087E350:("func_8087E350",),
- 0x8087E564:("func_8087E564",),
- 0x8087E5B4:("func_8087E5B4",),
- 0x8087E5D8:("func_8087E5D8",),
- 0x8087E684:("func_8087E684",),
- 0x8087E6D8:("func_8087E6D8",),
- 0x8087E92C:("func_8087E92C",),
- 0x8087E9D0:("func_8087E9D0",),
- 0x8087EA1C:("func_8087EA1C",),
- 0x8087EB54:("func_8087EB54",),
- 0x8087EB78:("func_8087EB78",),
- 0x8087EC20:("func_8087EC20",),
- 0x8087EC78:("func_8087EC78",),
- 0x8087ED10:("func_8087ED10",),
- 0x8087EEC4:("func_8087EEC4",),
- 0x8087F078:("func_8087F078",),
- 0x8087F1FC:("func_8087F1FC",),
- 0x8087F39C:("func_8087F39C",),
- 0x8087F590:("func_8087F590",),
- 0x8087F5B4:("func_8087F5B4",),
- 0x8087F658:("func_8087F658",),
- 0x8087F9A0:("func_8087F9A0",),
- 0x8087F9C4:("func_8087F9C4",),
- 0x8087FB08:("func_8087FB08",),
- 0x8087FB14:("func_8087FB14",),
- 0x8087FD94:("func_8087FD94",),
- 0x8087FDB8:("func_8087FDB8",),
- 0x8087FF08:("func_8087FF08",),
- 0x8087FF14:("func_8087FF14",),
- 0x808801A8:("func_808801A8",),
- 0x808801F8:("func_808801F8",),
- 0x808802D0:("func_808802D0",),
- 0x808804A4:("func_808804A4",),
- 0x808804CC:("func_808804CC",),
- 0x80880500:("func_80880500",),
- 0x80880534:("func_80880534",),
- 0x808806DC:("func_808806DC",),
- 0x80880844:("func_80880844",),
- 0x80880978:("func_80880978",),
- 0x80880D50:("func_80880D50",),
- 0x80880DA8:("func_80880DA8",),
- 0x80880E00:("func_80880E00",),
- 0x80881128:("func_80881128",),
+ 0x8087D70C:("EnHorse_RotateToPlayer",),
+ 0x8087D75C:("EnHorse_Freeze",),
+ 0x8087D814:("EnHorse_Frozen",),
+ 0x8087D988:("EnHorse_UpdateSpeed",),
+ 0x8087DDEC:("EnHorse_StartMountedIdleResetAnim",),
+ 0x8087DE28:("EnHorse_StartMountedIdle",),
+ 0x8087DF64:("EnHorse_MountedIdle",),
+ 0x8087E080:("EnHorse_MountedIdleAnim",),
+ 0x8087E0A4:("EnHorse_MountedIdleWhinney",),
+ 0x8087E18C:("EnHorse_MountedIdleWhinneying",),
+ 0x8087E2A8:("EnHorse_StartTurning",),
+ 0x8087E350:("EnHorse_MountedTurn",),
+ 0x8087E564:("EnHorse_StartWalkingFromIdle",),
+ 0x8087E5B4:("EnHorse_StartWalkingInterruptable",),
+ 0x8087E5D8:("EnHorse_StartWalking",),
+ 0x8087E684:("EnHorse_MountedWalkingReset",),
+ 0x8087E6D8:("EnHorse_MountedWalk",),
+ 0x8087E92C:("EnHorse_StartTrotting",),
+ 0x8087E9D0:("EnHorse_MountedTrotReset",),
+ 0x8087EA1C:("EnHorse_MountedTrot",),
+ 0x8087EB54:("EnHorse_StartGallopingInterruptable",),
+ 0x8087EB78:("EnHorse_StartGalloping",),
+ 0x8087EC20:("EnHorse_MountedGallopReset",),
+ 0x8087EC78:("EnHorse_JumpLanding",),
+ 0x8087ED10:("EnHorse_MountedGallop",),
+ 0x8087EEC4:("EnHorse_StartRearing",),
+ 0x8087F078:("EnHorse_MountedRearing",),
+ 0x8087F1FC:("EnHorse_StartBraking",),
+ 0x8087F39C:("EnHorse_Stopping",),
+ 0x8087F590:("EnHorse_StartReversingInterruptable",),
+ 0x8087F5B4:("EnHorse_StartReversing",),
+ 0x8087F658:("EnHorse_Reverse",),
+ 0x8087F9A0:("EnHorse_LowJumpInit",),
+ 0x8087F9C4:("EnHorse_StartLowJump",),
+ 0x8087FB08:("EnHorse_Stub1",),
+ 0x8087FB14:("EnHorse_LowJump",),
+ 0x8087FD94:("EnHorse_HighJumpInit",),
+ 0x8087FDB8:("EnHorse_StartHighJump",),
+ 0x8087FF08:("EnHorse_Stub2",),
+ 0x8087FF14:("EnHorse_HighJump",),
+ 0x808801A8:("EnHorse_InitInactive",),
+ 0x808801F8:("EnHorse_Inactive",),
+ 0x808802D0:("EnHorse_PlayIdleAnimation",),
+ 0x808804A4:("EnHorse_ChangeIdleAnimation",),
+ 0x808804CC:("EnHorse_ResetIdleAnimation",),
+ 0x80880500:("EnHorse_StartIdleRidable",),
+ 0x80880534:("EnHorse_Idle",),
+ 0x808806DC:("EnHorse_StartMovingAnimation",),
+ 0x80880844:("EnHorse_SetFollowAnimation",),
+ 0x80880978:("EnHorse_FollowPlayer",),
+ 0x80880D50:("EnHorse_InitIngoHorse",),
+ 0x80880DA8:("EnHorse_SetIngoAnimation",),
+ 0x80880E00:("EnHorse_UpdateIngoHorseAnim",),
+ 0x80881128:("EnHorse_UpdateIngoRace",),
0x8088126C:("func_8088126C",),
0x80881290:("func_80881290",),
0x80881398:("func_80881398",),
@@ -5289,26 +5289,26 @@
0x80881634:("func_80881634",),
0x8088168C:("func_8088168C",),
0x808819D8:("func_808819D8",),
- 0x80881BDC:("func_80881BDC",),
- 0x80881C54:("func_80881C54",),
- 0x80881DA4:("func_80881DA4",),
- 0x80881DC8:("func_80881DC8",),
- 0x80881F10:("func_80881F10",),
- 0x80881F48:("func_80881F48",),
- 0x808821C8:("func_808821C8",),
- 0x808822CC:("func_808822CC",),
- 0x8088247C:("func_8088247C",),
- 0x80882564:("func_80882564",),
- 0x808826B4:("func_808826B4",),
- 0x80882820:("func_80882820",),
- 0x808829D0:("func_808829D0",),
- 0x808829F4:("func_808829F4",),
- 0x80882A44:("func_80882A44",),
- 0x80882B9C:("func_80882B9C",),
- 0x80882D8C:("func_80882D8C",),
- 0x80882DC0:("func_80882DC0",),
- 0x80883104:("func_80883104",),
- 0x80883308:("func_80883308",),
+ 0x80881BDC:("EnHorse_CsMoveInit",),
+ 0x80881C54:("EnHorse_CsMoveToPoint",),
+ 0x80881DA4:("EnHorse_CsSetAnimHighJump",),
+ 0x80881DC8:("EnHorse_CsPlayHighJumpAnim",),
+ 0x80881F10:("EnHorse_CsJumpInit",),
+ 0x80881F48:("EnHorse_CsJump",),
+ 0x808821C8:("EnHorse_CsRearingInit",),
+ 0x808822CC:("EnHorse_CsRearing",),
+ 0x8088247C:("EnHorse_WarpMoveInit",),
+ 0x80882564:("EnHorse_CsWarpMoveToPoint",),
+ 0x808826B4:("EnHorse_CsWarpRearingInit",),
+ 0x80882820:("EnHorse_CsWarpRearing",),
+ 0x808829D0:("EnHorse_InitCutscene",),
+ 0x808829F4:("EnHorse_GetCutsceneFunctionIndex",),
+ 0x80882A44:("EnHorse_CutsceneUpdate",),
+ 0x80882B9C:("EnHorse_UpdateHbaRaceInfo",),
+ 0x80882D8C:("EnHorse_InitHorsebackArchery",),
+ 0x80882DC0:("EnHorse_UpdateHbaAnim",),
+ 0x80883104:("EnHorse_UpdateHorsebackArchery",),
+ 0x80883308:("EnHorse_FleePlayer",),
0x80883B70:("func_80883B70",),
0x80883BEC:("func_80883BEC",),
0x80883CB0:("func_80883CB0",),
@@ -5338,29 +5338,29 @@
0x80884A40:("func_80884A40",),
0x80884D04:("func_80884D04",),
0x80884E0C:("func_80884E0C",),
- 0x80885060:("func_80885060",),
- 0x808850DC:("func_808850DC",),
- 0x80885220:("func_80885220",),
- 0x808853E0:("func_808853E0",),
- 0x8088598C:("func_8088598C",),
- 0x80885A80:("func_80885A80",),
- 0x80885AF4:("func_80885AF4",),
- 0x80885B4C:("func_80885B4C",),
- 0x80885C90:("func_80885C90",),
- 0x80885DA4:("func_80885DA4",),
+ 0x80885060:("EnHorse_Vec3fOffset",),
+ 0x808850DC:("EnHorse_CalcFloorHeight",),
+ 0x80885220:("EnHorse_ObstructMovement",),
+ 0x808853E0:("EnHorse_CheckFloors",),
+ 0x8088598C:("EnHorse_MountDismount",),
+ 0x80885A80:("EnHorse_StickDirection",),
+ 0x80885AF4:("EnHorse_UpdateStick",),
+ 0x80885B4C:("EnHorse_ResolveCollision",),
+ 0x80885C90:("EnHorse_BgCheckSlowMoving",),
+ 0x80885DA4:("EnHorse_UpdateBgCheckInfo",),
0x80886C00:("func_80886C00",),
- 0x80886DC4:("func_80886DC4",),
- 0x80886FA8:("func_80886FA8",),
- 0x808870A4:("func_808870A4",),
- 0x808871A0:("func_808871A0",),
- 0x80887270:("func_80887270",),
+ 0x80886DC4:("EnHorse_RegenBoost",),
+ 0x80886FA8:("EnHorse_UpdatePlayerDir",),
+ 0x808870A4:("EnHorse_TiltBody",),
+ 0x808871A0:("EnHorse_UpdateConveyors",),
+ 0x80887270:("EnHorse_RandInt",),
0x808872A4:("EnHorse_Update",),
- 0x80887D20:("func_80887D20",),
- 0x80887D60:("func_80887D60",),
- 0x80887E64:("func_80887E64",),
- 0x80887EBC:("func_80887EBC",),
- 0x80887F58:("func_80887F58",),
- 0x80888C48:("func_80888C48",),
+ 0x80887D20:("EnHorse_PlayerDirToMountSide",),
+ 0x80887D60:("EnHorse_MountSideCheck",),
+ 0x80887E64:("EnHorse_GetMountSide",),
+ 0x80887EBC:("EnHorse_RandomOffset",),
+ 0x80887F58:("EnHorse_PostDraw",),
+ 0x80888C48:("EnHorse_OverrideLimbDraw",),
0x80888D18:("func_80888D18",),
0x80888D78:("EnHorse_Draw",),
0x8088A240:("EnArrow_Init",),
diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt
index 0d6b8fc768..2cce52fbae 100644
--- a/tools/disasm/variables.txt
+++ b/tools/disasm/variables.txt
@@ -5896,19 +5896,18 @@
0x8087B538:("D_8087B538","f32","",0x4),
0x80888EC0:("D_80888EC0","UNK_TYPE1","",0x1),
0x80888EE4:("D_80888EE4","UNK_TYPE1","",0x1),
- 0x80888F08:("D_80888F08","UNK_TYPE1","",0x1),
+ 0x80888F08:("sAnimationHeaders","AnimationHeader*","[5]",0x14),
0x80888F1C:("D_80888F1C","UNK_TYPE1","",0x1),
0x80888F34:("D_80888F34","UNK_TYPE4","",0x4),
- 0x80888F40:("D_80888F40","UNK_TYPE1","",0x1),
+ 0x80888F40:("sSkeletonHeaders","UNK_TYPE1","",0x1),
0x80888F54:("En_Horse_InitVars","UNK_TYPE1","",0x1),
- 0x80888F74:("D_80888F74","UNK_TYPE1","",0x1),
- 0x80888FA0:("D_80888FA0","UNK_TYPE1","",0x1),
+ 0x80888F74:("sCylinderInit1","UNK_TYPE1","",0x1),
+ 0x80888FA0:("sCylinderInit2","UNK_TYPE1","",0x1),
0x80888FCC:("D_80888FCC","UNK_TYPE1","",0x1),
- 0x80888FF0:("D_80888FF0","UNK_TYPE1","",0x1),
- 0x80888FFC:("D_80888FFC","UNK_PTR","",0x4),
- 0x80889000:("D_80889000","UNK_TYPE1","",0x1),
+ 0x80888FF0:("sJntSphInit","UNK_TYPE1","",0x10),
+ 0x80889000:("sColChkInfoInit","UNK_TYPE1","",0x1),
0x80889008:("D_80889008","UNK_TYPE1","",0x1),
- 0x80889010:("D_80889010","UNK_TYPE1","",0x1),
+ 0x80889010:("sInitChain","UNK_TYPE1","",0x1),
0x80889018:("D_80889018","UNK_TYPE1","",0x1),
0x80889030:("D_80889030","UNK_TYPE1","",0x1),
0x80889048:("D_80889048","UNK_TYPE1","",0x1),
@@ -5923,7 +5922,7 @@
0x8088911C:("D_8088911C","UNK_TYPE1","",0x1),
0x80889148:("D_80889148","UNK_TYPE4","",0x4),
0x80889154:("D_80889154","UNK_TYPE4","",0x4),
- 0x80889160:("D_80889160","UNK_PTR","",0x4),
+ 0x80889160:("sActionFuncs","UNK_PTR","",0x4),
0x808891C8:("D_808891C8","UNK_TYPE4","",0x4),
0x808891D4:("D_808891D4","UNK_TYPE4","",0x4),
0x808891E0:("D_808891E0","UNK_TYPE4","",0x4),
diff --git a/undefined_syms.txt b/undefined_syms.txt
index de13da3ae3..4807cfc119 100644
--- a/undefined_syms.txt
+++ b/undefined_syms.txt
@@ -1234,17 +1234,6 @@ D_0600B644 = 0x0600B644;
D_0600F248 = 0x0600F248;
D_06012A58 = 0x06012A58;
-// ovl_En_Horse
-
-D_06008C68 = 0x06008C68;
-D_0600A8DC = 0x0600A8DC;
-D_0600AD08 = 0x0600AD08;
-D_0600B3E0 = 0x0600B3E0;
-D_0600BDE0 = 0x0600BDE0;
-D_0600D178 = 0x0600D178;
-D_0600D4E8 = 0x0600D4E8;
-D_060150D8 = 0x060150D8;
-
// ovl_En_Horse_Link_Child
D_06002F98 = 0x06002F98;