diff --git a/soh/include/functions.h b/soh/include/functions.h index 8deb36953..49330bc95 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -889,13 +889,13 @@ void SkelCurve_SetAnim(SkelAnimeCurve* skelCurve, TransformUpdateIndex* transUpd s32 SkelCurve_Update(PlayState* play, SkelAnimeCurve* skelCurve); void SkelCurve_Draw(Actor* actor, PlayState* play, SkelAnimeCurve* skelCurve, OverrideCurveLimbDraw overrideLimbDraw, PostCurveLimbDraw postLimbDraw, s32 lod, void* data); -s32 func_8006CFC0(s32 scene); -void func_8006D074(PlayState* play); -void func_8006D0AC(PlayState* play); -void func_8006D0EC(PlayState* play, Player* player); -void func_8006D684(PlayState* play, Player* player); -void func_8006DC68(PlayState* play, Player* player); -void func_8006DD9C(Actor* actor, Vec3f* arg1, s16 arg2); +s32 Horse_IsValidScene(s32 scene); +void Horse_SetDefaultSpawn(PlayState* play); +void Horse_PatchLakeHyliaSpawn(PlayState* play); +void Horse_SetNormal(PlayState* play, Player* player); +void Horse_SetCutsceneMount(PlayState* play, Player* player); +void Horse_InitForScene(PlayState* play, Player* player); +void Actor_RotateToPoint(Actor* actor, Vec3f* target, s16 speed); s32 Jpeg_Decode(void* data, void* zbuffer, void* workBuff, u32 workSize); void KaleidoSetup_Update(PlayState* play); void KaleidoSetup_Init(PlayState* play); diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index d8263f5de..4575d9644 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -1467,7 +1467,7 @@ s32 func_8002DEEC(Player* player) { } void func_8002DF18(PlayState* play, Player* player) { - func_8006DC68(play, player); + Horse_InitForScene(play, player); } s32 func_8002DF38(PlayState* play, Actor* actor, u8 csAction) { diff --git a/soh/src/code/z_horse.c b/soh/src/code/z_horse.c index ef4b7ec50..3ec182b7b 100644 --- a/soh/src/code/z_horse.c +++ b/soh/src/code/z_horse.c @@ -4,7 +4,9 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" -s32 func_8006CFC0(s32 scene) { +// Checks whether the current scene is one of the five “horse-compatible” +// outdoor maps (field, lake, two Gerudo areas, ranch). +s32 Horse_IsValidScene(s32 scene) { s32 validScenes[] = { SCENE_HYRULE_FIELD, SCENE_LAKE_HYLIA, SCENE_GERUDO_VALLEY, SCENE_GERUDOS_FORTRESS, SCENE_LON_LON_RANCH }; s32 i; @@ -18,7 +20,9 @@ s32 func_8006CFC0(s32 scene) { return 0; } -void func_8006D074(PlayState* play) { +// Hard-codes Epona’s default spawn information (Hyrule Field near the entrance +// to Gerudo Valley) +void Horse_SetDefaultSpawn(PlayState* play) { gSaveContext.horseData.scene = SCENE_HYRULE_FIELD; gSaveContext.horseData.pos.x = -1840; gSaveContext.horseData.pos.y = 72; @@ -26,7 +30,10 @@ void func_8006D074(PlayState* play) { gSaveContext.horseData.angle = -27353; } -void func_8006D0AC(PlayState* play) { +// Only when the save already says “Lake Hylia”, overwrite the coords to the +// proper Lake Hylia shoreline start point. A one-off “oh, you’re at Lake, let me +// correct the numbers” fixer. +void Horse_PatchLakeHyliaSpawn(PlayState* play) { if (gSaveContext.horseData.scene == SCENE_LAKE_HYLIA) { gSaveContext.horseData.scene = SCENE_LAKE_HYLIA; gSaveContext.horseData.pos.x = -2065; @@ -43,7 +50,9 @@ typedef struct { /* 0x0A */ s16 type; } HorseSpawn; -void func_8006D0EC(PlayState* play, Player* player) { +// Decides whether to actually drop a horse actor into the world or instantly +// mount Link on one. +void Horse_SetNormal(PlayState* play, Player* player) { s32 i; HorseSpawn horseSpawns[] = { { SCENE_HYRULE_FIELD, -460, 100, 6640, 0, 2 }, { SCENE_LAKE_HYLIA, -1929, -1025, 768, 0, 2 }, @@ -88,7 +97,7 @@ void func_8006D0EC(PlayState* play, Player* player) { osSyncPrintf("馬存在によるセット %d %d %d\n", gSaveContext.horseData.scene, Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED), DREG(1)); - if (func_8006CFC0(gSaveContext.horseData.scene)) { + if (Horse_IsValidScene(gSaveContext.horseData.scene)) { Actor* horseActor = Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, gSaveContext.horseData.pos.x, gSaveContext.horseData.pos.y, gSaveContext.horseData.pos.z, 0, gSaveContext.horseData.angle, 0, 1, true); @@ -101,7 +110,7 @@ void func_8006D0EC(PlayState* play, Player* player) { // "Horse_SetNormal():%d set spot is no good." osSyncPrintf("Horse_SetNormal():%d セットスポットまずいです。\n", gSaveContext.horseData.scene); osSyncPrintf(VT_RST); - func_8006D074(play); + Horse_SetDefaultSpawn(play); } } else if ((play->sceneNum == SCENE_LON_LON_RANCH) && !Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED) && (DREG(1) == 0)) { @@ -137,7 +146,10 @@ typedef struct { /* 0x10 */ s16 type; } struct_8011F9B8; -void func_8006D684(PlayState* play, Player* player) { +// Handles “special” scripted mounts: field reload points, Lon Lon race, Gerudo +// Fortress archery, etc. It mounts Link, positions the camera, or spawns +// passive horses depending on the cutscene index in that lookup table. +void Horse_SetCutsceneMount(PlayState* play, Player* player) { s32 pad; s32 i; Vec3s spawnPos; @@ -248,17 +260,19 @@ void func_8006D684(PlayState* play, Player* player) { } } -void func_8006DC68(PlayState* play, Player* player) { +// Top-level dispatcher for adult-Link scenes. Validates the saved spawn, then +// calls either Horse_SetCutsceneMount or Horse_SetNormal as appropriate. +void Horse_InitForScene(PlayState* play, Player* player) { if (LINK_IS_ADULT) { - if (!func_8006CFC0(gSaveContext.horseData.scene)) { + if (!Horse_IsValidScene(gSaveContext.horseData.scene)) { osSyncPrintf(VT_COL(RED, WHITE)); // "Horse_Set_Check():%d set spot is no good." osSyncPrintf("Horse_Set_Check():%d セットスポットまずいです。\n", gSaveContext.horseData.scene); osSyncPrintf(VT_RST); - func_8006D074(play); + Horse_SetDefaultSpawn(play); } - if (func_8006CFC0(play->sceneNum)) { + if (Horse_IsValidScene(play->sceneNum)) { if ((gSaveContext.sceneSetupIndex > 3) || ((gSaveContext.entranceIndex == ENTR_HYRULE_FIELD_11 || gSaveContext.entranceIndex == ENTR_HYRULE_FIELD_12 || @@ -267,15 +281,17 @@ void func_8006DC68(PlayState* play, Player* player) { (gSaveContext.respawnFlag == 0)) || ((play->sceneNum == SCENE_LON_LON_RANCH) && ((gSaveContext.eventInf[0] & 0xF) == 6) && !Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED) && (DREG(1) == 0))) { - func_8006D684(play, player); + Horse_SetCutsceneMount(play, player); } else { - func_8006D0EC(play, player); + Horse_SetNormal(play, player); } } } } -void func_8006DD9C(Actor* actor, Vec3f* arg1, s16 arg2) { +// Generic helper: smoothly yaw an actor toward a target point, clamping the +// turn speed. It’s used by horse AI but isn’t horse-specific. +void Actor_RotateToPoint(Actor* actor, Vec3f* arg1, s16 arg2) { s16 x = Math_Vec3f_Yaw(&actor->world.pos, arg1) - actor->world.rot.y; if (x > arg2) { diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 0fc923070..ea78a693f 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1913,7 +1913,7 @@ u8 Item_Give(PlayState* play, u8 item) { osSyncPrintf(VT_RST); if (item == ITEM_MEDALLION_WATER) { - func_8006D0AC(play); + Horse_PatchLakeHyliaSpawn(play); } return Return_Item(item, MOD_NONE, ITEM_NONE); diff --git a/soh/src/overlays/actors/ovl_En_Ge1/z_en_ge1.c b/soh/src/overlays/actors/ovl_En_Ge1/z_en_ge1.c index eadd847b5..c43aab1da 100644 --- a/soh/src/overlays/actors/ovl_En_Ge1/z_en_ge1.c +++ b/soh/src/overlays/actors/ovl_En_Ge1/z_en_ge1.c @@ -235,7 +235,7 @@ void EnGe1_KickPlayer(EnGe1* this, PlayState* play) { if (this->cutsceneTimer > 0) { this->cutsceneTimer--; } else { - func_8006D074(play); + Horse_SetDefaultSpawn(play); if ((INV_CONTENT(ITEM_HOOKSHOT) == ITEM_NONE) || (INV_CONTENT(ITEM_LONGSHOT) == ITEM_NONE)) { play->nextEntranceIndex = ENTR_GERUDO_VALLEY_1; diff --git a/soh/src/overlays/actors/ovl_En_Ge2/z_en_ge2.c b/soh/src/overlays/actors/ovl_En_Ge2/z_en_ge2.c index 776a241b1..94550b2b9 100644 --- a/soh/src/overlays/actors/ovl_En_Ge2/z_en_ge2.c +++ b/soh/src/overlays/actors/ovl_En_Ge2/z_en_ge2.c @@ -244,7 +244,7 @@ void EnGe2_CaptureClose(EnGe2* this, PlayState* play) { if (this->timer > 0) { this->timer--; } else { - func_8006D074(play); + Horse_SetDefaultSpawn(play); if ((INV_CONTENT(ITEM_HOOKSHOT) == ITEM_NONE) || (INV_CONTENT(ITEM_LONGSHOT) == ITEM_NONE)) { play->nextEntranceIndex = ENTR_GERUDO_VALLEY_1; @@ -274,7 +274,7 @@ void EnGe2_CaptureCharge(EnGe2* this, PlayState* play) { if (this->timer > 0) { this->timer--; } else { - func_8006D074(play); + Horse_SetDefaultSpawn(play); if ((INV_CONTENT(ITEM_HOOKSHOT) == ITEM_NONE) || (INV_CONTENT(ITEM_LONGSHOT) == ITEM_NONE)) { play->nextEntranceIndex = ENTR_GERUDO_VALLEY_1; diff --git a/soh/src/overlays/actors/ovl_En_Horse/z_en_horse.c b/soh/src/overlays/actors/ovl_En_Horse/z_en_horse.c index c4d46035d..eb199e125 100644 --- a/soh/src/overlays/actors/ovl_En_Horse/z_en_horse.c +++ b/soh/src/overlays/actors/ovl_En_Horse/z_en_horse.c @@ -532,7 +532,7 @@ void EnHorse_RaceWaypointPos(RaceWaypoint* waypoints, s32 idx, Vec3f* pos) { } void EnHorse_RotateToPoint(EnHorse* this, PlayState* play, Vec3f* pos, s16 turnAmount) { - func_8006DD9C(&this->actor, pos, turnAmount); + Actor_RotateToPoint(&this->actor, pos, turnAmount); } void EnHorse_UpdateIngoRaceInfo(EnHorse* this, PlayState* play, RaceInfo* raceInfo) { diff --git a/soh/src/overlays/actors/ovl_En_Horse_Link_Child/z_en_horse_link_child.c b/soh/src/overlays/actors/ovl_En_Horse_Link_Child/z_en_horse_link_child.c index 630156e84..f65081471 100644 --- a/soh/src/overlays/actors/ovl_En_Horse_Link_Child/z_en_horse_link_child.c +++ b/soh/src/overlays/actors/ovl_En_Horse_Link_Child/z_en_horse_link_child.c @@ -453,7 +453,7 @@ void func_80A6A5A4(EnHorseLinkChild* this, PlayState* play) { yawDiff = Actor_WorldYawTowardActor(&this->actor, &GET_PLAYER(play)->actor) - this->actor.world.rot.y; // 0.7071 = cos(pi/4) if ((Math_CosS(yawDiff) < 0.7071f) && (this->animationIdx == 2)) { - func_8006DD9C(&this->actor, &GET_PLAYER(play)->actor.world.pos, 300); + Actor_RotateToPoint(&this->actor, &GET_PLAYER(play)->actor.world.pos, 300); } if (SkelAnime_Update(&this->skin.skelAnime)) { @@ -490,9 +490,9 @@ void func_80A6A7D0(EnHorseLinkChild* this, PlayState* play) { if ((this->animationIdx == 4) || (this->animationIdx == 3) || (this->animationIdx == 2)) { if (!this->unk_1E8) { - func_8006DD9C(&this->actor, &player->actor.world.pos, 300); + Actor_RotateToPoint(&this->actor, &player->actor.world.pos, 300); } else { - func_8006DD9C(&this->actor, &this->actor.home.pos, 300); + Actor_RotateToPoint(&this->actor, &this->actor.home.pos, 300); } }