diff --git a/soh/soh/GameMenuBar.cpp b/soh/soh/GameMenuBar.cpp index 186fad2ea..0de6cfc7e 100644 --- a/soh/soh/GameMenuBar.cpp +++ b/soh/soh/GameMenuBar.cpp @@ -639,6 +639,8 @@ namespace GameMenuBar { UIWidgets::Tooltip("Injects item counts in pickup messages, like golden skulltula tokens and heart pieces"); UIWidgets::PaddedEnhancementCheckbox("Pull grave during the day", "gDayGravePull", true, false); UIWidgets::Tooltip("Allows graves to be pulled when child during the day"); + UIWidgets::PaddedEnhancementCheckbox("Dogs follow you everywhere", "gDogFollowsEverywhere", true, false); + UIWidgets::Tooltip("Allows dogs to follow you anywhere you go, even if you leave the market"); // Blue Fire Arrows bool forceEnableBlueFireArrows = gSaveContext.n64ddFlag && diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index b1eef677a..ee5eb8b95 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -1334,6 +1334,7 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); }); SaveManager::Instance->LoadData("isMasterQuest", gSaveContext.isMasterQuest); + SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams); } void SaveManager::SaveBase() { @@ -1509,6 +1510,7 @@ void SaveManager::SaveBase() { SaveManager::Instance->SaveData("", gSaveContext.randomizerInf[i]); }); SaveManager::Instance->SaveData("isMasterQuest", gSaveContext.isMasterQuest); + SaveManager::Instance->SaveData("dogParams", gSaveContext.dogParams); } void SaveManager::SaveArray(const std::string& name, const size_t size, SaveArrayFunc func) { diff --git a/soh/src/overlays/actors/ovl_En_Dog/z_en_dog.c b/soh/src/overlays/actors/ovl_En_Dog/z_en_dog.c index 130cdc32e..e2e63fc03 100644 --- a/soh/src/overlays/actors/ovl_En_Dog/z_en_dog.c +++ b/soh/src/overlays/actors/ovl_En_Dog/z_en_dog.c @@ -371,12 +371,37 @@ void EnDog_FollowPlayer(EnDog* this, PlayState* play) { return; } - if (this->actor.xzDistToPlayer > 400.0f) { - if (this->nextBehavior != DOG_SIT && this->nextBehavior != DOG_SIT_2) { - this->nextBehavior = DOG_BOW; + if (CVarGetInteger("gDogFollowsEverywhere", 0)) { + // If the dog is too far away it's usually because they are stuck in a hole or on a different floor, this gives them a push + if (this->actor.xyzDistToPlayerSq > 250000.0f) { + Player* player = GET_PLAYER(play); + if (PlayerGrounded(player)) this->actor.world.pos.y = player->actor.world.pos.y; + } + + // If doggo is in the water make sure it's floating + if (this->actor.bgCheckFlags & 0x20) { + this->actor.gravity = 0.0f; + if (this->actor.yDistToWater > 11.0f) { + this->actor.world.pos.y += 2.0f; + } else if (this->actor.yDistToWater < 8.0f) { + this->actor.world.pos.y -= 2.0f; + } + } else { + this->actor.gravity = -1.0f; + } + } + + if (this->actor.xzDistToPlayer > 400.0f) { + if (CVarGetInteger("gDogFollowsEverywhere", 0)) { + // Instead of stopping following when the dog gets too far, just speed them up. + speed = this->actor.xzDistToPlayer / 25.0f; + } else { + if (this->nextBehavior != DOG_SIT && this->nextBehavior != DOG_SIT_2) { + this->nextBehavior = DOG_BOW; + } + gSaveContext.dogParams = 0; + speed = 0.0f; } - gSaveContext.dogParams = 0; - speed = 0.0f; } else if (this->actor.xzDistToPlayer > 100.0f) { this->nextBehavior = DOG_RUN; speed = 4.0f; @@ -392,7 +417,7 @@ void EnDog_FollowPlayer(EnDog* this, PlayState* play) { Math_ApproachF(&this->actor.speedXZ, speed, 0.6f, 1.0f); - if (!(this->actor.xzDistToPlayer > 400.0f)) { + if (!(this->actor.xzDistToPlayer > 400.0f) || CVarGetInteger("gDogFollowsEverywhere", 0)) { Math_SmoothStepToS(&this->actor.world.rot.y, this->actor.yawTowardsPlayer, 10, 1000, 1); this->actor.shape.rot = this->actor.world.rot; } diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index aef758377..3712d359f 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -10934,7 +10934,8 @@ void Player_Update(Actor* thisx, PlayState* play) { if (func_8084FCAC(this, play)) { if (gSaveContext.dogParams < 0) { - if (Object_GetIndex(&play->objectCtx, OBJECT_DOG) < 0) { + // Disable object dependency to prevent losing dog in scenes other than market + if (Object_GetIndex(&play->objectCtx, OBJECT_DOG) < 0 && !CVarGetInteger("gDogFollowsEverywhere", 0)) { gSaveContext.dogParams = 0; } else { gSaveContext.dogParams &= 0x7FFF; @@ -10944,7 +10945,8 @@ void Player_Update(Actor* thisx, PlayState* play) { dog = Actor_Spawn(&play->actorCtx, play, ACTOR_EN_DOG, sDogSpawnPos.x, sDogSpawnPos.y, sDogSpawnPos.z, 0, this->actor.shape.rot.y, 0, dogParams | 0x8000, true); if (dog != NULL) { - dog->room = 0; + // Room -1 allows actor to cross between rooms, similar to Navi + dog->room = CVarGetInteger("gDogFollowsEverywhere", 0) ? -1 : 0; } } } diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 397a1a2c6..877da8daf 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -2088,7 +2088,9 @@ void FileChoose_LoadGame(GameState* thisx) { gSaveContext.seqId = (u8)NA_BGM_DISABLED; gSaveContext.natureAmbienceId = 0xFF; gSaveContext.showTitleCard = true; - gSaveContext.dogParams = 0; + if (!CVarGetInteger("gDogFollowsEverywhere", 0)) { + gSaveContext.dogParams = 0; + } gSaveContext.timer1State = 0; gSaveContext.timer2State = 0; gSaveContext.eventInf[0] = 0;