summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Dubé <serprex@users.noreply.github.com>2025-12-31 01:27:37 +0000
committerGitHub <noreply@github.com>2025-12-31 01:27:37 +0000
commitd41273f34be3acee2f4d6046ad885b9dbc3e8ae6 (patch)
treebfc5c7ff595af53a8e5b6db57288df16db497938
parentc688923272f875b20183a3e6bee3429e04f008cc (diff)
Shuffle Bean Souls (#5833)
-rw-r--r--soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp2
-rw-r--r--soh/soh/Enhancements/randomizer/3drando/item_pool.cpp22
-rw-r--r--soh/soh/Enhancements/randomizer/draw.cpp12
-rw-r--r--soh/soh/Enhancements/randomizer/draw.h1
-rw-r--r--soh/soh/Enhancements/randomizer/hook_handlers.cpp68
-rw-r--r--soh/soh/Enhancements/randomizer/item_list.cpp21
-rw-r--r--soh/soh/Enhancements/randomizer/location_access.cpp43
-rw-r--r--soh/soh/Enhancements/randomizer/location_access.h4
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_crater.cpp16
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_trail.cpp16
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/overworld/desert_colossus.cpp12
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_valley.cpp12
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp12
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp24
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp14
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/overworld/lost_woods.cpp24
-rw-r--r--soh/soh/Enhancements/randomizer/location_access/overworld/zoras_river.cpp8
-rw-r--r--soh/soh/Enhancements/randomizer/logic.cpp59
-rw-r--r--soh/soh/Enhancements/randomizer/logic.h2
-rw-r--r--soh/soh/Enhancements/randomizer/option_descriptions.cpp4
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer.cpp45
-rw-r--r--soh/soh/Enhancements/randomizer/randomizerTypes.h15
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer_inf.h11
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp120
-rw-r--r--soh/soh/Enhancements/randomizer/savefile.cpp35
-rw-r--r--soh/soh/Enhancements/randomizer/settings.cpp10
-rw-r--r--soh/soh/OTRGlobals.cpp18
27 files changed, 523 insertions, 107 deletions
diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp
index c74c0ff23..4962aeac2 100644
--- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp
@@ -1964,6 +1964,8 @@ void StaticData::HintTable_Init_Item() {
CustomMessage("a gold fragment", /*german*/"ein Goldfragment", /*french*/"un fragment d'or")});
// /*spanish*/un fragmento dorado
+ hintTextTable[RHT_BEAN_SOUL] = HintText(CustomMessage("a bean soul", /*german*/"eine bohnenseele", /*french*/"une âme de haricot"));
+
hintTextTable[RHT_GOHMA_SOUL] = HintText(CustomMessage("the soul of Gohma", /*german*/"Gohmas Seele", /*french*/"l'Âme de Gohma"),
{
CustomMessage("something webbed", /*german*/"etwas Verwobenes", /*french*/"un truc entoilé")
diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp
index 8dc10b94f..e9260e02f 100644
--- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp
@@ -662,15 +662,16 @@ void GenerateItemPool() {
}
}
- if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_BEANS_ONLY) ||
- ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL)) {
+ // if beans unshuffled, put on bean guy, otherwise if not starting with beans, add to pool
+ if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).IsNot(RO_SHUFFLE_MERCHANTS_BEANS_ONLY) &&
+ ctx->GetOption(RSK_SHUFFLE_MERCHANTS).IsNot(RO_SHUFFLE_MERCHANTS_ALL)) {
+ ctx->PlaceItemInLocation(RC_ZR_MAGIC_BEAN_SALESMAN, RG_MAGIC_BEAN, false, true);
+ } else if (!ctx->GetOption(RSK_STARTING_BEANS)) {
AddItemToMainPool(RG_MAGIC_BEAN_PACK);
if (ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_PLENTIFUL)) {
AddItemToPool(PendingJunkPool, RG_MAGIC_BEAN_PACK);
}
ctx->possibleIceTrapModels.push_back(RG_MAGIC_BEAN_PACK);
- } else {
- ctx->PlaceItemInLocation(RC_ZR_MAGIC_BEAN_SALESMAN, RG_MAGIC_BEAN, false, true);
}
if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS) ||
@@ -752,6 +753,19 @@ void GenerateItemPool() {
ctx->PlaceItemInLocation(RC_KAK_100_GOLD_SKULLTULA_REWARD, RG_HUGE_RUPEE, false, true);
}
+ if (ctx->GetOption(RSK_SHUFFLE_BEAN_SOULS)) {
+ AddItemToMainPool(RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL);
+ AddItemToMainPool(RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL);
+ AddItemToMainPool(RG_DESERT_COLOSSUS_BEAN_SOUL);
+ AddItemToMainPool(RG_GERUDO_VALLEY_BEAN_SOUL);
+ AddItemToMainPool(RG_GRAVEYARD_BEAN_SOUL);
+ AddItemToMainPool(RG_KOKIRI_FOREST_BEAN_SOUL);
+ AddItemToMainPool(RG_LAKE_HYLIA_BEAN_SOUL);
+ AddItemToMainPool(RG_LOST_WOODS_BRIDGE_BEAN_SOUL);
+ AddItemToMainPool(RG_LOST_WOODS_BEAN_SOUL);
+ AddItemToMainPool(RG_ZORAS_RIVER_BEAN_SOUL);
+ }
+
if (ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS)) {
AddItemToMainPool(RG_GOHMA_SOUL);
AddItemToMainPool(RG_KING_DODONGO_SOUL);
diff --git a/soh/soh/Enhancements/randomizer/draw.cpp b/soh/soh/Enhancements/randomizer/draw.cpp
index 7d266d78b..7774125bc 100644
--- a/soh/soh/Enhancements/randomizer/draw.cpp
+++ b/soh/soh/Enhancements/randomizer/draw.cpp
@@ -28,6 +28,7 @@ extern "C" {
#include "objects/object_bv/object_bv.h"
#include "objects/object_gnd/object_gnd.h"
#include "objects/object_fd/object_fd.h"
+#include "objects/object_mamenoki/object_mamenoki.h"
#include "objects/object_mo/object_mo.h"
#include "objects/object_sst/object_sst.h"
#include "overlays/actors/ovl_Boss_Goma/z_boss_goma.h"
@@ -929,6 +930,17 @@ extern "C" void DrawGanon(PlayState* play) {
CLOSE_DISPS(play->state.gfxCtx);
}
+extern "C" void Randomizer_DrawBeanSprout(PlayState* play, GetItemEntry* getItemEntry) {
+ OPEN_DISPS(play->state.gfxCtx);
+
+ Gfx_SetupDL_25Opa(play->state.gfxCtx);
+ Matrix_Scale(0.3f, 0.3f, 0.3f, MTXMODE_APPLY);
+ gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_MODELVIEW | G_MTX_LOAD);
+ gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gMagicBeanSeedlingDL);
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
extern "C" void Randomizer_DrawBossSoul(PlayState* play, GetItemEntry* getItemEntry) {
s16 slot;
if (getItemEntry->getItemId != RG_ICE_TRAP) {
diff --git a/soh/soh/Enhancements/randomizer/draw.h b/soh/soh/Enhancements/randomizer/draw.h
index 8483a7bf9..3830fdceb 100644
--- a/soh/soh/Enhancements/randomizer/draw.h
+++ b/soh/soh/Enhancements/randomizer/draw.h
@@ -14,6 +14,7 @@ void Randomizer_DrawMap(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawCompass(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawKeyRing(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawBossKey(PlayState* play, GetItemEntry* getItemEntry);
+void Randomizer_DrawBeanSprout(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawBossSoul(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawDoubleDefense(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawMasterSword(PlayState* play, GetItemEntry* getItemEntry);
diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp
index faedf2fd7..7b4cd7645 100644
--- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp
+++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp
@@ -55,11 +55,13 @@ extern "C" {
#include "src/overlays/actors/ovl_En_Xc/z_en_xc.h"
#include "src/overlays/actors/ovl_Fishing/z_fishing.h"
#include "src/overlays/actors/ovl_En_Mk/z_en_mk.h"
+#include "src/overlays/actors/ovl_Obj_Bean/z_obj_bean.h"
#include "draw.h"
extern SaveContext gSaveContext;
extern PlayState* gPlayState;
extern void func_8084DFAC(PlayState* play, Player* player);
+extern void func_80B8FE00(ObjBean*); // trigger planting
extern void Player_SetupActionPreserveAnimMovement(PlayState* play, Player* player, PlayerActionFunc actionFunc,
s32 flags);
extern s32 Player_SetupWaitForPutAway(PlayState* play, Player* player, AfterPutAwayFunc func);
@@ -933,6 +935,8 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
RAND_GET_OPTION(RSK_SHUFFLE_MERCHANTS) == RO_SHUFFLE_MERCHANTS_ALL) {
*should = gSaveContext.rupees >=
OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_ZR_MAGIC_BEAN_SALESMAN)->GetPrice();
+ } else if (RAND_GET_OPTION(RSK_SKIP_PLANTING_BEANS)) {
+ *should = gSaveContext.rupees >= 60;
}
break;
}
@@ -1268,6 +1272,27 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
Flags_SetRandomizerInf(RAND_INF_MERCHANTS_MAGIC_BEAN_SALESMAN);
enMs->actionFunc = (EnMsActionFunc)EnMs_Wait;
*should = false;
+ } else if (RAND_GET_OPTION(RSK_SKIP_PLANTING_BEANS)) {
+ Rupees_ChangeBy(-60);
+ Item_Give(NULL, ITEM_BEAN);
+ BEANS_BOUGHT = 10;
+ AMMO(ITEM_BEAN) = 0;
+ gSaveContext.sceneFlags[SCENE_DEATH_MOUNTAIN_CRATER].swch |= (1 << 3);
+ gSaveContext.sceneFlags[SCENE_DEATH_MOUNTAIN_TRAIL].swch |= (1 << 6);
+ gSaveContext.sceneFlags[SCENE_DESERT_COLOSSUS].swch |= (1 << 24);
+ gSaveContext.sceneFlags[SCENE_GERUDO_VALLEY].swch |= (1 << 3);
+ gSaveContext.sceneFlags[SCENE_GRAVEYARD].swch |= (1 << 3);
+ gSaveContext.sceneFlags[SCENE_KOKIRI_FOREST].swch |= (1 << 9);
+ gSaveContext.sceneFlags[SCENE_LAKE_HYLIA].swch |= (1 << 1);
+ gSaveContext.sceneFlags[SCENE_LOST_WOODS].swch |= (1 << 4) | (1 << 18);
+ gSaveContext.sceneFlags[SCENE_ZORAS_RIVER].swch |= (1 << 3);
+ ObjBean* bean = (ObjBean*)Actor_Find(&gPlayState->actorCtx, ACTOR_OBJ_BEAN, ACTORCAT_BG);
+ if (bean != nullptr) {
+ Flags_SetSwitch(gPlayState, bean->dyna.actor.params & 0x3F);
+ func_80B8FE00(bean);
+ }
+ enMs->actionFunc = (EnMsActionFunc)EnMs_Wait;
+ *should = false;
}
break;
}
@@ -2249,6 +2274,49 @@ void RandomizerOnActorInitHandler(void* actorRef) {
return;
}
+ if (RAND_GET_OPTION(RSK_SHUFFLE_BEAN_SOULS)) {
+ if (actor->id == ACTOR_OBJ_BEAN) {
+ RandomizerInf currentBeanSoulRandInf = RAND_INF_MAX;
+ switch (gPlayState->sceneNum) {
+ case SCENE_DEATH_MOUNTAIN_CRATER:
+ currentBeanSoulRandInf = RAND_INF_DEATH_MOUNTAIN_CRATER_BEAN_SOUL;
+ break;
+ case SCENE_DEATH_MOUNTAIN_TRAIL:
+ currentBeanSoulRandInf = RAND_INF_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL;
+ break;
+ case SCENE_DESERT_COLOSSUS:
+ currentBeanSoulRandInf = RAND_INF_DESERT_COLOSSUS_BEAN_SOUL;
+ break;
+ case SCENE_GERUDO_VALLEY:
+ currentBeanSoulRandInf = RAND_INF_GERUDO_VALLEY_BEAN_SOUL;
+ break;
+ case SCENE_GRAVEYARD:
+ currentBeanSoulRandInf = RAND_INF_GRAVEYARD_BEAN_SOUL;
+ break;
+ case SCENE_KOKIRI_FOREST:
+ currentBeanSoulRandInf = RAND_INF_KOKIRI_FOREST_BEAN_SOUL;
+ break;
+ case SCENE_LAKE_HYLIA:
+ currentBeanSoulRandInf = RAND_INF_LAKE_HYLIA_BEAN_SOUL;
+ break;
+ case SCENE_LOST_WOODS:
+ if ((actor->params & 0x3F) == 4) {
+ currentBeanSoulRandInf = RAND_INF_LOST_WOODS_BRIDGE_BEAN_SOUL;
+ } else {
+ currentBeanSoulRandInf = RAND_INF_LOST_WOODS_BEAN_SOUL;
+ }
+ break;
+ case SCENE_ZORAS_RIVER:
+ currentBeanSoulRandInf = RAND_INF_ZORAS_RIVER_BEAN_SOUL;
+ break;
+ }
+ if (currentBeanSoulRandInf != RAND_INF_MAX && !Flags_GetRandomizerInf(currentBeanSoulRandInf)) {
+ Actor_Kill(actor);
+ return;
+ }
+ }
+ }
+
// If child is in the adult shooting gallery or adult in the child shooting gallery, then despawn the shooting
// gallery man
if (actor->id == ACTOR_EN_SYATEKI_MAN && RAND_GET_OPTION(RSK_SHUFFLE_INTERIOR_ENTRANCES) &&
diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp
index 861923312..10c2eea91 100644
--- a/soh/soh/Enhancements/randomizer/item_list.cpp
+++ b/soh/soh/Enhancements/randomizer/item_list.cpp
@@ -316,6 +316,27 @@ void Rando::StaticData::InitItemTable() {
itemTable[RG_BUY_RED_POTION_40] = Item(RG_BUY_RED_POTION_40, Text{ "Buy Red Potion [40]", "Acheter: Potion Rouge [40]", "Rotes Elixier kaufen [40]" }, ITEMTYPE_SHOP, GI_POTION_RED, false, LOGIC_NONE, RHT_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, OBJECT_GI_LIQUID, GID_POTION_RED, 0x43, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_JUNK, MOD_NONE, false, 40);
itemTable[RG_BUY_RED_POTION_50] = Item(RG_BUY_RED_POTION_50, Text{ "Buy Red Potion [50]", "Acheter: Potion Rouge [50]", "Rotes Elixier kaufen [50]" }, ITEMTYPE_SHOP, GI_POTION_RED, false, LOGIC_NONE, RHT_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, OBJECT_GI_LIQUID, GID_POTION_RED, 0x43, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_JUNK, MOD_NONE, false, 50);
// Misc.
+ itemTable[RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL] = Item(RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, Text{ "Death Mountain Crater Bean Soul" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_NONE, RHT_BEAN_SOUL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL].SetCustomDrawFunc(Randomizer_DrawBeanSprout);
+ itemTable[RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL] = Item(RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, Text{ "Death Mountain Trail Bean Soul" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_NONE, RHT_BEAN_SOUL, RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL].SetCustomDrawFunc(Randomizer_DrawBeanSprout);
+ itemTable[RG_DESERT_COLOSSUS_BEAN_SOUL] = Item(RG_DESERT_COLOSSUS_BEAN_SOUL, Text{ "Desert Colossus Bean Soul" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_NONE, RHT_BEAN_SOUL, RG_DESERT_COLOSSUS_BEAN_SOUL, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_DESERT_COLOSSUS_BEAN_SOUL].SetCustomDrawFunc(Randomizer_DrawBeanSprout);
+ itemTable[RG_GERUDO_VALLEY_BEAN_SOUL] = Item(RG_GERUDO_VALLEY_BEAN_SOUL, Text{ "Gerudo Valley Bean Soul" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_NONE, RHT_BEAN_SOUL, RG_GERUDO_VALLEY_BEAN_SOUL, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_GERUDO_VALLEY_BEAN_SOUL].SetCustomDrawFunc(Randomizer_DrawBeanSprout);
+ itemTable[RG_GRAVEYARD_BEAN_SOUL] = Item(RG_GRAVEYARD_BEAN_SOUL, Text{ "Graveyard Bean Soul" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_NONE, RHT_BEAN_SOUL, RG_GRAVEYARD_BEAN_SOUL, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_GRAVEYARD_BEAN_SOUL].SetCustomDrawFunc(Randomizer_DrawBeanSprout);
+ itemTable[RG_KOKIRI_FOREST_BEAN_SOUL] = Item(RG_KOKIRI_FOREST_BEAN_SOUL, Text{ "Kokiri Forest Bean Soul" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_NONE, RHT_BEAN_SOUL, RG_KOKIRI_FOREST_BEAN_SOUL, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_KOKIRI_FOREST_BEAN_SOUL].SetCustomDrawFunc(Randomizer_DrawBeanSprout);
+ itemTable[RG_LAKE_HYLIA_BEAN_SOUL] = Item(RG_LAKE_HYLIA_BEAN_SOUL, Text{ "Lake Hylia Bean Soul" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_NONE, RHT_BEAN_SOUL, RG_LAKE_HYLIA_BEAN_SOUL, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_LAKE_HYLIA_BEAN_SOUL].SetCustomDrawFunc(Randomizer_DrawBeanSprout);
+ itemTable[RG_LOST_WOODS_BRIDGE_BEAN_SOUL] = Item(RG_LOST_WOODS_BRIDGE_BEAN_SOUL, Text{ "Lost Woods Bridge Bean Soul" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_NONE, RHT_BEAN_SOUL, RG_LOST_WOODS_BRIDGE_BEAN_SOUL, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_LOST_WOODS_BRIDGE_BEAN_SOUL].SetCustomDrawFunc(Randomizer_DrawBeanSprout);
+ itemTable[RG_LOST_WOODS_BEAN_SOUL] = Item(RG_LOST_WOODS_BEAN_SOUL, Text{ "Lost Woods Bean Soul" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_NONE, RHT_BEAN_SOUL, RG_LOST_WOODS_BEAN_SOUL, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_LOST_WOODS_BEAN_SOUL].SetCustomDrawFunc(Randomizer_DrawBeanSprout);
+ itemTable[RG_ZORAS_RIVER_BEAN_SOUL] = Item(RG_ZORAS_RIVER_BEAN_SOUL, Text{ "Zora's River Bean Soul" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_NONE, RHT_BEAN_SOUL, RG_ZORAS_RIVER_BEAN_SOUL, OBJECT_GI_BEAN, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_ZORAS_RIVER_BEAN_SOUL].SetCustomDrawFunc(Randomizer_DrawBeanSprout);
+
itemTable[RG_GOHMA_SOUL] = Item(RG_GOHMA_SOUL, Text{ "Gohma's Soul", "Âme de Gohma", "Gohmas Seele" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_CAN_SUMMON_GOHMA, RHT_GOHMA_SOUL, RG_GOHMA_SOUL, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
itemTable[RG_GOHMA_SOUL].SetCustomDrawFunc(Randomizer_DrawBossSoul);
itemTable[RG_KING_DODONGO_SOUL] = Item(RG_KING_DODONGO_SOUL, Text{ "King Dodongo's Soul", "Âme du Roi Dodongo", "König Dodongos Seele" }, ITEMTYPE_ITEM, 0xE1, true, LOGIC_CAN_SUMMON_KINGDODONGO, RHT_KING_DODONGO_SOUL, RG_KING_DODONGO_SOUL, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp
index e3430c5a9..7cab9fdb7 100644
--- a/soh/soh/Enhancements/randomizer/location_access.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access.cpp
@@ -505,8 +505,11 @@ Rando::Entrance* Region::GetExit(RandomizerRegion exitToReturn) {
return nullptr;
}
-bool Region::CanPlantBeanCheck() const {
- return Rando::Context::GetInstance()->GetLogic()->GetAmmo(ITEM_BEAN) > 0 && BothAgesCheck();
+bool Region::CanPlantBeanCheck(RandomizerGet bean) const {
+ auto ctx = Rando::Context::GetInstance();
+ auto logic = ctx->GetLogic();
+ return logic->HasItem(bean) && logic->GetAmmo(ITEM_BEAN) > 0 &&
+ (ctx->GetOption(RSK_SKIP_PLANTING_BEANS) || BothAgesCheck());
}
bool Region::AllAccountedFor() const {
@@ -675,49 +678,55 @@ bool MQSpiritSharedBrokenWallRoom(const RandomizerRegion region, ConditionFn con
return areaTable[region].MQSpiritShared(condition, true, anyAge);
}
-bool BeanPlanted(const RandomizerRegion region) {
+bool BeanPlanted(const RandomizerGet bean) {
+ auto logic = Rando::Context::GetInstance()->GetLogic();
+ // flag irrelevant if plant won't spawn
+ if (!logic->HasItem(bean)) {
+ return false;
+ }
+
// swchFlag found using the Actor Viewer to get the Obj_Bean parameters & 0x3F
// not tested with multiple OTRs, but can be automated similarly to GetDungeonSmallKeyDoors
SceneID sceneID;
uint8_t swchFlag;
- switch (region) {
- case RR_ZORAS_RIVER:
+ switch (bean) {
+ case RG_ZORAS_RIVER_BEAN_SOUL:
sceneID = SceneID::SCENE_ZORAS_RIVER;
swchFlag = 3;
break;
- case RR_THE_GRAVEYARD:
+ case RG_GRAVEYARD_BEAN_SOUL:
sceneID = SceneID::SCENE_GRAVEYARD;
swchFlag = 3;
break;
- case RR_KOKIRI_FOREST:
+ case RG_KOKIRI_FOREST_BEAN_SOUL:
sceneID = SceneID::SCENE_KOKIRI_FOREST;
swchFlag = 9;
break;
- case RR_THE_LOST_WOODS:
+ case RG_LOST_WOODS_BRIDGE_BEAN_SOUL:
sceneID = SceneID::SCENE_LOST_WOODS;
swchFlag = 4;
break;
- case RR_LW_BEYOND_MIDO:
+ case RG_LOST_WOODS_BEAN_SOUL:
sceneID = SceneID::SCENE_LOST_WOODS;
swchFlag = 18;
break;
- case RR_DEATH_MOUNTAIN_TRAIL:
+ case RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL:
sceneID = SceneID::SCENE_DEATH_MOUNTAIN_TRAIL;
swchFlag = 6;
break;
- case RR_LAKE_HYLIA:
+ case RG_LAKE_HYLIA_BEAN_SOUL:
sceneID = SceneID::SCENE_LAKE_HYLIA;
swchFlag = 1;
break;
- case RR_GERUDO_VALLEY:
+ case RG_GERUDO_VALLEY_BEAN_SOUL:
sceneID = SceneID::SCENE_GERUDO_VALLEY;
swchFlag = 3;
break;
- case RR_DMC_CENTRAL_LOCAL:
+ case RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL:
sceneID = SceneID::SCENE_DEATH_MOUNTAIN_CRATER;
swchFlag = 3;
break;
- case RR_DESERT_COLOSSUS:
+ case RG_DESERT_COLOSSUS_BEAN_SOUL:
sceneID = SceneID::SCENE_DESERT_COLOSSUS;
swchFlag = 24;
break;
@@ -733,7 +742,7 @@ bool BeanPlanted(const RandomizerRegion region) {
if (gPlayState != nullptr && gPlayState->sceneNum == sceneID) {
swch = gPlayState->actorCtx.flags.swch;
} else if (sceneID != SCENE_ID_MAX) {
- swch = Rando::Context::GetInstance()->GetLogic()->GetSaveContext()->sceneFlags[sceneID].swch;
+ swch = logic->GetSaveContext()->sceneFlags[sceneID].swch;
} else {
swch = 0;
}
@@ -741,8 +750,8 @@ bool BeanPlanted(const RandomizerRegion region) {
return swch >> swchFlag & 1;
}
-bool CanPlantBean(const RandomizerRegion region) {
- return areaTable[region].CanPlantBeanCheck() || BeanPlanted(region);
+bool CanPlantBean(const RandomizerRegion region, const RandomizerGet bean) {
+ return areaTable[region].CanPlantBeanCheck(bean) || BeanPlanted(bean);
}
bool BothAges(const RandomizerRegion region) {
diff --git a/soh/soh/Enhancements/randomizer/location_access.h b/soh/soh/Enhancements/randomizer/location_access.h
index 26f540aa2..fcb1f6131 100644
--- a/soh/soh/Enhancements/randomizer/location_access.h
+++ b/soh/soh/Enhancements/randomizer/location_access.h
@@ -207,7 +207,7 @@ class Region {
return hereVal;
}
- bool CanPlantBeanCheck() const;
+ bool CanPlantBeanCheck(RandomizerGet bean) const;
bool AllAccountedFor() const;
bool MQSpiritShared(ConditionFn condition, bool IsBrokenWall, bool anyAge = false);
@@ -224,7 +224,7 @@ bool Here(const RandomizerRegion region,
condition); // RANDOTODO make a less stupid way to check own at either age than self referencing with this
bool MQSpiritSharedStatueRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge = false);
bool MQSpiritSharedBrokenWallRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge = false);
-bool CanPlantBean(const RandomizerRegion region);
+bool CanPlantBean(const RandomizerRegion region, RandomizerGet bean);
bool BothAges(const RandomizerRegion region);
bool ChildCanAccess(const RandomizerRegion region);
bool AdultCanAccess(const RandomizerRegion region);
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_crater.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_crater.cpp
index 61b345911..907d209ef 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_crater.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_crater.cpp
@@ -66,7 +66,7 @@ void RegionTable_Init_DeathMountainCrater() {
areaTable[RR_DMC_CENTRAL_NEARBY] = Region("DMC Central Nearby", SCENE_DEATH_MOUNTAIN_CRATER, {}, {
//Locations
- LOCATION(RC_DMC_VOLCANO_FREESTANDING_POH, logic->IsAdult && logic->Hearts() >= 3 && (CanPlantBean(RR_DMC_CENTRAL_LOCAL) || (ctx->GetTrickOption(RT_DMC_HOVER_BEAN_POH) && logic->CanUse(RG_HOVER_BOOTS)))),
+ LOCATION(RC_DMC_VOLCANO_FREESTANDING_POH, logic->IsAdult && logic->Hearts() >= 3 && (CanPlantBean(RR_DMC_CENTRAL_LOCAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL) || (ctx->GetTrickOption(RT_DMC_HOVER_BEAN_POH) && logic->CanUse(RG_HOVER_BOOTS)))),
LOCATION(RC_SHEIK_IN_CRATER, logic->IsAdult && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
}, {
//Exits
@@ -75,10 +75,10 @@ void RegionTable_Init_DeathMountainCrater() {
areaTable[RR_DMC_CENTRAL_LOCAL] = Region("DMC Central Local", SCENE_DEATH_MOUNTAIN_CRATER, {
//Events
- EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3);}),
+ EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3);}),
}, {
//Locations
- LOCATION(RC_DMC_GS_BEAN_PATCH, (logic->FireTimer() >= 8 || logic->Hearts() >= 3) && logic->CanSpawnSoilSkull() && logic->CanAttack()),
+ LOCATION(RC_DMC_GS_BEAN_PATCH, (logic->FireTimer() >= 8 || logic->Hearts() >= 3) && logic->CanSpawnSoilSkull(RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL) && logic->CanAttack()),
LOCATION(RC_DMC_NEAR_PLATFORM_RED_RUPEE, logic->IsChild),
LOCATION(RC_DMC_MIDDLE_PLATFORM_RED_RUPEE, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_1, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
@@ -87,14 +87,14 @@ void RegionTable_Init_DeathMountainCrater() {
LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_4, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_5, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_6, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
- LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
- LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
- LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
+ LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
+ LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
+ LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)),
}, {
//Exits
Entrance(RR_DMC_CENTRAL_NEARBY, []{return true;}),
- Entrance(RR_DMC_LOWER_NEARBY, []{return (logic->IsAdult && CanPlantBean(RR_DMC_CENTRAL_LOCAL)) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT);}),
- Entrance(RR_DMC_UPPER_NEARBY, []{return logic->IsAdult && CanPlantBean(RR_DMC_CENTRAL_LOCAL);}),
+ Entrance(RR_DMC_LOWER_NEARBY, []{return (logic->IsAdult && CanPlantBean(RR_DMC_CENTRAL_LOCAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL)) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT);}),
+ Entrance(RR_DMC_UPPER_NEARBY, []{return logic->IsAdult && CanPlantBean(RR_DMC_CENTRAL_LOCAL, RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL);}),
Entrance(RR_FIRE_TEMPLE_ENTRYWAY, []{return (logic->IsChild && logic->Hearts() >= 3 && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)) || (logic->IsAdult && logic->FireTimer() >= 24);}),
Entrance(RR_DMC_DISTANT_PLATFORM, []{return logic->FireTimer() >= 48 && logic->CanUse(RG_DISTANT_SCARECROW);}),
});
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_trail.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_trail.cpp
index e3d262b17..1691053ab 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_trail.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_trail.cpp
@@ -7,25 +7,25 @@ void RegionTable_Init_DeathMountainTrail() {
// clang-format off
areaTable[RR_DEATH_MOUNTAIN_TRAIL] = Region("Death Mountain", SCENE_DEATH_MOUNTAIN_TRAIL, {
//Events
- EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET));}),
+ EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET));}),
}, {
//Locations
LOCATION(RC_DMT_CHEST, logic->BlastOrSmash() || (ctx->GetTrickOption(RT_DMT_BOMBABLE) && logic->IsChild && logic->HasItem(RG_GORONS_BRACELET))),
- LOCATION(RC_DMT_FREESTANDING_POH, logic->TakeDamage() || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET)))),
- LOCATION(RC_DMT_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET) || (ctx->GetTrickOption(RT_DMT_SOIL_GS) && (logic->TakeDamage() || logic->CanUse(RG_HOVER_BOOTS)) && logic->CanUse(RG_BOOMERANG)))),
+ LOCATION(RC_DMT_FREESTANDING_POH, logic->TakeDamage() || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL, RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET)))),
+ LOCATION(RC_DMT_GS_BEAN_PATCH, logic->CanSpawnSoilSkull(RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET) || (ctx->GetTrickOption(RT_DMT_SOIL_GS) && (logic->TakeDamage() || logic->CanUse(RG_HOVER_BOOTS)) && logic->CanUse(RG_BOOMERANG)))),
LOCATION(RC_DMT_GS_NEAR_KAK, logic->BlastOrSmash()),
- LOCATION(RC_DMT_GS_ABOVE_DODONGOS_CAVERN, logic->IsAdult && logic->AtNight && (logic->CanUse(RG_MEGATON_HAMMER) || (ctx->GetTrickOption(RT_HOOKSHOT_EXTENSION) && logic->CanUse(RG_HOOKSHOT)) || (ctx->GetTrickOption(RT_DMT_BEAN_LOWER_GS) && CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL)) || (ctx->GetTrickOption(RT_DMT_HOVERS_LOWER_GS) && logic->CanUse(RG_HOVER_BOOTS)) || (ctx->GetTrickOption(RT_DMT_JS_LOWER_GS) && logic->CanJumpslash())) && logic->CanGetNightTimeGS()),
+ LOCATION(RC_DMT_GS_ABOVE_DODONGOS_CAVERN, logic->IsAdult && logic->AtNight && (logic->CanUse(RG_MEGATON_HAMMER) || (ctx->GetTrickOption(RT_HOOKSHOT_EXTENSION) && logic->CanUse(RG_HOOKSHOT)) || (ctx->GetTrickOption(RT_DMT_BEAN_LOWER_GS) && CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL, RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL)) || (ctx->GetTrickOption(RT_DMT_HOVERS_LOWER_GS) && logic->CanUse(RG_HOVER_BOOTS)) || (ctx->GetTrickOption(RT_DMT_JS_LOWER_GS) && logic->CanJumpslash())) && logic->CanGetNightTimeGS()),
LOCATION(RC_DMT_BLUE_RUPEE, logic->IsChild && logic->BlastOrSmash()),
LOCATION(RC_DMT_RED_RUPEE, logic->IsChild && logic->BlastOrSmash()),
- LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))),
- LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))),
- LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))),
+ LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))),
+ LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))),
+ LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))),
LOCATION(RC_DMT_FLAG_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)),
}, {
//Exits
Entrance(RR_KAK_BEHIND_GATE, []{return true;}),
Entrance(RR_GORON_CITY, []{return true;}),
- Entrance(RR_DEATH_MOUNTAIN_SUMMIT, []{return Here(RR_DEATH_MOUNTAIN_TRAIL, []{return logic->BlastOrSmash();}) || (logic->IsAdult && ((CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL) && logic->HasItem(RG_GORONS_BRACELET)) || (logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_DMT_CLIMB_HOVERS))));}),
+ Entrance(RR_DEATH_MOUNTAIN_SUMMIT, []{return Here(RR_DEATH_MOUNTAIN_TRAIL, []{return logic->BlastOrSmash();}) || (logic->IsAdult && ((CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL, RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL) && logic->HasItem(RG_GORONS_BRACELET)) || (logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_DMT_CLIMB_HOVERS))));}),
Entrance(RR_DODONGOS_CAVERN_ENTRYWAY, []{return logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET) || logic->IsAdult;}),
Entrance(RR_DMT_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}),
});
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/desert_colossus.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/desert_colossus.cpp
index 5ffb8ac8d..f948fe22d 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/desert_colossus.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/desert_colossus.cpp
@@ -10,13 +10,13 @@ void RegionTable_Init_DesertColossus() {
EventAccess(LOGIC_BUG_ACCESS, []{return true;}),
}, {
//Locations
- LOCATION(RC_COLOSSUS_FREESTANDING_POH, logic->IsAdult && CanPlantBean(RR_DESERT_COLOSSUS)),
- LOCATION(RC_COLOSSUS_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()),
+ LOCATION(RC_COLOSSUS_FREESTANDING_POH, logic->IsAdult && CanPlantBean(RR_DESERT_COLOSSUS, RG_DESERT_COLOSSUS_BEAN_SOUL)),
+ LOCATION(RC_COLOSSUS_GS_BEAN_PATCH, logic->CanSpawnSoilSkull(RG_DESERT_COLOSSUS_BEAN_SOUL) && logic->CanAttack()),
LOCATION(RC_COLOSSUS_GS_TREE, logic->IsAdult && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()),
- LOCATION(RC_COLOSSUS_GS_HILL, logic->IsAdult && ((CanPlantBean(RR_DESERT_COLOSSUS) && logic->CanAttack()) || logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_COLOSSUS_GS) && logic->CanUse(RG_HOOKSHOT))) && logic->CanGetNightTimeGS()),
- LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_COLOSSUS_GS_HILL, logic->IsAdult && ((CanPlantBean(RR_DESERT_COLOSSUS, RG_DESERT_COLOSSUS_BEAN_SOUL) && logic->CanAttack()) || logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_COLOSSUS_GS) && logic->CanUse(RG_HOOKSHOT))) && logic->CanGetNightTimeGS()),
+ LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_DESERT_COLOSSUS_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_DESERT_COLOSSUS_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_DESERT_COLOSSUS_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_COLOSSUS_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()),
LOCATION(RC_COLOSSUS_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_COLOSSUS_GOSSIP_STONE, true),
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_valley.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_valley.cpp
index f83aa8e99..7ed1ae42b 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_valley.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_valley.cpp
@@ -23,15 +23,15 @@ void RegionTable_Init_GerudoValley() {
areaTable[RR_GV_UPPER_STREAM] = Region("GV Upper Stream", SCENE_GERUDO_VALLEY, {
//Events
- EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairy() || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS));}),
+ EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairy() || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_GERUDO_VALLEY_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS));}),
}, {
//Locations
- LOCATION(RC_GV_WATERFALL_FREESTANDING_POH, logic->IsChild || logic->HasItem(RG_BRONZE_SCALE)),//can use cucco as child
- LOCATION(RC_GV_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()),
+ LOCATION(RC_GV_WATERFALL_FREESTANDING_POH, logic->IsChild || logic->HasItem(RG_BRONZE_SCALE) || CanPlantBean(RR_GV_UPPER_STREAM, RG_GERUDO_VALLEY_BEAN_SOUL)),//can use cucco as child
+ LOCATION(RC_GV_GS_BEAN_PATCH, logic->CanSpawnSoilSkull(RG_GERUDO_VALLEY_BEAN_SOUL) && logic->CanAttack()),
LOCATION(RC_GV_COW, logic->IsChild && logic->CanUse(RG_EPONAS_SONG)),
- LOCATION(RC_GV_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_GV_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_GV_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_GV_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_GERUDO_VALLEY_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_GV_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_GERUDO_VALLEY_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_GV_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_GERUDO_VALLEY_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_GV_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()),
LOCATION(RC_GV_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_GV_GOSSIP_STONE, true),
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp
index ff1b90467..3c1eb42e2 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp
@@ -12,13 +12,13 @@ void RegionTable_Init_Graveyard() {
EventAccess(LOGIC_BORROW_BUNNY_HOOD, []{return logic->IsChild && logic->AtDay && logic->Get(LOGIC_BORROW_SPOOKY_MASK) && logic->HasItem(RG_CHILD_WALLET);}),
}, {
//Locations
- LOCATION(RC_GRAVEYARD_FREESTANDING_POH, (((logic->IsAdult && CanPlantBean(RR_THE_GRAVEYARD)) || logic->CanUse(RG_LONGSHOT)) && logic->CanBreakCrates()) || (ctx->GetTrickOption(RT_GY_POH) && logic->CanUse(RG_BOOMERANG))),
+ LOCATION(RC_GRAVEYARD_FREESTANDING_POH, (((logic->IsAdult && CanPlantBean(RR_THE_GRAVEYARD, RG_GRAVEYARD_BEAN_SOUL)) || logic->CanUse(RG_LONGSHOT)) && logic->CanBreakCrates()) || (ctx->GetTrickOption(RT_GY_POH) && logic->CanUse(RG_BOOMERANG))),
LOCATION(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, logic->HasItem(RG_CHILD_WALLET) && logic->IsChild && logic->AtNight), //TODO: This needs to change
LOCATION(RC_GRAVEYARD_GS_WALL, logic->IsChild && logic->HookshotOrBoomerang() && logic->AtNight && logic->CanGetNightTimeGS()),
- LOCATION(RC_GRAVEYARD_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()),
- LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_GRAVEYARD_GS_BEAN_PATCH, logic->CanSpawnSoilSkull(RG_GRAVEYARD_BEAN_SOUL) && logic->CanAttack()),
+ LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_GRAVEYARD_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_GRAVEYARD_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_GRAVEYARD_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_GY_GRASS_1, logic->CanCutShrubs()),
LOCATION(RC_GY_GRASS_2, logic->CanCutShrubs()),
LOCATION(RC_GY_GRASS_3, logic->CanCutShrubs()),
@@ -31,7 +31,7 @@ void RegionTable_Init_Graveyard() {
LOCATION(RC_GY_GRASS_10, logic->CanCutShrubs()),
LOCATION(RC_GY_GRASS_11, logic->CanCutShrubs()),
LOCATION(RC_GY_GRASS_12, logic->CanCutShrubs()),
- LOCATION(RC_GRAVEYARD_CRATE, ((logic->IsAdult && CanPlantBean(RR_THE_GRAVEYARD)) || logic->CanUse(RG_LONGSHOT)) && logic->CanBreakCrates()),
+ LOCATION(RC_GRAVEYARD_CRATE, ((logic->IsAdult && CanPlantBean(RR_THE_GRAVEYARD, RG_GRAVEYARD_BEAN_SOUL)) || logic->CanUse(RG_LONGSHOT)) && logic->CanBreakCrates()),
}, {
//Exits
Entrance(RR_GRAVEYARD_SHIELD_GRAVE, []{return logic->IsAdult || logic->AtNight;}),
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp
index 4e73fa2bc..c0fac1702 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp
@@ -7,17 +7,17 @@ void RegionTable_Init_KokiriForest() {
// clang-format off
areaTable[RR_KOKIRI_FOREST] = Region("Kokiri Forest", SCENE_KOKIRI_FOREST, {
//Events
- EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairyExceptSuns() || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS));}),
+ EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairyExceptSuns() || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_KOKIRI_FOREST_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS));}),
EventAccess(LOGIC_SHOWED_MIDO_SWORD_AND_SHIELD, []{return logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD) && logic->CanUse(RG_DEKU_SHIELD);}),
}, {
//Locations
LOCATION(RC_KF_KOKIRI_SWORD_CHEST, logic->IsChild),
LOCATION(RC_KF_GS_KNOW_IT_ALL_HOUSE, logic->IsChild && logic->CanAttack() && logic->CanGetNightTimeGS()),
- LOCATION(RC_KF_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()),
+ LOCATION(RC_KF_GS_BEAN_PATCH, logic->CanSpawnSoilSkull(RG_KOKIRI_FOREST_BEAN_SOUL) && logic->CanAttack()),
LOCATION(RC_KF_GS_HOUSE_OF_TWINS, logic->IsAdult && (logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_KF_ADULT_GS) && logic->CanUse(RG_HOVER_BOOTS))) && logic->CanGetNightTimeGS()),
- LOCATION(RC_KF_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_KF_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_KF_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_KF_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_KOKIRI_FOREST_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_KF_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_KOKIRI_FOREST_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_KF_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_KOKIRI_FOREST_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_KF_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()),
LOCATION(RC_KF_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_KF_BRIDGE_RUPEE, logic->IsChild),
@@ -28,13 +28,13 @@ void RegionTable_Init_KokiriForest() {
LOCATION(RC_KF_NORTH_GRASS_EAST_RUPEE, logic->IsChild),
LOCATION(RC_KF_BOULDER_RUPEE_1, logic->IsChild),
LOCATION(RC_KF_BOULDER_RUPEE_2, logic->IsChild),
- LOCATION(RC_KF_BEAN_RUPEE_1, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
- LOCATION(RC_KF_BEAN_RUPEE_2, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
- LOCATION(RC_KF_BEAN_RUPEE_3, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
- LOCATION(RC_KF_BEAN_RUPEE_4, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
- LOCATION(RC_KF_BEAN_RUPEE_5, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
- LOCATION(RC_KF_BEAN_RUPEE_6, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
- LOCATION(RC_KF_BEAN_RED_RUPEE, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
+ LOCATION(RC_KF_BEAN_RUPEE_1, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
+ LOCATION(RC_KF_BEAN_RUPEE_2, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
+ LOCATION(RC_KF_BEAN_RUPEE_3, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
+ LOCATION(RC_KF_BEAN_RUPEE_4, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
+ LOCATION(RC_KF_BEAN_RUPEE_5, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
+ LOCATION(RC_KF_BEAN_RUPEE_6, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
+ LOCATION(RC_KF_BEAN_RED_RUPEE, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))),
LOCATION(RC_KF_SARIAS_ROOF_WEST_HEART, logic->IsChild),
LOCATION(RC_KF_SARIAS_ROOF_EAST_HEART, logic->IsChild),
LOCATION(RC_KF_SARIAS_ROOF_NORTH_HEART, logic->IsChild),
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp
index 76ca529e7..ad114cbe9 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp
@@ -7,7 +7,7 @@ void RegionTable_Init_LakeHylia() {
// clang-format off
areaTable[RR_LAKE_HYLIA] = Region("Lake Hylia", SCENE_LAKE_HYLIA, {
//Events
- EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairy() || logic->CanUse(RG_STICKS) || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS));}),
+ EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairy() || logic->CanUse(RG_STICKS) || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_LAKE_HYLIA_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS));}),
EventAccess(LOGIC_BUG_ACCESS, []{return logic->IsChild && logic->CanCutShrubs();}),
EventAccess(LOGIC_CHILD_SCARECROW, []{return logic->IsChild && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 2;}),
EventAccess(LOGIC_ADULT_SCARECROW, []{return logic->IsAdult && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 2;}),
@@ -15,17 +15,17 @@ void RegionTable_Init_LakeHylia() {
//Locations
LOCATION(RC_LH_UNDERWATER_ITEM, logic->IsChild && logic->HasItem(RG_SILVER_SCALE)),
LOCATION(RC_LH_SUN, logic->IsAdult && ((logic->Get(LOGIC_WATER_TEMPLE_CLEAR) && logic->HasItem(RG_BRONZE_SCALE)) || logic->CanUse(RG_DISTANT_SCARECROW)) && logic->CanUse(RG_FAIRY_BOW)),
- LOCATION(RC_LH_FREESTANDING_POH, logic->IsAdult && (logic->CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA))),
- LOCATION(RC_LH_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)),
+ LOCATION(RC_LH_FREESTANDING_POH, logic->IsAdult && (logic->CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA, RG_LAKE_HYLIA_BEAN_SOUL)) && logic->CanAvoidEnemy(RE_GUAY, false)),
+ LOCATION(RC_LH_GS_BEAN_PATCH, logic->CanSpawnSoilSkull(RG_LAKE_HYLIA_BEAN_SOUL) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)),
LOCATION(RC_LH_GS_LAB_WALL, logic->IsChild && (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG) || (ctx->GetTrickOption(RT_LH_LAB_WALL_GS) && logic->CanJumpslashExceptHammer())) && logic->CanGetNightTimeGS()),
LOCATION(RC_LH_GS_SMALL_ISLAND, logic->IsChild && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) && logic->CanGetNightTimeGS() && logic->HasItem(RG_BRONZE_SCALE)),
LOCATION(RC_LH_GS_TREE, logic->IsAdult && logic->CanUse(RG_LONGSHOT) && logic->CanGetNightTimeGS()),
LOCATION(RC_LH_FRONT_RUPEE, logic->IsChild && logic->HasItem(RG_BRONZE_SCALE)),
LOCATION(RC_LH_MIDDLE_RUPEE, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))),
LOCATION(RC_LH_BACK_RUPEE, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))),
- LOCATION(RC_LH_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_LH_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_LH_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_LH_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_LAKE_HYLIA_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_LH_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_LAKE_HYLIA_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_LH_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_LAKE_HYLIA_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_LH_LAB_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()),
LOCATION(RC_LH_LAB_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)),
//You can walk along the edge of the lake to get these without swimming, the fairy is created going backwards, which is convenient here
@@ -84,7 +84,7 @@ void RegionTable_Init_LakeHylia() {
Entrance(RR_HYRULE_FIELD, []{return true;}),
Entrance(RR_LH_FROM_SHORTCUT, []{return true;}),
Entrance(RR_LH_OWL_FLIGHT, []{return logic->IsChild;}),
- Entrance(RR_LH_FISHING_ISLAND, []{return ((logic->IsChild || logic->Get(LOGIC_WATER_TEMPLE_CLEAR)) && logic->HasItem(RG_BRONZE_SCALE)) || (logic->IsAdult && (logic->CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA)));}),
+ Entrance(RR_LH_FISHING_ISLAND, []{return ((logic->IsChild || logic->Get(LOGIC_WATER_TEMPLE_CLEAR)) && logic->HasItem(RG_BRONZE_SCALE)) || (logic->IsAdult && (logic->CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA, RG_LAKE_HYLIA_BEAN_SOUL)));}),
Entrance(RR_LH_LAB, []{return logic->CanOpenOverworldDoor(RG_HYLIA_LAB_KEY);}),
Entrance(RR_LH_FROM_WATER_TEMPLE, []{return true;}),
Entrance(RR_LH_GROTTO, []{return true;}),
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/lost_woods.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/lost_woods.cpp
index a14fed0d7..5aaa5ccd2 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/lost_woods.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/lost_woods.cpp
@@ -12,7 +12,7 @@ void RegionTable_Init_LostWoods() {
areaTable[RR_THE_LOST_WOODS] = Region("Lost Woods", SCENE_LOST_WOODS, {
//Events
- EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairyExceptSuns() || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS));}),
+ EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairyExceptSuns() || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_LOST_WOODS_BRIDGE_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS));}),
EventAccess(LOGIC_BUG_ACCESS, []{return logic->IsChild && logic->CanCutShrubs();}),
EventAccess(LOGIC_BORROW_SPOOKY_MASK, []{return logic->IsChild && logic->Get(LOGIC_BORROW_SKULL_MASK) && logic->CanUse(RG_SARIAS_SONG) && logic->HasItem(RG_CHILD_WALLET);}),
}, {
@@ -32,7 +32,7 @@ void RegionTable_Init_LostWoods() {
LOCATION(RC_LW_OCARINA_MEMORY_GAME, logic->IsChild && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 5),
LOCATION(RC_LW_TARGET_IN_WOODS, logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT)),
LOCATION(RC_LW_DEKU_SCRUB_NEAR_BRIDGE, logic->IsChild && logic->CanStunDeku() && GetCheckPrice() <= GetWalletCapacity()),
- LOCATION(RC_LW_GS_BEAN_PATCH_NEAR_BRIDGE, logic->CanSpawnSoilSkull() && logic->CanAttack()),
+ LOCATION(RC_LW_GS_BEAN_PATCH_NEAR_BRIDGE, logic->CanSpawnSoilSkull(RG_LOST_WOODS_BRIDGE_BEAN_SOUL) && logic->CanAttack()),
//RANDOTODO handle collecting some of these as you leave the shortcut from the other side
LOCATION(RC_LW_SHORTCUT_RUPEE_1, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))),
LOCATION(RC_LW_SHORTCUT_RUPEE_2, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))),
@@ -42,9 +42,9 @@ void RegionTable_Init_LostWoods() {
LOCATION(RC_LW_SHORTCUT_RUPEE_6, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))),
LOCATION(RC_LW_SHORTCUT_RUPEE_7, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))),
LOCATION(RC_LW_SHORTCUT_RUPEE_8, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))),
- LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_LOST_WOODS_BRIDGE_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_LOST_WOODS_BRIDGE_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_LOST_WOODS_BRIDGE_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_LW_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()),
LOCATION(RC_LW_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_LW_SHORTCUT_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)),
@@ -56,7 +56,7 @@ void RegionTable_Init_LostWoods() {
//Exits
Entrance(RR_LW_FOREST_EXIT, []{return true;}),
Entrance(RR_GC_WOODS_WARP, []{return true;}),
- Entrance(RR_LW_BRIDGE, []{return (logic->IsAdult && (CanPlantBean(RR_THE_LOST_WOODS) || ctx->GetTrickOption(RT_LW_BRIDGE))) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT);}),
+ Entrance(RR_LW_BRIDGE, []{return (logic->IsAdult && (CanPlantBean(RR_THE_LOST_WOODS, RG_LOST_WOODS_BRIDGE_BEAN_SOUL) || ctx->GetTrickOption(RT_LW_BRIDGE))) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT);}),
Entrance(RR_ZR_FROM_SHORTCUT, []{return logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS) || (ctx->GetTrickOption(RT_LOST_WOOD_NAVI_DIVE) && logic->IsChild && logic->HasItem(RG_BRONZE_SCALE) && logic->CanJumpslash());}),
Entrance(RR_LW_BEYOND_MIDO, []{return logic->IsChild || logic->CanUse(RG_SARIAS_SONG) || ctx->GetTrickOption(RT_LW_MIDO_BACKFLIP);}),
Entrance(RR_LW_NEAR_SHORTCUTS_GROTTO, []{return Here(RR_THE_LOST_WOODS, []{return logic->BlastOrSmash();});}),
@@ -64,17 +64,17 @@ void RegionTable_Init_LostWoods() {
areaTable[RR_LW_BEYOND_MIDO] = Region("LW Beyond Mido", SCENE_LOST_WOODS, {
//Events
- EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CanUse(RG_STICKS);}),
+ EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CanUse(RG_STICKS) || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_LOST_WOODS_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS));}),
}, {
//Locations
LOCATION(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, logic->IsChild && logic->CanStunDeku() && GetCheckPrice() <= GetWalletCapacity()),
LOCATION(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, logic->IsChild && logic->CanStunDeku() && GetCheckPrice() <= GetWalletCapacity()),
- LOCATION(RC_LW_GS_ABOVE_THEATER, logic->IsAdult && ((CanPlantBean(RR_LW_BEYOND_MIDO) && logic->CanAttack()) || (ctx->GetTrickOption(RT_LW_GS_BEAN) && logic->CanUse(RG_HOOKSHOT) && (logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOMBCHU_5) || logic->CanUse(RG_DINS_FIRE)))) && logic->CanGetNightTimeGS()),
- LOCATION(RC_LW_GS_BEAN_PATCH_NEAR_THEATER, logic->CanSpawnSoilSkull() && (logic->CanAttack() || (ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_OFF) && logic->CanReflectNuts()))),
+ LOCATION(RC_LW_GS_ABOVE_THEATER, logic->IsAdult && ((CanPlantBean(RR_LW_BEYOND_MIDO, RG_LOST_WOODS_BEAN_SOUL) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)) || (ctx->GetTrickOption(RT_LW_GS_BEAN) && logic->CanUse(RG_HOOKSHOT) && (logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOMBCHU_5) || logic->CanUse(RG_DINS_FIRE)))) && logic->CanGetNightTimeGS()),
+ LOCATION(RC_LW_GS_BEAN_PATCH_NEAR_THEATER, logic->CanSpawnSoilSkull(RG_LOST_WOODS_BEAN_SOUL) && (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) || (ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_OFF) && logic->CanReflectNuts()))),
LOCATION(RC_LW_BOULDER_RUPEE, logic->BlastOrSmash()),
- LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_1, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_2, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_3, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_1, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->HasItem(RG_LOST_WOODS_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_2, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->HasItem(RG_LOST_WOODS_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_3, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->HasItem(RG_LOST_WOODS_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_LW_GRASS_4, logic->CanCutShrubs()),
LOCATION(RC_LW_GRASS_5, logic->CanCutShrubs()),
LOCATION(RC_LW_GRASS_6, logic->CanCutShrubs()),
diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/zoras_river.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/zoras_river.cpp
index 642f51117..a3df2f78e 100644
--- a/soh/soh/Enhancements/randomizer/location_access/overworld/zoras_river.cpp
+++ b/soh/soh/Enhancements/randomizer/location_access/overworld/zoras_river.cpp
@@ -29,7 +29,7 @@ void RegionTable_Init_ZoraRiver() {
areaTable[RR_ZORAS_RIVER] = Region("Zora River", SCENE_ZORAS_RIVER, {
//Events
- EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairy() || (logic->IsChild && logic->CanUse(RG_STICKS)) || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS));}),
+ EventAccess(LOGIC_FAIRY_ACCESS, []{return logic->CallGossipFairy() || (logic->IsChild && logic->CanUse(RG_STICKS)) || (logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_ZORAS_RIVER_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS));}),
}, {
//Locations
LOCATION(RC_ZR_MAGIC_BEAN_SALESMAN, logic->IsChild && GetCheckPrice() <= GetWalletCapacity()/* && CanUse(SPEAK_HYLIAN)*/),
@@ -45,9 +45,9 @@ void RegionTable_Init_ZoraRiver() {
LOCATION(RC_ZR_GS_LADDER, logic->IsChild && logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_SHORT_JUMPSLASH) && logic->CanGetNightTimeGS()),
LOCATION(RC_ZR_GS_NEAR_RAISED_GROTTOS, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_LONGSHOT) && logic->CanGetNightTimeGS()),
LOCATION(RC_ZR_GS_ABOVE_BRIDGE, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_HOOKSHOT) && logic->CanGetNightTimeGS()),
- LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
- LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_ZORAS_RIVER_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_ZORAS_RIVER_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
+ LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->HasItem(RG_ZORAS_RIVER_BEAN_SOUL) && logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_ZR_NEAR_DOMAIN_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()),
LOCATION(RC_ZR_NEAR_DOMAIN_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_ZR_BENEATH_WATERFALL_LEFT_RUPEE, logic->IsAdult && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG))),
diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp
index bb835c440..06f1e16ec 100644
--- a/soh/soh/Enhancements/randomizer/logic.cpp
+++ b/soh/soh/Enhancements/randomizer/logic.cpp
@@ -132,6 +132,17 @@ bool Logic::HasItem(RandomizerGet itemName) {
case RG_OCARINA_C_RIGHT_BUTTON:
case RG_OCARINA_C_DOWN_BUTTON:
case RG_OCARINA_C_UP_BUTTON:
+ // Bean Souls
+ case RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL:
+ case RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL:
+ case RG_DESERT_COLOSSUS_BEAN_SOUL:
+ case RG_GERUDO_VALLEY_BEAN_SOUL:
+ case RG_GRAVEYARD_BEAN_SOUL:
+ case RG_KOKIRI_FOREST_BEAN_SOUL:
+ case RG_LAKE_HYLIA_BEAN_SOUL:
+ case RG_LOST_WOODS_BRIDGE_BEAN_SOUL:
+ case RG_LOST_WOODS_BEAN_SOUL:
+ case RG_ZORAS_RIVER_BEAN_SOUL:
// Boss Souls
case RG_GOHMA_SOUL:
case RG_KING_DODONGO_SOUL:
@@ -571,6 +582,7 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
return CanJumpslash() || HasExplosives() || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW);
case RE_KEESE:
case RE_FIRE_KEESE:
+ case RE_GUAY:
switch (distance) {
case ED_CLOSE:
case ED_SHORT_JUMPSLASH:
@@ -583,15 +595,15 @@ bool Logic::CanKillEnemy(RandomizerEnemy enemy, EnemyDistance distance, bool wal
killed = killed || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_STICKS);
[[fallthrough]];
case ED_BOMB_THROW:
- // RANDOTODO test dins and chu range in a practical example
- killed = killed || (!inWater && CanUse(RG_BOMB_BAG));
+ // RANDOTODO test chu range in a practical example
+ killed = killed || (!inWater && CanUse(RG_BOMB_BAG)) || (enemy == RE_GUAY && CanUse(RG_DINS_FIRE));
[[fallthrough]];
case ED_BOOMERANG:
- // RANDOTODO test dins and chu range in a practical example
+ // RANDOTODO test chu range in a practical example
killed = killed || CanUse(RG_BOOMERANG);
[[fallthrough]];
case ED_HOOKSHOT:
- // RANDOTODO test dins, bomb and chu range in a practical example
+ // RANDOTODO test chu range in a practical example
killed = killed || CanUse(RG_HOOKSHOT) || (wallOrFloor && CanUse(RG_BOMBCHU_5));
[[fallthrough]];
case ED_LONGSHOT:
@@ -912,6 +924,7 @@ bool Logic::CanAvoidEnemy(RandomizerEnemy enemy, bool grounded, uint8_t quantity
return !grounded || CanUse(RG_NUTS);
case RE_KEESE:
case RE_FIRE_KEESE:
+ case RE_GUAY:
return CanUse(RG_NUTS);
case RE_BLUE_BUBBLE:
// RANDOTODO Trick to use shield hylian shield as child to stun these guys
@@ -956,6 +969,7 @@ bool Logic::CanGetEnemyDrop(RandomizerEnemy enemy, EnemyDistance distance, bool
break;
case RE_KEESE:
case RE_FIRE_KEESE:
+ case RE_GUAY:
return true;
default:
return aboveLink || (distance <= ED_BOOMERANG && CanUse(RG_BOOMERANG));
@@ -1173,8 +1187,8 @@ bool Logic::BlastOrSmash() {
return HasExplosives() || CanUse(RG_MEGATON_HAMMER);
}
-bool Logic::CanSpawnSoilSkull() {
- return IsChild && CanUse(RG_BOTTLE_WITH_BUGS);
+bool Logic::CanSpawnSoilSkull(RandomizerGet bean) {
+ return IsChild && CanUse(RG_BOTTLE_WITH_BUGS) && HasItem(bean);
}
bool Logic::CanReflectNuts() {
@@ -1402,6 +1416,16 @@ std::map<RandomizerGet, uint32_t> Logic::RandoGetToRandInf = {
{ RG_ZELDAS_LETTER, RAND_INF_ZELDAS_LETTER },
{ RG_WEIRD_EGG, RAND_INF_WEIRD_EGG },
{ RG_RUTOS_LETTER, RAND_INF_OBTAINED_RUTOS_LETTER },
+ { RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, RAND_INF_DEATH_MOUNTAIN_CRATER_BEAN_SOUL },
+ { RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, RAND_INF_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL },
+ { RG_DESERT_COLOSSUS_BEAN_SOUL, RAND_INF_DESERT_COLOSSUS_BEAN_SOUL },
+ { RG_GERUDO_VALLEY_BEAN_SOUL, RAND_INF_GERUDO_VALLEY_BEAN_SOUL },
+ { RG_GRAVEYARD_BEAN_SOUL, RAND_INF_GRAVEYARD_BEAN_SOUL },
+ { RG_KOKIRI_FOREST_BEAN_SOUL, RAND_INF_KOKIRI_FOREST_BEAN_SOUL },
+ { RG_LAKE_HYLIA_BEAN_SOUL, RAND_INF_LAKE_HYLIA_BEAN_SOUL },
+ { RG_LOST_WOODS_BRIDGE_BEAN_SOUL, RAND_INF_LOST_WOODS_BRIDGE_BEAN_SOUL },
+ { RG_LOST_WOODS_BEAN_SOUL, RAND_INF_LOST_WOODS_BEAN_SOUL },
+ { RG_ZORAS_RIVER_BEAN_SOUL, RAND_INF_ZORAS_RIVER_BEAN_SOUL },
{ RG_GOHMA_SOUL, RAND_INF_GOHMA_SOUL },
{ RG_KING_DODONGO_SOUL, RAND_INF_KING_DODONGO_SOUL },
{ RG_BARINADE_SOUL, RAND_INF_BARINADE_SOUL },
@@ -1768,6 +1792,16 @@ void Logic::ApplyItemEffect(Item& item, bool state) {
case RG_RUTOS_LETTER:
SetRandoInf(RAND_INF_OBTAINED_RUTOS_LETTER, state);
break;
+ case RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL:
+ case RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL:
+ case RG_DESERT_COLOSSUS_BEAN_SOUL:
+ case RG_GERUDO_VALLEY_BEAN_SOUL:
+ case RG_GRAVEYARD_BEAN_SOUL:
+ case RG_KOKIRI_FOREST_BEAN_SOUL:
+ case RG_LAKE_HYLIA_BEAN_SOUL:
+ case RG_LOST_WOODS_BRIDGE_BEAN_SOUL:
+ case RG_LOST_WOODS_BEAN_SOUL:
+ case RG_ZORAS_RIVER_BEAN_SOUL:
case RG_GOHMA_SOUL:
case RG_KING_DODONGO_SOUL:
case RG_BARINADE_SOUL:
@@ -2319,6 +2353,19 @@ void Logic::Reset(bool resetSaveContext /*= true*/) {
SetRandoInf(RAND_INF_FISHING_POLE_FOUND, true);
}
+ if (ctx->GetOption(RSK_SHUFFLE_BEAN_SOULS).Is(false)) {
+ SetRandoInf(RAND_INF_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, true);
+ SetRandoInf(RAND_INF_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, true);
+ SetRandoInf(RAND_INF_DESERT_COLOSSUS_BEAN_SOUL, true);
+ SetRandoInf(RAND_INF_GERUDO_VALLEY_BEAN_SOUL, true);
+ SetRandoInf(RAND_INF_GRAVEYARD_BEAN_SOUL, true);
+ SetRandoInf(RAND_INF_KOKIRI_FOREST_BEAN_SOUL, true);
+ SetRandoInf(RAND_INF_LAKE_HYLIA_BEAN_SOUL, true);
+ SetRandoInf(RAND_INF_LOST_WOODS_BRIDGE_BEAN_SOUL, true);
+ SetRandoInf(RAND_INF_LOST_WOODS_BEAN_SOUL, true);
+ SetRandoInf(RAND_INF_ZORAS_RIVER_BEAN_SOUL, true);
+ }
+
// If not keysanity, start with 1 logical key to account for automatically unlocking the basement door in
// vanilla FiT
if (!IsFireLoopLocked() && ctx->GetDungeon(Rando::FIRE_TEMPLE)->IsVanilla()) {
diff --git a/soh/soh/Enhancements/randomizer/logic.h b/soh/soh/Enhancements/randomizer/logic.h
index 9873e90aa..859f41f16 100644
--- a/soh/soh/Enhancements/randomizer/logic.h
+++ b/soh/soh/Enhancements/randomizer/logic.h
@@ -76,7 +76,7 @@ class Logic {
bool BlueFire();
bool HasExplosives();
bool BlastOrSmash();
- bool CanSpawnSoilSkull();
+ bool CanSpawnSoilSkull(RandomizerGet bean);
bool CanReflectNuts();
bool CanCutShrubs();
bool CanStunDeku();
diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp
index 67513935b..1dd94f4b2 100644
--- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp
+++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp
@@ -627,6 +627,8 @@ void Settings::CreateOptionDescriptions() {
"Start with the ability to summon Pierre the Scarecrow. Pulling out an Ocarina in the usual locations will "
"automatically summon him.\n"
"With \"Shuffle Ocarina Buttons\" enabled, you'll need at least two Ocarina buttons to summon him.";
+ mOptionDescriptions[RSK_SKIP_PLANTING_BEANS] = "Beans will be planted once you find beans.\n"
+ "If bean souls are shuffled, you must find soul still.";
mOptionDescriptions[RSK_ITEM_POOL] = "Sets how many major items appear in the item pool.\n"
"\n"
"Plentiful - Extra major items are added to the pool.\n"
@@ -776,6 +778,8 @@ void Settings::CreateOptionDescriptions() {
"location is reachable. When disabled, only "
"required items and locations to beat the game "
"will be guaranteed reachable.";
+ mOptionDescriptions[RSK_SHUFFLE_BEAN_SOULS] =
+ "Shuffle 10 bean souls which must be found to spawn corresponding soil / plant.";
mOptionDescriptions[RSK_SHUFFLE_BOSS_SOULS] =
"Shuffles 8 boss souls (one for each blue warp dungeon). A boss will not appear until you collect its "
"respective soul."
diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp
index dd6c78a79..0c5086b52 100644
--- a/soh/soh/Enhancements/randomizer/randomizer.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer.cpp
@@ -5579,7 +5579,7 @@ CustomMessage Randomizer::GetGoronMessage(u16 index) {
void Randomizer::CreateCustomMessages() {
// RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED
// with GIMESSAGE(getItemID, itemID, english, german, french).
- const std::array<GetItemMessage, 112> getItemMessages = { {
+ const std::array<GetItemMessage, 122> getItemMessages = { {
GIMESSAGE(RG_GREG_RUPEE, ITEM_MASK_GORON, "You found %gGreg%w!", "%gGreg%w! Du hast ihn&wirklich gefunden!",
"Félicitation! Vous avez trouvé %gGreg%w!"),
GIMESSAGE(RG_MASTER_SWORD, ITEM_SWORD_MASTER, "You found the %gMaster Sword%w!",
@@ -5855,6 +5855,27 @@ void Randomizer::CreateCustomMessages() {
"Du erhältst die %rKindergeldbörse%w!&Jetzt kannst Du bis&zu %y99 Rubine%w mit Dir führen!",
"Vous obtenez la %rPetite Bourse%w!&Elle peut contenir jusqu'à %y99 rubis%w!"),
+ GIMESSAGE(RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, ITEM_BEAN, "You found the&%gDeath Mountain Crater Bean Soul%w!",
+ TODO_TRANSLATE, TODO_TRANSLATE),
+ GIMESSAGE(RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, ITEM_BEAN, "You found the&%gDeath Mountain Trail Bean Soul%w!",
+ TODO_TRANSLATE, TODO_TRANSLATE),
+ GIMESSAGE(RG_DESERT_COLOSSUS_BEAN_SOUL, ITEM_BEAN, "You found the&%gDesert Colossus Bean Soul%w!",
+ TODO_TRANSLATE, TODO_TRANSLATE),
+ GIMESSAGE(RG_GERUDO_VALLEY_BEAN_SOUL, ITEM_BEAN, "You found the&%gGerudo Valley Bean Soul%w!", TODO_TRANSLATE,
+ TODO_TRANSLATE),
+ GIMESSAGE(RG_GRAVEYARD_BEAN_SOUL, ITEM_BEAN, "You found the&%gGraveyard Bean Soul%w!", TODO_TRANSLATE,
+ TODO_TRANSLATE),
+ GIMESSAGE(RG_KOKIRI_FOREST_BEAN_SOUL, ITEM_BEAN, "You found the&%gKokiri Forest Bean Soul%w!", TODO_TRANSLATE,
+ TODO_TRANSLATE),
+ GIMESSAGE(RG_LAKE_HYLIA_BEAN_SOUL, ITEM_BEAN, "You found the&%gLake Hylia Bean Soul%w!", TODO_TRANSLATE,
+ TODO_TRANSLATE),
+ GIMESSAGE(RG_LOST_WOODS_BRIDGE_BEAN_SOUL, ITEM_BEAN, "You found the&%gLost Wood's Bridge Bean Soul%w!",
+ TODO_TRANSLATE, TODO_TRANSLATE),
+ GIMESSAGE(RG_LOST_WOODS_BEAN_SOUL, ITEM_BEAN, "You found the&%gLost Wood's Theatre Bean Soul%w!",
+ TODO_TRANSLATE, TODO_TRANSLATE),
+ GIMESSAGE(RG_ZORAS_RIVER_BEAN_SOUL, ITEM_BEAN, "You found the&%gZora's River Bean Soul%w!", TODO_TRANSLATE,
+ TODO_TRANSLATE),
+
GIMESSAGE(RG_GOHMA_SOUL, ITEM_BIG_POE, "You found the soul for %gGohma%w!",
"Du hast die Seele von&%gGohma%w gefunden!", "Vous obtenez l'âme de %gGohma%w!"),
GIMESSAGE(RG_KING_DODONGO_SOUL, ITEM_BIG_POE, "You found the soul for %rKing&Dodongo%w!",
@@ -6086,6 +6107,16 @@ std::map<RandomizerGet, RandomizerInf> randomizerGetToRandInf = {
{ RG_OCARINA_C_DOWN_BUTTON, RAND_INF_HAS_OCARINA_C_DOWN },
{ RG_OCARINA_C_LEFT_BUTTON, RAND_INF_HAS_OCARINA_C_LEFT },
{ RG_OCARINA_C_RIGHT_BUTTON, RAND_INF_HAS_OCARINA_C_RIGHT },
+ { RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, RAND_INF_DEATH_MOUNTAIN_CRATER_BEAN_SOUL },
+ { RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, RAND_INF_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL },
+ { RG_DESERT_COLOSSUS_BEAN_SOUL, RAND_INF_DESERT_COLOSSUS_BEAN_SOUL },
+ { RG_GERUDO_VALLEY_BEAN_SOUL, RAND_INF_GERUDO_VALLEY_BEAN_SOUL },
+ { RG_GRAVEYARD_BEAN_SOUL, RAND_INF_GRAVEYARD_BEAN_SOUL },
+ { RG_KOKIRI_FOREST_BEAN_SOUL, RAND_INF_KOKIRI_FOREST_BEAN_SOUL },
+ { RG_LAKE_HYLIA_BEAN_SOUL, RAND_INF_LAKE_HYLIA_BEAN_SOUL },
+ { RG_LOST_WOODS_BRIDGE_BEAN_SOUL, RAND_INF_LOST_WOODS_BRIDGE_BEAN_SOUL },
+ { RG_LOST_WOODS_BEAN_SOUL, RAND_INF_LOST_WOODS_BEAN_SOUL },
+ { RG_ZORAS_RIVER_BEAN_SOUL, RAND_INF_ZORAS_RIVER_BEAN_SOUL },
{ RG_GOHMA_SOUL, RAND_INF_GOHMA_SOUL },
{ RG_KING_DODONGO_SOUL, RAND_INF_KING_DODONGO_SOUL },
{ RG_BARINADE_SOUL, RAND_INF_BARINADE_SOUL },
@@ -6321,6 +6352,18 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
if (INV_CONTENT(ITEM_BEAN) == ITEM_NONE) {
INV_CONTENT(ITEM_BEAN) = ITEM_BEAN;
AMMO(ITEM_BEAN) = 10;
+ if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SKIP_PLANTING_BEANS)) {
+ gSaveContext.sceneFlags[SCENE_DEATH_MOUNTAIN_CRATER].swch |= (1 << 3);
+ gSaveContext.sceneFlags[SCENE_DEATH_MOUNTAIN_TRAIL].swch |= (1 << 6);
+ gSaveContext.sceneFlags[SCENE_DESERT_COLOSSUS].swch |= (1 << 24);
+ gSaveContext.sceneFlags[SCENE_GERUDO_VALLEY].swch |= (1 << 3);
+ gSaveContext.sceneFlags[SCENE_GRAVEYARD].swch |= (1 << 3);
+ gSaveContext.sceneFlags[SCENE_KOKIRI_FOREST].swch |= (1 << 9);
+ gSaveContext.sceneFlags[SCENE_LAKE_HYLIA].swch |= (1 << 1);
+ gSaveContext.sceneFlags[SCENE_LOST_WOODS].swch |= (1 << 4) | (1 << 18);
+ gSaveContext.sceneFlags[SCENE_ZORAS_RIVER].swch |= (1 << 3);
+ AMMO(ITEM_BEAN) = 0;
+ }
}
break;
case RG_DOUBLE_DEFENSE:
diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h
index 6dc0ffdd9..9cde3a7eb 100644
--- a/soh/soh/Enhancements/randomizer/randomizerTypes.h
+++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h
@@ -4367,6 +4367,16 @@ typedef enum {
RG_BUY_RED_POTION_50,
RG_TRIFORCE,
RG_TRIFORCE_PIECE,
+ RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL,
+ RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL,
+ RG_DESERT_COLOSSUS_BEAN_SOUL,
+ RG_GERUDO_VALLEY_BEAN_SOUL,
+ RG_GRAVEYARD_BEAN_SOUL,
+ RG_KOKIRI_FOREST_BEAN_SOUL,
+ RG_LAKE_HYLIA_BEAN_SOUL,
+ RG_LOST_WOODS_BRIDGE_BEAN_SOUL,
+ RG_LOST_WOODS_BEAN_SOUL,
+ RG_ZORAS_RIVER_BEAN_SOUL,
RG_GOHMA_SOUL,
RG_KING_DODONGO_SOUL,
RG_BARINADE_SOUL,
@@ -5570,6 +5580,7 @@ typedef enum {
RHT_DEKU_STICK_CAPACITY_20,
RHT_DEKU_STICK_CAPACITY_30,
RHT_TRIFORCE_PIECE,
+ RHT_BEAN_SOUL,
RHT_GOHMA_SOUL,
RHT_KING_DODONGO_SOUL,
RHT_BARINADE_SOUL,
@@ -6258,12 +6269,14 @@ typedef enum {
RSK_SKIP_CHILD_ZELDA,
RSK_STARTING_STICKS,
RSK_STARTING_NUTS,
+ RSK_STARTING_BEANS,
RSK_FULL_WALLETS,
RSK_SHUFFLE_CHEST_MINIGAME,
RSK_BIG_POE_COUNT,
RSK_SKIP_EPONA_RACE,
RSK_COMPLETE_MASK_QUEST,
RSK_SKIP_SCARECROWS_SONG,
+ RSK_SKIP_PLANTING_BEANS,
RSK_SKULLS_SUNS_SONG,
RSK_SHUFFLE_ADULT_TRADE,
RSK_SHUFFLE_MERCHANTS,
@@ -6341,6 +6354,7 @@ typedef enum {
RSK_TRIFORCE_HUNT,
RSK_TRIFORCE_HUNT_PIECES_TOTAL,
RSK_TRIFORCE_HUNT_PIECES_REQUIRED,
+ RSK_SHUFFLE_BEAN_SOULS,
RSK_SHUFFLE_BOSS_SOULS,
RSK_FISHSANITY,
RSK_FISHSANITY_POND_COUNT,
@@ -6891,6 +6905,7 @@ typedef enum {
RE_GOHMA_LARVA,
RE_KEESE,
RE_FIRE_KEESE,
+ RE_GUAY,
RE_MAD_SCRUB,
RE_BLUE_BUBBLE,
RE_POE,
diff --git a/soh/soh/Enhancements/randomizer/randomizer_inf.h b/soh/soh/Enhancements/randomizer/randomizer_inf.h
index ad928e855..b2d8c21ea 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_inf.h
+++ b/soh/soh/Enhancements/randomizer/randomizer_inf.h
@@ -182,6 +182,17 @@ DEFINE_RAND_INF(RAND_INF_ADULT_LOACH)
DEFINE_RAND_INF(RAND_INF_10_BIG_POES)
DEFINE_RAND_INF(RAND_INF_GRANT_GANONS_BOSSKEY)
+DEFINE_RAND_INF(RAND_INF_DEATH_MOUNTAIN_CRATER_BEAN_SOUL)
+DEFINE_RAND_INF(RAND_INF_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL)
+DEFINE_RAND_INF(RAND_INF_DESERT_COLOSSUS_BEAN_SOUL)
+DEFINE_RAND_INF(RAND_INF_GERUDO_VALLEY_BEAN_SOUL)
+DEFINE_RAND_INF(RAND_INF_GRAVEYARD_BEAN_SOUL)
+DEFINE_RAND_INF(RAND_INF_KOKIRI_FOREST_BEAN_SOUL)
+DEFINE_RAND_INF(RAND_INF_LAKE_HYLIA_BEAN_SOUL)
+DEFINE_RAND_INF(RAND_INF_LOST_WOODS_BRIDGE_BEAN_SOUL)
+DEFINE_RAND_INF(RAND_INF_LOST_WOODS_BEAN_SOUL)
+DEFINE_RAND_INF(RAND_INF_ZORAS_RIVER_BEAN_SOUL)
+
DEFINE_RAND_INF(RAND_INF_GOHMA_SOUL)
DEFINE_RAND_INF(RAND_INF_KING_DODONGO_SOUL)
DEFINE_RAND_INF(RAND_INF_BARINADE_SOUL)
diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
index cd32cc4b1..16a11cdbc 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
@@ -55,6 +55,7 @@ static WidgetInfo triforcePieceCount;
static WidgetInfo dungeonItemTracking;
static WidgetInfo gregTracking;
static WidgetInfo triforcePieceTracking;
+static WidgetInfo beanSoulsTracking;
static WidgetInfo bossSoulsTracking;
static WidgetInfo ocarinaButtonTracking;
static WidgetInfo overworldKeysTracking;
@@ -136,6 +137,19 @@ std::vector<ItemTrackerItem> triforcePieces = {
ITEM_TRACKER_ITEM(RG_TRIFORCE_PIECE, 0, DrawItem),
};
+std::vector<ItemTrackerItem> beanSoulItems = {
+ ITEM_TRACKER_ITEM_CUSTOM(RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_DESERT_COLOSSUS_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_GERUDO_VALLEY_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_GRAVEYARD_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_KOKIRI_FOREST_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_LAKE_HYLIA_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_LOST_WOODS_BRIDGE_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_LOST_WOODS_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_ZORAS_RIVER_BEAN_SOUL, ITEM_BEAN, ITEM_BEAN, 0, DrawItem),
+};
+
std::vector<ItemTrackerItem> bossSoulItems = {
ITEM_TRACKER_ITEM(RG_GOHMA_SOUL, 0, DrawItem), ITEM_TRACKER_ITEM(RG_KING_DODONGO_SOUL, 0, DrawItem),
ITEM_TRACKER_ITEM(RG_BARINADE_SOUL, 0, DrawItem), ITEM_TRACKER_ITEM(RG_PHANTOM_GANON_SOUL, 0, DrawItem),
@@ -246,6 +260,19 @@ std::map<uint16_t, std::string> itemTrackerDungeonShortNames = {
{ SCENE_THIEVES_HIDEOUT, "HIDE" },
};
+std::map<uint16_t, std::string> itemTrackerBeanShortNames = {
+ { RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, "DMC" },
+ { RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, "DMT" },
+ { RG_DESERT_COLOSSUS_BEAN_SOUL, "DC" },
+ { RG_GERUDO_VALLEY_BEAN_SOUL, "GV" },
+ { RG_GRAVEYARD_BEAN_SOUL, "GY" },
+ { RG_KOKIRI_FOREST_BEAN_SOUL, "KF" },
+ { RG_LAKE_HYLIA_BEAN_SOUL, "LA" },
+ { RG_LOST_WOODS_BRIDGE_BEAN_SOUL, "LWB" },
+ { RG_LOST_WOODS_BEAN_SOUL, "LWT" },
+ { RG_ZORAS_RIVER_BEAN_SOUL, "ZR" },
+};
+
std::map<uint16_t, std::string> itemTrackerBossShortNames = {
{ RG_GOHMA_SOUL, "GOHMA" }, { RG_KING_DODONGO_SOUL, "KD" }, { RG_BARINADE_SOUL, "BARI" },
{ RG_PHANTOM_GANON_SOUL, "PG" }, { RG_VOLVAGIA_SOUL, "VOLV" }, { RG_MORPHA_SOUL, "MORPH" },
@@ -809,6 +836,56 @@ void DrawItem(ItemTrackerItem item) {
hasItem = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT);
itemName = "Triforce Piece";
break;
+ case RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_DEATH_MOUNTAIN_CRATER_BEAN_SOUL);
+ itemName = "Death Mountain Crater Bean Soul";
+ break;
+ case RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL);
+ itemName = "Death Mountain Trail Bean Soul";
+ break;
+ case RG_DESERT_COLOSSUS_BEAN_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_DESERT_COLOSSUS_BEAN_SOUL);
+ itemName = "Desert Colossus Bean Soul";
+ break;
+ case RG_GERUDO_VALLEY_BEAN_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_GERUDO_VALLEY_BEAN_SOUL);
+ itemName = "Gerudo Valley Bean Soul";
+ break;
+ case RG_GRAVEYARD_BEAN_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_GRAVEYARD_BEAN_SOUL);
+ itemName = "Graveyard Bean Soul";
+ break;
+ case RG_KOKIRI_FOREST_BEAN_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_KOKIRI_FOREST_BEAN_SOUL);
+ itemName = "Kokiri Forest Bean Soul";
+ break;
+ case RG_LAKE_HYLIA_BEAN_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_LAKE_HYLIA_BEAN_SOUL);
+ itemName = "Lake Hylia Bean Soul";
+ break;
+ case RG_LOST_WOODS_BRIDGE_BEAN_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_LOST_WOODS_BRIDGE_BEAN_SOUL);
+ itemName = "Lost Woods Bridge Bean Soul";
+ break;
+ case RG_LOST_WOODS_BEAN_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_LOST_WOODS_BEAN_SOUL);
+ itemName = "Lost Woods Theatre Bean Soul";
+ break;
+ case RG_ZORAS_RIVER_BEAN_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_ZORAS_RIVER_BEAN_SOUL);
+ itemName = "Zora's River Bean Soul";
+ break;
case RG_GOHMA_SOUL:
actualItemId = item.id;
hasItem = Flags_GetRandomizerInf(RAND_INF_GOHMA_SOUL);
@@ -1025,6 +1102,16 @@ void DrawItem(ItemTrackerItem item) {
DrawItemCount(item, false);
+ if (item.id >= RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL && item.id <= RG_ZORAS_RIVER_BEAN_SOUL) {
+ ImVec2 p = ImGui::GetCursorScreenPos();
+ std::string beanName = itemTrackerBeanShortNames[item.id];
+ ImGui::SetCursorScreenPos(
+ ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize(beanName.c_str()).x / 2), p.y - (iconSize + 13)));
+ ImGui::PushStyleColor(ImGuiCol_Text, IM_COL_WHITE);
+ ImGui::Text("%s", beanName.c_str());
+ ImGui::PopStyleColor();
+ }
+
if (item.id >= RG_GOHMA_SOUL && item.id <= RG_GANON_SOUL) {
ImVec2 p = ImGui::GetCursorScreenPos();
std::string bossName = itemTrackerBossShortNames[item.id];
@@ -1478,6 +1565,19 @@ void UpdateVectors() {
mainWindowItems.insert(mainWindowItems.end(), fishingPoleItems.begin(), fishingPoleItems.end());
}
+ // If we're adding bean souls to the main window...
+ if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.BeanSouls"), SECTION_DISPLAY_HIDDEN) ==
+ SECTION_DISPLAY_MAIN_WINDOW) {
+ //...add empty items on the main window to get the souls on their own row. (Too many to sit with Greg/Triforce
+ // pieces)
+ while (mainWindowItems.size() % 6) {
+ mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem));
+ }
+
+ // Add bean souls
+ mainWindowItems.insert(mainWindowItems.end(), beanSoulItems.begin(), beanSoulItems.end());
+ }
+
// If we're adding boss souls to the main window...
if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.BossSouls"), SECTION_DISPLAY_HIDDEN) ==
SECTION_DISPLAY_MAIN_WINDOW) {
@@ -1674,6 +1774,13 @@ void ItemTrackerWindow::DrawElement() {
EndFloatingWindows();
}
+ if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.BeanSouls"), SECTION_DISPLAY_HIDDEN) ==
+ SECTION_DISPLAY_SEPARATE) {
+ BeginFloatingWindows("Bean Soul Tracker");
+ DrawItemsInRows(beanSoulItems);
+ EndFloatingWindows();
+ }
+
if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.BossSouls"), SECTION_DISPLAY_HIDDEN) ==
SECTION_DISPLAY_SEPARATE) {
BeginFloatingWindows("Boss Soul Tracker");
@@ -1914,6 +2021,7 @@ void ItemTrackerSettingsWindow::DrawElement() {
}
SohGui::mSohMenu->MenuDrawItem(gregTracking, 250, THEME_COLOR);
SohGui::mSohMenu->MenuDrawItem(triforcePieceTracking, 250, THEME_COLOR);
+ SohGui::mSohMenu->MenuDrawItem(beanSoulsTracking, 250, THEME_COLOR);
SohGui::mSohMenu->MenuDrawItem(bossSoulsTracking, 250, THEME_COLOR);
SohGui::mSohMenu->MenuDrawItem(ocarinaButtonTracking, 250, THEME_COLOR);
SohGui::mSohMenu->MenuDrawItem(overworldKeysTracking, 250, THEME_COLOR);
@@ -2028,6 +2136,18 @@ void RegisterItemTrackerWidgets() {
;
SohGui::mSohMenu->AddSearchWidget({ gregTracking, "Randomizer", "Item Tracker", "General Settings", "icon" });
+ beanSoulsTracking = { .name = "Bean Souls", .type = WidgetType::WIDGET_CVAR_COMBOBOX };
+ beanSoulsTracking.CVar(CVAR_TRACKER_ITEM("DisplayType.BeanSouls"))
+ .Options(ComboboxOptions()
+ .DefaultIndex(SECTION_DISPLAY_HIDDEN)
+ .ComponentAlignment(ComponentAlignments::Right)
+ .LabelPosition(LabelPositions::Far)
+ .Color(THEME_COLOR)
+ .ComboMap(displayTypes))
+ .Callback([](WidgetInfo& info) { shouldUpdateVectors = true; });
+ ;
+ SohGui::mSohMenu->AddSearchWidget({ beanSoulsTracking, "Randomizer", "Item Tracker", "General Settings", "icon" });
+
bossSoulsTracking = { .name = "Boss Souls", .type = WidgetType::WIDGET_CVAR_COMBOBOX };
bossSoulsTracking.CVar(CVAR_TRACKER_ITEM("DisplayType.BossSouls"))
.Options(ComboboxOptions()
diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp
index c8c3ea431..0bcfa1038 100644
--- a/soh/soh/Enhancements/randomizer/savefile.cpp
+++ b/soh/soh/Enhancements/randomizer/savefile.cpp
@@ -266,6 +266,41 @@ extern "C" void Randomizer_InitSaveFile() {
// Go away Ruto (Water Temple first cutscene).
gSaveContext.sceneFlags[SCENE_WATER_TEMPLE].swch |= (1 << 0x10);
+ if (Randomizer_GetSettingValue(RSK_STARTING_BEANS)) {
+ INV_CONTENT(ITEM_BEAN) = ITEM_BEAN;
+ if (Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_BEANS_ONLY &&
+ Randomizer_GetSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_ALL) {
+ BEANS_BOUGHT = 10;
+ }
+ if (Randomizer_GetSettingValue(RSK_SKIP_PLANTING_BEANS)) {
+ AMMO(ITEM_BEAN) = 0;
+ gSaveContext.sceneFlags[SCENE_DEATH_MOUNTAIN_CRATER].swch |= (1 << 3);
+ gSaveContext.sceneFlags[SCENE_DEATH_MOUNTAIN_TRAIL].swch |= (1 << 6);
+ gSaveContext.sceneFlags[SCENE_DESERT_COLOSSUS].swch |= (1 << 24);
+ gSaveContext.sceneFlags[SCENE_GERUDO_VALLEY].swch |= (1 << 3);
+ gSaveContext.sceneFlags[SCENE_GRAVEYARD].swch |= (1 << 3);
+ gSaveContext.sceneFlags[SCENE_KOKIRI_FOREST].swch |= (1 << 9);
+ gSaveContext.sceneFlags[SCENE_LAKE_HYLIA].swch |= (1 << 1);
+ gSaveContext.sceneFlags[SCENE_LOST_WOODS].swch |= (1 << 4) | (1 << 18);
+ gSaveContext.sceneFlags[SCENE_ZORAS_RIVER].swch |= (1 << 3);
+ } else {
+ AMMO(ITEM_BEAN) = 10;
+ }
+ }
+
+ if (Randomizer_GetSettingValue(RSK_SHUFFLE_BEAN_SOULS) == RO_GENERIC_OFF) {
+ Flags_SetRandomizerInf(RAND_INF_DEATH_MOUNTAIN_CRATER_BEAN_SOUL);
+ Flags_SetRandomizerInf(RAND_INF_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL);
+ Flags_SetRandomizerInf(RAND_INF_DESERT_COLOSSUS_BEAN_SOUL);
+ Flags_SetRandomizerInf(RAND_INF_GERUDO_VALLEY_BEAN_SOUL);
+ Flags_SetRandomizerInf(RAND_INF_GRAVEYARD_BEAN_SOUL);
+ Flags_SetRandomizerInf(RAND_INF_KOKIRI_FOREST_BEAN_SOUL);
+ Flags_SetRandomizerInf(RAND_INF_LAKE_HYLIA_BEAN_SOUL);
+ Flags_SetRandomizerInf(RAND_INF_LOST_WOODS_BRIDGE_BEAN_SOUL);
+ Flags_SetRandomizerInf(RAND_INF_LOST_WOODS_BEAN_SOUL);
+ Flags_SetRandomizerInf(RAND_INF_ZORAS_RIVER_BEAN_SOUL);
+ }
+
if (Randomizer_GetSettingValue(RSK_SHUFFLE_OCARINA_BUTTONS) == RO_GENERIC_OFF) {
Flags_SetRandomizerInf(RAND_INF_HAS_OCARINA_A);
Flags_SetRandomizerInf(RAND_INF_HAS_OCARINA_C_LEFT);
diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp
index 1266cb651..95463f20d 100644
--- a/soh/soh/Enhancements/randomizer/settings.cpp
+++ b/soh/soh/Enhancements/randomizer/settings.cpp
@@ -237,6 +237,7 @@ void Settings::CreateOptions() {
OPT_BOOL(RSK_SHUFFLE_ADULT_TRADE, "Shuffle Adult Trade", CVAR_RANDOMIZER_SETTING("ShuffleAdultTrade"), mOptionDescriptions[RSK_SHUFFLE_ADULT_TRADE]);
OPT_U8(RSK_SHUFFLE_CHEST_MINIGAME, "Shuffle Chest Minigame", {"Off", "On (Separate)", "On (Pack)"});
OPT_BOOL(RSK_SHUFFLE_100_GS_REWARD, "Shuffle 100 GS Reward", CVAR_RANDOMIZER_SETTING("Shuffle100GSReward"), mOptionDescriptions[RSK_SHUFFLE_100_GS_REWARD], IMFLAG_SEPARATOR_BOTTOM, WidgetType::Checkbox, RO_GENERIC_OFF);
+ OPT_BOOL(RSK_SHUFFLE_BEAN_SOULS, "Shuffle Bean Souls", CVAR_RANDOMIZER_SETTING("ShuffleBeanSouls"), mOptionDescriptions[RSK_SHUFFLE_BEAN_SOULS], IMFLAG_SEPARATOR_BOTTOM, WidgetType::Checkbox, RO_GENERIC_OFF);
OPT_U8(RSK_SHUFFLE_BOSS_SOULS, "Shuffle Boss Souls", {"Off", "On", "On + Ganon"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleBossSouls"), mOptionDescriptions[RSK_SHUFFLE_BOSS_SOULS], WidgetType::Combobox);
OPT_BOOL(RSK_SHUFFLE_DEKU_STICK_BAG, "Shuffle Deku Stick Bag", CVAR_RANDOMIZER_SETTING("ShuffleDekuStickBag"), mOptionDescriptions[RSK_SHUFFLE_DEKU_STICK_BAG], IMFLAG_SEPARATOR_BOTTOM, WidgetType::Checkbox, RO_GENERIC_OFF);
OPT_BOOL(RSK_SHUFFLE_DEKU_NUT_BAG, "Shuffle Deku Nut Bag", CVAR_RANDOMIZER_SETTING("ShuffleDekuNutBag"), mOptionDescriptions[RSK_SHUFFLE_DEKU_NUT_BAG], IMFLAG_SEPARATOR_BOTTOM, WidgetType::Checkbox, RO_GENERIC_OFF);
@@ -276,6 +277,7 @@ void Settings::CreateOptions() {
OPT_BOOL(RSK_SKIP_CHILD_ZELDA, "Skip Child Zelda", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipChildZelda"), mOptionDescriptions[RSK_SKIP_CHILD_ZELDA], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP);
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_BOOL(RSK_SKIP_PLANTING_BEANS, "Skip Planting Beans", CVAR_RANDOMIZER_SETTING("SkipPlantingBeans"), mOptionDescriptions[RSK_SKIP_PLANTING_BEANS]);
OPT_U8(RSK_BIG_POE_COUNT, "Big Poe Target Count", {NumOpts(0, 10)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("BigPoeTargetCount"), mOptionDescriptions[RSK_BIG_POE_COUNT], WidgetType::Slider, 10);
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);
@@ -322,6 +324,7 @@ void Settings::CreateOptions() {
OPT_BOOL(RSK_STARTING_MASTER_SWORD, "Start with Master Sword", CVAR_RANDOMIZER_SETTING("StartingMasterSword"));
OPT_BOOL(RSK_STARTING_STICKS, "Start with Stick Ammo", {"No", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingSticks"), "", WidgetType::Checkbox, RO_GENERIC_OFF);
OPT_BOOL(RSK_STARTING_NUTS, "Start with Nut Ammo", {"No", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingNuts"), "", WidgetType::Checkbox, RO_GENERIC_OFF);
+ OPT_BOOL(RSK_STARTING_BEANS, "Start with Magic Beans", {"No", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingBeans"), "", WidgetType::Checkbox, RO_GENERIC_OFF);
OPT_BOOL(RSK_FULL_WALLETS, "Full Wallets", {"No", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("FullWallets"), mOptionDescriptions[RSK_FULL_WALLETS], WidgetType::Checkbox, RO_GENERIC_OFF);
OPT_BOOL(RSK_STARTING_ZELDAS_LULLABY, "Start with Zelda's Lullaby", CVAR_RANDOMIZER_SETTING("StartingZeldasLullaby"), "", IMFLAG_NONE);
OPT_BOOL(RSK_STARTING_EPONAS_SONG, "Start with Epona's Song", CVAR_RANDOMIZER_SETTING("StartingEponasSong"), "", IMFLAG_NONE);
@@ -1343,6 +1346,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_FROG_SONG_RUPEES],
&mOptions[RSK_SHUFFLE_ADULT_TRADE],
&mOptions[RSK_SHUFFLE_100_GS_REWARD],
+ &mOptions[RSK_SHUFFLE_BEAN_SOULS],
&mOptions[RSK_SHUFFLE_BOSS_SOULS],
&mOptions[RSK_SHUFFLE_FOUNTAIN_FAIRIES],
&mOptions[RSK_SHUFFLE_STONE_FAIRIES],
@@ -1389,7 +1393,7 @@ void Settings::CreateOptions() {
mOptionGroups[RSG_TIMESAVERS_IMGUI] = OptionGroup::SubGroup(
"Timesavers",
{ &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_COMPLETE_MASK_QUEST], &mOptions[RSK_SKIP_SCARECROWS_SONG], &mOptions[RSK_SKIP_PLANTING_BEANS] },
WidgetContainerType::COLUMN);
mOptionGroups[RSG_ITEM_POOL_HINTS_IMGUI] = OptionGroup::SubGroup("",
{
@@ -1463,6 +1467,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_STARTING_OCARINA],
&mOptions[RSK_STARTING_STICKS],
&mOptions[RSK_STARTING_NUTS],
+ &mOptions[RSK_STARTING_BEANS],
&mOptions[RSK_STARTING_SKULLTULA_TOKEN],
&mOptions[RSK_STARTING_HEARTS],
},
@@ -1608,6 +1613,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_ADULT_TRADE],
&mOptions[RSK_SHUFFLE_CHEST_MINIGAME],
&mOptions[RSK_SHUFFLE_100_GS_REWARD],
+ &mOptions[RSK_SHUFFLE_BEAN_SOULS],
&mOptions[RSK_SHUFFLE_BOSS_SOULS],
&mOptions[RSK_SHUFFLE_DEKU_STICK_BAG],
&mOptions[RSK_SHUFFLE_DEKU_NUT_BAG],
@@ -1664,6 +1670,7 @@ void Settings::CreateOptions() {
mOptionGroups[RSG_STARTING_OTHER] = OptionGroup::SubGroup("Other", {
&mOptions[RSK_STARTING_STICKS],
&mOptions[RSK_STARTING_NUTS],
+ &mOptions[RSK_STARTING_BEANS],
&mOptions[RSK_FULL_WALLETS],
&mOptions[RSK_STARTING_SKULLTULA_TOKEN],
&mOptions[RSK_STARTING_HEARTS],
@@ -1679,6 +1686,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SKIP_CHILD_ZELDA],
&mOptions[RSK_SKIP_EPONA_RACE],
&mOptions[RSK_SKIP_SCARECROWS_SONG],
+ &mOptions[RSK_SKIP_PLANTING_BEANS],
&mOptions[RSK_BIG_POE_COUNT],
&mOptions[RSK_COMPLETE_MASK_QUEST],
});
diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp
index 2aadd55d2..9167d5e9c 100644
--- a/soh/soh/OTRGlobals.cpp
+++ b/soh/soh/OTRGlobals.cpp
@@ -2549,12 +2549,18 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
u16 naviTextId = Random(0, NUM_NAVI_MESSAGES);
messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::NaviRandoMessageTableID,
naviTextId, MF_FORMATTED);
- } else if (textId == TEXT_BEAN_SALESMAN_BUY_FOR_10 &&
- (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_BEANS_ONLY) ||
- ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL))) {
- messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(
- RC_ZR_MAGIC_BEAN_SALESMAN, TEXT_BEAN_SALESMAN_BUY_FOR_10, TEXT_NONE,
- Randomizer_GetSettingValue(RSK_MERCHANT_TEXT_HINT) == RO_GENERIC_OFF);
+ } else if (textId == TEXT_BEAN_SALESMAN_BUY_FOR_10) {
+ if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_BEANS_ONLY) ||
+ ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL)) {
+ messageEntry = OTRGlobals::Instance->gRandomizer->GetMerchantMessage(
+ RC_ZR_MAGIC_BEAN_SALESMAN, TEXT_BEAN_SALESMAN_BUY_FOR_10, TEXT_NONE,
+ Randomizer_GetSettingValue(RSK_MERCHANT_TEXT_HINT) == RO_GENERIC_OFF);
+ } else if (ctx->GetOption(RSK_SKIP_PLANTING_BEANS)) {
+ // TODO_TRANSLATE Translate into french and german
+ messageEntry =
+ CustomMessage("For #60 rupees# I'll plant beans across Hyrule, deal?\x1B#Yes&No#", { QM_YELLOW });
+ messageEntry.AutoFormat();
+ }
} else if (textId == TEXT_BEAN_SALESMAN_BUY_FOR_100) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(
Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN_BUY_FOR_100, MF_AUTO_FORMAT);