From 4ffdc0b2f971349df9f13b3b21e1c1dab0f4697e Mon Sep 17 00:00:00 2001 From: rozlette Date: Sun, 8 Dec 2024 00:22:33 -0600 Subject: [PATCH] RBA and BA --- soh/soh/SohMenuBar.cpp | 2 - soh/src/code/z_parameter.c | 294 +++++++++++++++++++++++++++++++++++-- 2 files changed, 281 insertions(+), 15 deletions(-) diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index a6cbd2d81..1798cc643 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -1551,8 +1551,6 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Restore pre-release behavior where defeating a Gold Skulltula will play a cutscene showing it die."); UIWidgets::PaddedEnhancementCheckbox("Quick Bongo Kill", CVAR_ENHANCEMENT("QuickBongoKill"), true, false); UIWidgets::Tooltip("Restore a bug from NTSC 1.0 that allows bypassing Bongo Bongo's intro cutscene to quickly kill him"); - UIWidgets::PaddedEnhancementCheckbox("Original RBA Values", CVAR_ENHANCEMENT("RestoreRBAValues"), true, false); - UIWidgets::Tooltip("Restores the original outcomes when performing Reverse Bottle Adventure."); UIWidgets::PaddedEnhancementCheckbox("Early Eyeball Frog", CVAR_ENHANCEMENT("EarlyEyeballFrog"), true, false); UIWidgets::Tooltip("Restores a bug from NTSC 1.0/1.1 that allows you to obtain the eyeball frog from King Zora instead of the Zora Tunic by holding shield."); diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index d2c3e1a26..c6ec78b9e 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1439,6 +1439,140 @@ Gfx* Gfx_TextureI8(Gfx* displayListHead, void* texture, s16 textureWidth, s16 te return displayListHead; } +void Inventory_DoBA(u8 cRight) { + if (cRight >= ITEM_STICK && cRight <= ITEM_POTION_BLUE) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.items[cRight]; + } else if (cRight >= ITEM_FAIRY && cRight <= ITEM_MASK_BUNNY) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.ammo[cRight - ITEM_FAIRY]; + } else if (cRight == ITEM_MASK_GORON) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.equipment >> 8) & 0xFF; + } else if (cRight == ITEM_MASK_ZORA) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.equipment & 0xFF; + } else if (cRight == ITEM_MASK_GERUDO || cRight == ITEM_MASK_TRUTH) { + // ITEM_MASK_GERUDO and ITEM_MASK_TRUTH land in padding bytes + gSaveContext.equips.buttonItems[0] = 0; + } else if (cRight == ITEM_SOLD_OUT) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.upgrades >> 24) & 0xFF; + } else if (cRight == ITEM_POCKET_EGG) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.upgrades >> 16) & 0xFF; + } else if (cRight == ITEM_POCKET_CUCCO) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.upgrades >> 8) & 0xFF; + } else if (cRight == ITEM_COJIRO) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.upgrades & 0xFF; + } else if (cRight == ITEM_ODD_MUSHROOM) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.questItems >> 24) & 0xFF; + } else if (cRight == ITEM_ODD_POTION) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.questItems >> 16) & 0xFF; + } else if (cRight == ITEM_SAW) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.questItems >> 8) & 0xFF; + } else if (cRight == ITEM_SWORD_BROKEN) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.questItems & 0xFF; + } else if (cRight >= ITEM_PRESCRIPTION && cRight <= ITEM_BULLET_BAG_30) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.dungeonItems[cRight - ITEM_PRESCRIPTION]; + } else if (cRight >= ITEM_BULLET_BAG_40 && cRight <= ITEM_SWORD_KNIFE) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.dungeonKeys[cRight - ITEM_BULLET_BAG_40]; + } else if (cRight == ITEM_SONG_BOLERO) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.defenseHearts; + } else if (cRight == ITEM_SONG_SERENADE) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.gsTokens >> 8) & 0xFF; + } else if (cRight == ITEM_SONG_REQUIEM) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.gsTokens & 0xFF; + } else if (cRight == ITEM_SONG_NOCTURNE || cRight == ITEM_SONG_PRELUDE) { + // ITEM_SONG_NOCTURNE and ITEM_SONG_PRELUDE land in padding bytes + gSaveContext.equips.buttonItems[0] = 0; + } else if (cRight >= ITEM_SONG_LULLABY) { + // The rest of the items fall into the saved scene flags. Let's calculate the scene and which field it pulls from + u32 offset = cRight - ITEM_SONG_LULLABY; + u32 scene = offset / sizeof(SavedSceneFlags); + switch (offset % sizeof(SavedSceneFlags)) { + case 0: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].chest >> 24) & 0xFF; + break; + case 1: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].chest >> 16) & 0xFF; + break; + case 2: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].chest >> 8) & 0xFF; + break; + case 3: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].chest & 0xFF; + break; + case 4: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].swch >> 24) & 0xFF; + break; + case 5: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].swch >> 16) & 0xFF; + break; + case 6: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].swch >> 8) & 0xFF; + break; + case 7: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].swch & 0xFF; + break; + case 8: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].clear >> 24) & 0xFF; + break; + case 9: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].clear >> 16) & 0xFF; + break; + case 10: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].clear >> 8) & 0xFF; + break; + case 11: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].clear & 0xFF; + break; + case 12: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].collect >> 24) & 0xFF; + break; + case 13: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].collect >> 16) & 0xFF; + break; + case 14: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].collect >> 8) & 0xFF; + break; + case 15: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].collect & 0xFF; + break; + case 16: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].unk >> 24) & 0xFF; + break; + case 17: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].unk >> 16) & 0xFF; + break; + case 18: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].unk >> 8) & 0xFF; + break; + case 19: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].unk & 0xFF; + break; + case 20: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].rooms >> 24) & 0xFF; + break; + case 21: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].rooms >> 16) & 0xFF; + break; + case 22: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].rooms >> 8) & 0xFF; + break; + case 23: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].rooms & 0xFF; + break; + case 24: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].floors >> 24) & 0xFF; + break; + case 25: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].floors >> 16) & 0xFF; + break; + case 26: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].floors >> 8) & 0xFF; + break; + case 27: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].floors & 0xFF; + break; + } + } +} + void Rando_Inventory_SwapAgeEquipment(void) { s16 i; u16 shieldEquipValue; @@ -1518,8 +1652,13 @@ void Rando_Inventory_SwapAgeEquipment(void) { (gSaveContext.equips.buttonItems[i] <= ITEM_POE)) || ((gSaveContext.equips.buttonItems[i] >= ITEM_WEIRD_EGG) && (gSaveContext.equips.buttonItems[i] <= ITEM_CLAIM_CHECK))) { - gSaveContext.equips.buttonItems[i] = - gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[i - 1]]; + if (i == 0) { + // If bottle is on B, it triggers BA, which we need to recreate + Inventory_DoBA(gSaveContext.equips.buttonItems[3]); + } else { + gSaveContext.equips.buttonItems[i] = + gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[i - 1]]; + } } } @@ -1675,8 +1814,13 @@ void Inventory_SwapAgeEquipment(void) { ((gSaveContext.equips.buttonItems[i] >= ITEM_WEIRD_EGG) && (gSaveContext.equips.buttonItems[i] <= ITEM_CLAIM_CHECK))) { osSyncPrintf("Register_Item_Pt(%d)=%d\n", i, gSaveContext.equips.cButtonSlots[i - 1]); - gSaveContext.equips.buttonItems[i] = - gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[i - 1]]; + if (i == 0) { + // If bottle is on B, it triggers BA, which we need to recreate + Inventory_DoBA(gSaveContext.equips.buttonItems[3]); + } else { + gSaveContext.equips.buttonItems[i] = + gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[i - 1]]; + } } } @@ -2699,11 +2843,136 @@ s32 Inventory_HasSpecificBottle(u8 bottleItem) { } } -void byteSwapInventory() { - gSaveContext.inventory.equipment = BE16SWAP(gSaveContext.inventory.equipment); - gSaveContext.inventory.upgrades = BE32SWAP(gSaveContext.inventory.upgrades); - gSaveContext.inventory.questItems = BE32SWAP(gSaveContext.inventory.questItems); - gSaveContext.inventory.gsTokens = BE16SWAP(gSaveContext.inventory.gsTokens); +void Inventory_DoRBA(u8 cRight, u8 item) { + if (cRight >= ITEM_STICK && cRight <= ITEM_POTION_BLUE) { + gSaveContext.inventory.items[cRight] = item; + } else if (cRight >= ITEM_FAIRY && cRight <= ITEM_MASK_BUNNY) { + gSaveContext.inventory.ammo[cRight - ITEM_FAIRY] = item; + } else if (cRight == ITEM_MASK_GORON) { + gSaveContext.inventory.equipment = (item << 8) | (gSaveContext.inventory.equipment & 0x00FF); + } else if (cRight == ITEM_MASK_ZORA) { + gSaveContext.inventory.equipment = item | (gSaveContext.inventory.equipment & 0xFF00); + } + // ITEM_MASK_GERUDO and ITEM_MASK_TRUTH land in padding bytes + else if (cRight == ITEM_SOLD_OUT) { + gSaveContext.inventory.upgrades = (item << 24) | (gSaveContext.inventory.upgrades & 0x00FFFFFF); + } else if (cRight == ITEM_POCKET_EGG) { + gSaveContext.inventory.upgrades = (item << 16) | (gSaveContext.inventory.upgrades & 0xFF00FFFF); + } else if (cRight == ITEM_POCKET_CUCCO) { + gSaveContext.inventory.upgrades = (item << 8) | (gSaveContext.inventory.upgrades & 0xFFFF00FF); + } else if (cRight == ITEM_COJIRO) { + gSaveContext.inventory.upgrades = item | (gSaveContext.inventory.upgrades & 0xFFFFFF00); + } else if (cRight == ITEM_ODD_MUSHROOM) { + gSaveContext.inventory.questItems = (item << 24) | (gSaveContext.inventory.questItems & 0x00FFFFFF); + } else if (cRight == ITEM_ODD_POTION) { + gSaveContext.inventory.questItems = (item << 16) | (gSaveContext.inventory.questItems & 0xFF00FFFF); + } else if (cRight == ITEM_SAW) { + gSaveContext.inventory.questItems = (item << 8) | (gSaveContext.inventory.questItems & 0xFFFF00FF); + } else if (cRight == ITEM_SWORD_BROKEN) { + gSaveContext.inventory.questItems = item | (gSaveContext.inventory.questItems & 0xFFFFFF00); + } else if (cRight >= ITEM_PRESCRIPTION && cRight <= ITEM_BULLET_BAG_30) { + gSaveContext.inventory.dungeonItems[cRight - ITEM_PRESCRIPTION] = item; + } else if (cRight >= ITEM_BULLET_BAG_40 && cRight <= ITEM_SWORD_KNIFE) { + gSaveContext.inventory.dungeonKeys[cRight - ITEM_BULLET_BAG_40] = item; + } else if (cRight == ITEM_SONG_BOLERO) { + gSaveContext.inventory.defenseHearts = item; + } else if (cRight == ITEM_SONG_SERENADE) { + gSaveContext.inventory.gsTokens = (item << 8) | (gSaveContext.inventory.gsTokens & 0x00FF); + } else if (cRight == ITEM_SONG_REQUIEM) { + gSaveContext.inventory.gsTokens = item | (gSaveContext.inventory.gsTokens & 0xFF00); + } + // ITEM_SONG_NOCTURNE and ITEM_SONG_PRELUDE land in padding bytes + else if (cRight >= ITEM_SONG_LULLABY) { + // The rest of the items fall into the saved scene flags. Let's calculate the scene and which field it sets + u32 offset = cRight - ITEM_SONG_LULLABY; + u32 scene = offset / sizeof(SavedSceneFlags); + switch (offset % sizeof(SavedSceneFlags)) { + case 0: + gSaveContext.sceneFlags[scene].chest = (item << 24) | (gSaveContext.sceneFlags[scene].chest & 0x00FFFFFF); + break; + case 1: + gSaveContext.sceneFlags[scene].chest = (item << 16) | (gSaveContext.sceneFlags[scene].chest & 0xFF00FFFF); + break; + case 2: + gSaveContext.sceneFlags[scene].chest = (item << 8) | (gSaveContext.sceneFlags[scene].chest & 0xFFFF00FF); + break; + case 3: + gSaveContext.sceneFlags[scene].chest = item | (gSaveContext.sceneFlags[scene].chest & 0xFFFFFF00); + break; + case 4: + gSaveContext.sceneFlags[scene].swch = (item << 24) | (gSaveContext.sceneFlags[scene].swch & 0x00FFFFFF); + break; + case 5: + gSaveContext.sceneFlags[scene].swch = (item << 16) | (gSaveContext.sceneFlags[scene].swch & 0xFF00FFFF); + break; + case 6: + gSaveContext.sceneFlags[scene].swch = (item << 8) | (gSaveContext.sceneFlags[scene].swch & 0xFFFF00FF); + break; + case 7: + gSaveContext.sceneFlags[scene].swch = item | (gSaveContext.sceneFlags[scene].swch & 0xFFFFFF00); + break; + case 8: + gSaveContext.sceneFlags[scene].clear = (item << 24) | (gSaveContext.sceneFlags[scene].clear & 0x00FFFFFF); + break; + case 9: + gSaveContext.sceneFlags[scene].clear = (item << 16) | (gSaveContext.sceneFlags[scene].clear & 0xFF00FFFF); + break; + case 10: + gSaveContext.sceneFlags[scene].clear = (item << 8) | (gSaveContext.sceneFlags[scene].clear & 0xFFFF00FF); + break; + case 11: + gSaveContext.sceneFlags[scene].clear = item | (gSaveContext.sceneFlags[scene].clear & 0xFFFFFF00); + break; + case 12: + gSaveContext.sceneFlags[scene].collect = (item << 24) | (gSaveContext.sceneFlags[scene].collect & 0x00FFFFFF); + break; + case 13: + gSaveContext.sceneFlags[scene].collect = (item << 16) | (gSaveContext.sceneFlags[scene].collect & 0xFF00FFFF); + break; + case 14: + gSaveContext.sceneFlags[scene].collect = (item << 8) | (gSaveContext.sceneFlags[scene].collect & 0xFFFF00FF); + break; + case 15: + gSaveContext.sceneFlags[scene].collect = item | (gSaveContext.sceneFlags[scene].collect & 0xFFFFFF00); + break; + case 16: + gSaveContext.sceneFlags[scene].unk = (item << 24) | (gSaveContext.sceneFlags[scene].unk & 0x00FFFFFF); + break; + case 17: + gSaveContext.sceneFlags[scene].unk = (item << 16) | (gSaveContext.sceneFlags[scene].unk & 0xFF00FFFF); + break; + case 18: + gSaveContext.sceneFlags[scene].unk = (item << 8) | (gSaveContext.sceneFlags[scene].unk & 0xFFFF00FF); + break; + case 19: + gSaveContext.sceneFlags[scene].unk = item | (gSaveContext.sceneFlags[scene].unk & 0xFFFFFF00); + break; + case 20: + gSaveContext.sceneFlags[scene].rooms = (item << 24) | (gSaveContext.sceneFlags[scene].rooms & 0x00FFFFFF); + break; + case 21: + gSaveContext.sceneFlags[scene].rooms = (item << 16) | (gSaveContext.sceneFlags[scene].rooms & 0xFF00FFFF); + break; + case 22: + gSaveContext.sceneFlags[scene].rooms = (item << 8) | (gSaveContext.sceneFlags[scene].rooms & 0xFFFF00FF); + break; + case 23: + gSaveContext.sceneFlags[scene].rooms = item | (gSaveContext.sceneFlags[scene].rooms & 0xFFFFFF00); + break; + case 24: + gSaveContext.sceneFlags[scene].floors = (item << 24) | (gSaveContext.sceneFlags[scene].floors & 0x00FFFFFF); + break; + case 25: + gSaveContext.sceneFlags[scene].floors = (item << 16) | (gSaveContext.sceneFlags[scene].floors & 0xFF00FFFF); + break; + case 26: + gSaveContext.sceneFlags[scene].floors = (item << 8) | (gSaveContext.sceneFlags[scene].floors & 0xFFFF00FF); + break; + case 27: + gSaveContext.sceneFlags[scene].floors = item | (gSaveContext.sceneFlags[scene].floors & 0xFFFFFF00); + break; + } + } } void Inventory_UpdateBottleItem(PlayState* play, u8 item, u8 button) { @@ -2717,10 +2986,9 @@ void Inventory_UpdateBottleItem(PlayState* play, u8 item, u8 button) { item = ITEM_MILK_HALF; } - if (CVarGetInteger(CVAR_ENHANCEMENT("RestoreRBAValues"),0)) { - byteSwapInventory(); - gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[button - 1]] = item; - byteSwapInventory(); + if (button == 0) { + // If bottle is on B, it triggers RBA, which we need to recreate + Inventory_DoRBA(gSaveContext.equips.buttonItems[3], item); } else { gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[button - 1]] = item; }