setting to skip bottling big poes

empty bottle still required to collect

avoids logic needing to work around player soft locking by filling bottles without poe collector access
This commit is contained in:
Demur Rumed 2025-03-29 20:40:01 +00:00
parent 824c203b97
commit b8c7d26f6e
9 changed files with 67 additions and 17 deletions

View file

@ -228,6 +228,14 @@ typedef enum {
// - `*Actor` (interactRangeActor)
VB_BOTTLE_ACTOR,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*EnPoField`
VB_BOTTLE_BIG_POE,
// #### `result`
// ```c
// ((this->actor.params == DNS_TYPE_HEART_PIECE) && (Flags_GetItemGetInf(ITEMGETINF_DEKU_SCRUB_HEART_PIECE))) ||
@ -1663,6 +1671,14 @@ typedef enum {
// - `*EnRu1`
VB_RUTO_WANT_TO_BE_TOSSED_TO_SAPPHIRE,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*EnGb`
VB_SELL_POES_TO_POE_COLLECTOR,
// #### `result`
// ```c
// true

View file

@ -602,7 +602,7 @@ void ValidateEntrances(bool checkPoeCollectorAccess, bool checkOtherEntranceAcce
ResetLogic(ctx, gals, !checkOtherEntranceAccess);
ctx->allLocationsReachable = false;
if (checkPoeCollectorAccess) {
if (checkPoeCollectorAccess && !ctx->GetOption(RSK_SKIP_BOTTLING_BIG_POES)) {
logic->AreCheckingBigPoes = true;
}

View file

@ -29,6 +29,7 @@ extern "C" {
#include "src/overlays/actors/ovl_En_Shopnuts/z_en_shopnuts.h"
#include "src/overlays/actors/ovl_En_Dns/z_en_dns.h"
#include "src/overlays/actors/ovl_En_Gb/z_en_gb.h"
#include "src/overlays/actors/ovl_En_Po_Field/z_en_po_field.h"
#include "src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.h"
#include "src/overlays/actors/ovl_En_Ko/z_en_ko.h"
#include "src/overlays/actors/ovl_En_Mk/z_en_mk.h"
@ -1084,6 +1085,30 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
*should = false;
break;
}
case VB_BOTTLE_BIG_POE: {
if (RAND_GET_OPTION(RSK_SKIP_BOTTLING_BIG_POES)) {
EnPoField* enPoe = va_arg(args, EnPoField*);
enPoe->actor.textId = 0x508F;
Flags_SetSwitch(gPlayState, enPoe->actor.params & 0xFF);
HIGH_SCORE(HS_POE_POINTS) += 100;
if (HIGH_SCORE(HS_POE_POINTS) > 1100) {
HIGH_SCORE(HS_POE_POINTS) = 1100;
}
*should = false;
}
break;
}
case VB_SELL_POES_TO_POE_COLLECTOR: {
EnGb* enGb = va_arg(args, EnGb*);
if (RAND_GET_OPTION(RSK_SKIP_BOTTLING_BIG_POES) && !Flags_GetRandomizerInf(RAND_INF_10_BIG_POES) &&
HIGH_SCORE(HS_POE_POINTS) >= 1000) {
enGb->textId = 0x70F8;
Message_ContinueTextbox(gPlayState, enGb->textId);
enGb->actionFunc = func_80A2FB40;
*should = false;
}
break;
}
case VB_GIVE_ITEM_FROM_POE_COLLECTOR: {
EnGb* enGb = va_arg(args, EnGb*);
if (!Flags_GetRandomizerInf(RAND_INF_10_BIG_POES)) {

View file

@ -595,6 +595,8 @@ void Settings::CreateOptionDescriptions() {
"rewards on slider does not change.";
mOptionDescriptions[RSK_CUCCO_COUNT] = "The amount of cuccos needed to claim the reward from Anju the Cucco Lady.";
mOptionDescriptions[RSK_BIG_POE_COUNT] = "The Poe collector will give a reward for turning in this many Big Poes.";
mOptionDescriptions[RSK_SKIP_BOTTLING_BIG_POES] =
"Collecting big poes will not fill a bottle, but still require a bottle.";
mOptionDescriptions[RSK_SKIP_CHILD_STEALTH] =
"The crawlspace into Hyrule Castle goes straight to Zelda, skipping the guards.";
mOptionDescriptions[RSK_SKIP_CHILD_ZELDA] =

View file

@ -5795,6 +5795,7 @@ typedef enum {
RSK_SHUFFLE_CHEST_MINIGAME,
RSK_CUCCO_COUNT,
RSK_BIG_POE_COUNT,
RSK_SKIP_BOTTLING_BIG_POES,
RSK_SKIP_EPONA_RACE,
RSK_COMPLETE_MASK_QUEST,
RSK_SKIP_SCARECROWS_SONG,

View file

@ -269,6 +269,7 @@ void Settings::CreateOptions() {
OPT_BOOL(RSK_SKIP_EPONA_RACE, "Skip Epona Race", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipEponaRace"), mOptionDescriptions[RSK_SKIP_EPONA_RACE], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP);
OPT_BOOL(RSK_SKIP_SCARECROWS_SONG, "Skip Scarecrow's Song", CVAR_RANDOMIZER_SETTING("SkipScarecrowsSong"), mOptionDescriptions[RSK_SKIP_SCARECROWS_SONG]);
OPT_U8(RSK_BIG_POE_COUNT, "Big Poe Target Count", {NumOpts(1, 10)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("BigPoeTargetCount"), mOptionDescriptions[RSK_BIG_POE_COUNT], WidgetType::Slider, 9);
OPT_BOOL(RSK_SKIP_BOTTLING_BIG_POES, "Skip Bottling Big Poes",CVAR_RANDOMIZER_SETTING("SkipBottlingBigPoes"), mOptionDescriptions[RSK_SKIP_BOTTLING_BIG_POES]);
OPT_U8(RSK_CUCCO_COUNT, "Cuccos to return", {NumOpts(0, 7)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("CuccosToReturn"), mOptionDescriptions[RSK_CUCCO_COUNT], WidgetType::Slider, 7);
OPT_BOOL(RSK_COMPLETE_MASK_QUEST, "Complete Mask Quest", CVAR_RANDOMIZER_SETTING("CompleteMaskQuest"), mOptionDescriptions[RSK_COMPLETE_MASK_QUEST]);
OPT_U8(RSK_GOSSIP_STONE_HINTS, "Gossip Stone Hints", {"No Hints", "Need Nothing", "Mask of Truth", "Stone of Agony"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GossipStoneHints"), mOptionDescriptions[RSK_GOSSIP_STONE_HINTS], WidgetType::Combobox, RO_GOSSIP_STONES_NEED_NOTHING, false, IMFLAG_NONE);
@ -1311,8 +1312,9 @@ void Settings::CreateOptions() {
WidgetContainerType::TABLE);
mOptionGroups[RSG_TIMESAVERS_IMGUI] = OptionGroup::SubGroup(
"Timesavers",
{ &mOptions[RSK_CUCCO_COUNT], &mOptions[RSK_BIG_POE_COUNT], &mOptions[RSK_SKIP_CHILD_ZELDA],
&mOptions[RSK_SKIP_EPONA_RACE], &mOptions[RSK_COMPLETE_MASK_QUEST], &mOptions[RSK_SKIP_SCARECROWS_SONG] },
{ &mOptions[RSK_CUCCO_COUNT], &mOptions[RSK_BIG_POE_COUNT], &mOptions[RSK_SKIP_BOTTLING_BIG_POES],
&mOptions[RSK_SKIP_CHILD_ZELDA], &mOptions[RSK_SKIP_EPONA_RACE], &mOptions[RSK_COMPLETE_MASK_QUEST],
&mOptions[RSK_SKIP_SCARECROWS_SONG] },
WidgetContainerType::COLUMN);
mOptionGroups[RSG_ITEM_POOL_HINTS_IMGUI] = OptionGroup::SubGroup("",
{
@ -1577,6 +1579,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SKIP_EPONA_RACE],
&mOptions[RSK_SKIP_SCARECROWS_SONG],
&mOptions[RSK_BIG_POE_COUNT],
&mOptions[RSK_SKIP_BOTTLING_BIG_POES],
&mOptions[RSK_CUCCO_COUNT],
&mOptions[RSK_COMPLETE_MASK_QUEST],
});

View file

@ -288,19 +288,21 @@ void func_80A2F83C(EnGb* this, PlayState* play) {
}
}
if (Actor_ProcessTalkRequest(&this->dyna.actor, play)) {
switch (func_8002F368(play)) {
case EXCH_ITEM_NONE:
func_80A2F180(this);
this->actionFunc = func_80A2F94C;
break;
case EXCH_ITEM_POE:
player->actor.textId = 0x70F6;
this->actionFunc = func_80A2F9C0;
break;
case EXCH_ITEM_BIG_POE:
player->actor.textId = 0x70F7;
this->actionFunc = func_80A2FA50;
break;
if (GameInteractor_Should(VB_SELL_POES_TO_POE_COLLECTOR, true, this)) {
switch (func_8002F368(play)) {
case EXCH_ITEM_NONE:
func_80A2F180(this);
this->actionFunc = func_80A2F94C;
break;
case EXCH_ITEM_POE:
player->actor.textId = 0x70F6;
this->actionFunc = func_80A2F9C0;
break;
case EXCH_ITEM_BIG_POE:
player->actor.textId = 0x70F7;
this->actionFunc = func_80A2FA50;
break;
}
}
return;
}

View file

@ -47,6 +47,7 @@ typedef struct EnGb {
/* 0x0388 */ EnGbCagedSoul cagedSouls[4];
} EnGb; // size = 0x0438
void func_80A2FB40(EnGb* actor, PlayState* play);
void func_80A2FC0C(EnGb* actor, PlayState* play);
#endif

View file

@ -712,7 +712,7 @@ void EnPoField_SoulInteract(EnPoField* this, PlayState* play) {
if (this->actor.params == 0) {
Item_Give(play, ITEM_POE);
this->actor.textId = 0x5008;
} else {
} else if (GameInteractor_Should(VB_BOTTLE_BIG_POE, true, this)) {
this->actor.textId = 0x508F;
Item_Give(play, ITEM_BIG_POE);
Flags_SetSwitch(play, sEnPoFieldSpawnSwitchFlags[this->spawnFlagIndex]);