Progressive BGS (#7037)

This commit is contained in:
Philip Dubé
2026-08-08 18:00:23 +00:00
committed by GitHub
parent 6420c435b1
commit 29668a06d6
9 changed files with 50 additions and 11 deletions
@@ -182,7 +182,11 @@ void GenerateItemPool() {
AddFixedItemToPool(RG_PROGRESSIVE_HOOKSHOT, 2 - ctx->GetOption(RSK_STARTING_HOOKSHOT).Get());
if (!ctx->GetOption(RSK_STARTING_HYLIAN_SHIELD)) AddItemToPool(RG_HYLIAN_SHIELD, 1, 1, 1, 1);
AddItemToPool(RG_DOUBLE_DEFENSE, 2, 1, 0, 0);
if (ctx->GetOption(RSK_STARTING_BIGGORON_SWORD).IsNot(RO_STARTING_BGS_BIGGORON_SWORD)) {
if (ctx->GetOption(RSK_PROGRESSIVE_GORON_SWORD)) {
int startGoronSword = ctx->GetOption(RSK_STARTING_BIGGORON_SWORD).Get();
AddItemToPool(RG_PROGRESSIVE_GORONSWORD, std::max(0, 3 - startGoronSword), std::max(0, 2 - startGoronSword),
std::max(0, 2 - startGoronSword), std::max(0, 1 - startGoronSword));
} else if (ctx->GetOption(RSK_STARTING_BIGGORON_SWORD).IsNot(RO_STARTING_BGS_BIGGORON_SWORD)) {
AddItemToPool(RG_BIGGORON_SWORD, 2, 1, 1, 0);
}
bool isScrubs = ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_ALL);
@@ -527,7 +531,7 @@ void GenerateItemPool() {
if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL_BUT_BEANS) ||
ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ALL)) {
if (/*!ProgressiveGoronSword TODO: Implement Progressive Goron Sword*/
if (!ctx->GetOption(RSK_PROGRESSIVE_GORON_SWORD) &&
ctx->GetOption(RSK_STARTING_BIGGORON_SWORD).Is(RO_STARTING_BGS_OFF)) {
AddFixedItemToPool(RG_GIANTS_KNIFE, 1);
}
@@ -538,7 +542,9 @@ void GenerateItemPool() {
}
} else {
ctx->PlaceItemInLocation(RC_KAK_GRANNYS_SHOP, RG_BLUE_POTION_REFILL, false, true);
ctx->PlaceItemInLocation(RC_GC_MEDIGORON, RG_GIANTS_KNIFE, false, true);
// when progressive, Medigoron only replaces broken knives, so he never hands out a first one
ctx->PlaceItemInLocation(
RC_GC_MEDIGORON, ctx->GetOption(RSK_PROGRESSIVE_GORON_SWORD) ? RG_SOLD_OUT : RG_GIANTS_KNIFE, false, true);
ctx->PlaceItemInLocation(RC_WASTELAND_BOMBCHU_SALESMAN, RG_BOMBCHU_10, false, true);
}
@@ -1495,6 +1495,9 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
Flags_UnsetInfTable(INFTABLE_B1);
*should = true;
}
} else if (id == VB_BE_ELIGIBLE_FOR_GIANTS_KNIFE_PURCHASE && RAND_GET_OPTION(RSK_PROGRESSIVE_GORON_SWORD)) {
// the progressive sword carries the first knife, leaving Medigoron to replace broken ones
*should = false;
}
break;
}
+3 -2
View File
@@ -370,8 +370,9 @@ std::shared_ptr<GetItemEntry> Item::GetGIEntry() const { // NOLINT(*-no-recursio
break;
}
break;
case RG_PROGRESSIVE_GORONSWORD: // todo progressive?
actual = RG_BIGGORON_SWORD;
case RG_PROGRESSIVE_GORONSWORD:
// owning the slot means the knife was already given, breaking it doesn't clear the flag
actual = logic->CheckEquipment(EQUIP_FLAG_SWORD_BGS) ? RG_BIGGORON_SWORD : RG_GIANTS_KNIFE;
break;
case RG_PROGRESSIVE_BOMBCHU_BAG:
if (OTRGlobals::Instance->gRandoContext->GetOption(RSK_BOMBCHU_BAG).Is(RO_BOMBCHU_BAG_SINGLE)) {
+16 -2
View File
@@ -73,10 +73,13 @@ bool Logic::HasItem(RandomizerGet itemName) {
case RG_IRON_BOOTS:
case RG_HOVER_BOOTS:
return CheckEquipment(RandoGetToEquipFlag.at(itemName));
case RG_PROGRESSIVE_GORONSWORD:
case RG_GIANTS_KNIFE:
return CheckEquipment(RandoGetToEquipFlag.at(itemName)) || Get(LOGIC_MEDIGORON);
// progressive leaves Medigoron replacing broken knives, so the first one has to be found
return CheckEquipment(EQUIP_FLAG_SWORD_BGS) ||
(!ctx->GetOption(RSK_PROGRESSIVE_GORON_SWORD) && Get(LOGIC_MEDIGORON));
case RG_BIGGORON_SWORD:
return CheckEquipment(RandoGetToEquipFlag.at(itemName)) && mSaveContext->bgsFlag;
return CheckEquipment(EQUIP_FLAG_SWORD_BGS) && mSaveContext->bgsFlag;
case RG_GORONS_BRACELET:
return CurrentUpgrade(UPG_STRENGTH);
case RG_SILVER_GAUNTLETS:
@@ -335,6 +338,7 @@ bool Logic::ItemUseAllowed(RandomizerGet itemName) {
switch (itemName) {
case RG_KOKIRI_SWORD:
case RG_MASTER_SWORD:
case RG_PROGRESSIVE_GORONSWORD:
case RG_GIANTS_KNIFE:
case RG_BIGGORON_SWORD:
return BAllowed();
@@ -578,6 +582,7 @@ bool Logic::CanUse(RandomizerGet itemName) {
return IsAdult; // || MirrorShieldAsChild;
case RG_MASTER_SWORD:
return IsAdult; // || MasterSwordAsChild;
case RG_PROGRESSIVE_GORONSWORD:
case RG_GIANTS_KNIFE:
case RG_BIGGORON_SWORD:
return IsAdult; // || BiggoronSwordAsChild;
@@ -2262,6 +2267,15 @@ void Logic::ApplyItemEffect(Item& item, bool state) {
}
SetInventory(ITEM_BOMBCHU, (!state ? ITEM_NONE : ITEM_BOMBCHU));
} break;
case RG_PROGRESSIVE_GORONSWORD:
if (state ? CheckEquipment(EQUIP_FLAG_SWORD_BGS) : mSaveContext->bgsFlag) {
mSaveContext->bgsFlag = state;
} else if (state) {
mSaveContext->inventory.equipment |= EQUIP_FLAG_SWORD_BGS;
} else {
mSaveContext->inventory.equipment &= ~EQUIP_FLAG_SWORD_BGS;
}
break;
case RG_PROGRESSIVE_MAGIC_METER: {
auto realGI = item.GetGIEntry();
if (realGI->itemId == RG_MAGIC_INF && realGI->modIndex == MOD_RANDOMIZER) {
@@ -860,6 +860,12 @@ void Settings::CreateOptionDescriptions() {
"\n"
"If you have Bombchu Bag disabled, you will need a Bomb Bag "
"and existing Bombchus for Bombchus to drop.";
mOptionDescriptions[RSK_PROGRESSIVE_GORON_SWORD] =
"Giant's Knife and Biggoron's Sword are shuffled as one progressive item: the first copy is the "
"breakable Giant's Knife, the second is Biggoron's Sword.\n"
"\n"
"Starting with Biggoron's Sword still starts you with both.\n"
"Medigoron only repairs broken Giant's Knife.";
mOptionDescriptions[RSK_BLUE_FIRE_ARROWS] =
"Ice Arrows act like Blue Fire, making them able to melt red ice. "
"Item placement logic will respect this option, so it might be required to use this to progress.";
@@ -472,7 +472,10 @@ ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGe
return Inventory_HasEmptyBottle() ? CAN_OBTAIN : CANT_OBTAIN_NEED_EMPTY_BOTTLE;
// Trade Items
// case RG_PROGRESSIVE_GORONSWORD:
// Giant's Knife and Biggoron's Sword share a slot, bgsFlag marks the final upgrade.
// Giant's Knife itself stays obtainable, Medigoron replaces broken ones.
case RG_PROGRESSIVE_GORONSWORD:
return !gSaveContext.bgsFlag ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE;
// case RG_GIANTS_KNIFE:
// Misc Items
@@ -308,6 +308,7 @@ RANDO_ENUM_ITEM(RSK_ROCS_FEATHER)
RANDO_ENUM_ITEM(RSK_SHUFFLE_ICICLES)
RANDO_ENUM_ITEM(RSK_SHUFFLE_RED_ICE)
RANDO_ENUM_ITEM(RSK_STARTING_BUNNY_HOOD)
RANDO_ENUM_ITEM(RSK_PROGRESSIVE_GORON_SWORD)
RANDO_ENUM_ITEM(RSK_MAX)
RANDO_ENUM_END(RandomizerSettingKey)
@@ -882,13 +882,15 @@ void DrawItemCount(ItemTrackerItem item, bool hideMax) {
void DrawEquip(ItemTrackerItem item) {
assert(item.kind == ITEM_KIND_ITEM);
bool hasEquip = HasEquipment(item);
bool hasEquip = HasEquipment(item) && IsValidSaveFile();
bool giantsKnife = item.id == ITEM_SWORD_BGS && hasEquip && !gSaveContext.bgsFlag;
std::string iconName = giantsKnife ? "ITEM_SWORD_KNIFE" : hasEquip ? item.iconName : item.fadedIconName;
float iconSize = static_cast<float>(CVarGetInteger(CVAR_TRACKER_ITEM("IconSize"), 36));
ImGui::Image(std::dynamic_pointer_cast<Fast::Fast3dGui>(Ship::Context::GetRawInstance()->GetWindow()->GetGui())
->GetTextureByName(hasEquip && IsValidSaveFile() ? item.iconName : item.fadedIconName),
->GetTextureByName(iconName),
ImVec2(iconSize, iconSize), ImVec2(0.0f, 0.0f), ImVec2(1, 1));
Tooltip(SohUtils::GetItemName(item.id).c_str());
Tooltip(giantsKnife ? "Giant's Knife" : SohUtils::GetItemName(item.id).c_str());
}
void DrawQuest(ItemTrackerItem item) {
@@ -423,6 +423,7 @@ void Settings::CreateOptions() {
});
OPT_U8(RSK_BOMBCHU_BAG, "Bombchu Bag", {"None", "Single Bag", "Progressive Bags"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("BombchuBag"), mOptionDescriptions[RSK_BOMBCHU_BAG], WIDGET_CVAR_COMBOBOX, RO_BOMBCHU_BAG_NONE);
OPT_U8(RSK_ENABLE_BOMBCHU_DROPS, "Bombchu Drops", {"No", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("EnableBombchuDrops"), mOptionDescriptions[RSK_ENABLE_BOMBCHU_DROPS], WIDGET_CVAR_COMBOBOX, RO_AMMO_DROPS_ON);
OPT_BOOL(RSK_PROGRESSIVE_GORON_SWORD, "Progressive Goron Sword", CVAR_RANDOMIZER_SETTING("ProgressiveGoronSword"), mOptionDescriptions[RSK_PROGRESSIVE_GORON_SWORD]);
// TODO: AmmoDrops and/or HeartDropRefill, combine with/separate Ammo Drops from Bombchu Drops?
// Triforce Hunt: the total piece count is the on/off control. Zero disables the hunt entirely; any
// positive value adds that many Triforce Pieces to the pool and unlocks the pieces-location option.
@@ -2116,6 +2117,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_ROCS_FEATHER],
&mOptions[RSK_BOMBCHU_BAG],
&mOptions[RSK_ENABLE_BOMBCHU_DROPS],
&mOptions[RSK_PROGRESSIVE_GORON_SWORD],
&mOptions[RSK_INFINITE_UPGRADES],
&mOptions[RSK_SKELETON_KEY],
},
@@ -2305,6 +2307,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_100_GS_REWARD],
&mOptions[RSK_SHUFFLE_BEAN_SOULS],
&mOptions[RSK_ROCS_FEATHER],
&mOptions[RSK_PROGRESSIVE_GORON_SWORD],
&mOptions[RSK_SHUFFLE_BOSS_SOULS],
&mOptions[RSK_SHUFFLE_DEKU_STICK_BAG],
&mOptions[RSK_SHUFFLE_DEKU_NUT_BAG],