shithub: zelda3

Download patch

ref: 9d5a90cd6630e5be07a0a1523643eee00fd51d05
parent: a363cda13240b649fdd3b983e94897775dd8c92f
author: Snesrev <snesrev@protonmail.com>
date: Wed Sep 21 15:11:45 EDT 2022

Secondary item slot on button X
 - Allows two items to be used at a time
 - Hold X on item screen to select the secondary item
 - Push Select to show map
 - Push Select on the item menu to show the old Select menu

--- a/dungeon.c
+++ b/dungeon.c
@@ -14,6 +14,7 @@
 #include "player_oam.h"
 #include "tables/generated_dungeon_rooms.h"
 #include "tagalong.h"
+#include "messaging.h"
 
 // todo: move to config
 static const uint16 kBossRooms[] = {
@@ -6583,32 +6584,26 @@
 
 void Module07_00_PlayerControl() {  // 8288de
   if (!(flag_custom_spell_anim_active | flag_is_link_immobilized | flag_block_link_menu)) {
-    if (filtered_joypad_H & 0x10) {
+    if (filtered_joypad_H & 0x10) {  // start
       overworld_map_state = 0;
       submodule_index = 1;
       saved_module_for_menu = main_module_index;
       main_module_index = 14;
       return;
-    }
-    if (filtered_joypad_L & 0x40 && (uint8)cur_palace_index_x2 != 0xff && (uint8)dungeon_room_index) {
-      overworld_map_state = 0;
-      submodule_index = 3;
-      saved_module_for_menu = main_module_index;
-      main_module_index = 14;
-      return;
-    }
-    if (joypad1H_last & 0x20 && sram_progress_indicator) {
-      choice_in_multiselect_box_bak = choice_in_multiselect_box;
-      dialogue_message_index = 0x186;
-      uint8 bak = main_module_index;
-      Main_ShowTextMessage();
-      main_module_index = bak;
-      subsubmodule_index = 0;
-      overworld_map_state = 0;
-      submodule_index = 11;
-      saved_module_for_menu = main_module_index;
-      main_module_index = 14;
-      return;
+    } else if (DidPressButtonForMap()) {  // x
+      if ((uint8)cur_palace_index_x2 != 0xff && (uint8)dungeon_room_index) {
+        overworld_map_state = 0;
+        submodule_index = 3;
+        saved_module_for_menu = main_module_index;
+        main_module_index = 14;
+        return;
+      }
+    } else if (joypad1H_last & 0x20) {  // select
+      if (sram_progress_indicator) {
+        overworld_map_state = 0;
+        DisplaySelectMenu();
+        return;
+      }
     }
     Hud_HandleItemSwitchInputs();
   }
--- a/hud.c
+++ b/hud.c
@@ -1,13 +1,8 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <assert.h>
+#include "hud.h"
 #include "zelda_rtl.h"
 
 #include "variables.h"
-#include "hud.h"
+#include "messaging.h"
 
 enum {
   kNewStyleInventory = 0,
@@ -19,7 +14,13 @@
 } ItemBoxGfx;
 
 static void Hud_DrawItem(uint16 *dst, const ItemBoxGfx *src);
+static bool Hud_DoWeHaveThisItem(uint8 item);
+static void Hud_EquipPrevItem(uint8 *item);
+static void Hud_EquipNextItem(uint8 *item);
+static int Hud_GetItemPosition(int item);
+static void Hud_ReorderItem(int direction);
 
+
 const uint8 kMaxBombsForLevel[] = { 10, 15, 20, 25, 30, 35, 40, 50 };
 const uint8 kMaxArrowsForLevel[] = { 30, 35, 40, 45, 50, 55, 60, 70 };
 static const uint8 kMaxHealthForLevel[] = { 9, 9, 9, 9, 9, 9, 9, 9, 17, 17, 17, 17, 17, 17, 17, 25, 25, 25, 25, 25, 25 };
@@ -224,8 +225,6 @@
 static const uint16 kDungFloorIndicator_Gfx0[11] = { 0x2508, 0x2509, 0x2509, 0x250a, 0x250b, 0x250c, 0x250d, 0x251d, 0xe51c, 0x250e, 0x7f };
 static const uint16 kDungFloorIndicator_Gfx1[11] = { 0x2518, 0x2519, 0xa509, 0x251a, 0x251b, 0x251c, 0x2518, 0xa51d, 0xe50c, 0xa50e, 0x7f };
 
-static int Hud_GetCurrentItemPosition();
-static void Hud_ReorderItem(int direction);
 
 void Hud_RefreshIcon() {
   Hud_SearchForEquippedItem();
@@ -252,34 +251,36 @@
   }
 }
 
-// Returns the zero based index of the currently selected hud item
-static int Hud_GetCurrentItemPosition() {
+// Returns the zero based index of the currently selected hud item,
+// or -1 if the item is item 0.
+static int Hud_GetItemPosition(int item) {
+  if (item <= 0)
+    return -1;
   if (hud_inventory_order[0] != 0) {
     int i = 0;
-    for (; i < kHudItemCount - 1 && hud_inventory_order[i] != hud_cur_item; i++) {}
+    for (; i < kHudItemCount - 1 && hud_inventory_order[i] != item; i++) {}
     return i;
   } else {
-    return hud_cur_item ? hud_cur_item - 1 : hud_cur_item;
+    return item ? item - 1 : item;
   }
 }
 
-void Hud_GotoPrevItem() {
+static void Hud_GotoPrevItem(uint8 *item, uint8 first_item_index) {
   if (hud_inventory_order[0] != 0) {
-    int i = Hud_GetCurrentItemPosition();
-    hud_cur_item = hud_inventory_order[i == 0 ? kHudItemCount - 1 : i - 1];
+    int pos = Hud_GetItemPosition(*item);
+    *item = (pos == 0 && !first_item_index) ? 0 :
+        hud_inventory_order[(pos <= 0 ? kHudItemCount : pos) - 1];
   } else {
-    if (--hud_cur_item < 1)
-      hud_cur_item = kHudItemCount;
+    *item = (*item > first_item_index) ? *item - 1 : kHudItemCount;
   }
 }
 
-void Hud_GotoNextItem() {
+static void Hud_GotoNextItem(uint8 *item, uint8 first_item_index) {
   if (hud_inventory_order[0] != 0) {
-    int i = Hud_GetCurrentItemPosition();
-    hud_cur_item = hud_inventory_order[i >= kHudItemCount - 1 ? 0 : i + 1];
+    int i = Hud_GetItemPosition(*item);
+    *item = hud_inventory_order[((uint)i >= kHudItemCount - 1) ? 0 : i + 1];
   } else {
-    if (++hud_cur_item > kHudItemCount)
-      hud_cur_item = 1;
+    *item = (*item < kHudItemCount) ? *item + 1 : first_item_index;
   }
 }
 
@@ -472,10 +473,10 @@
 }
 
 bool Hud_HaveAnyItems() { // new
-  uint8 or_all = 0;
   for (int i = 0; i < 20; i++)
-    or_all |= (&link_item_bow)[i];
-  return or_all != 0;
+    if ((&link_item_bow)[i])
+      return true;
+  return false;
 }
 
 void Hud_Init() {  // 8dddab
@@ -484,20 +485,9 @@
   Hud_DrawAbilityBox();
   Hud_DrawProgressIcons();
   Hud_DrawEquipmentBox();
+  Hud_DrawSelectedYButtonItem();
 
-  if (Hud_HaveAnyItems()) {
-    int first_bottle = 0;
-    while (first_bottle < 4 && link_bottle_info[first_bottle] == 0)
-      first_bottle++;
-    if (first_bottle == 4)
-      link_item_bottle_index = 0;
-    else if (link_item_bottle_index == 0)
-      link_item_bottle_index = first_bottle + 1;
-
-    if (!Hud_DoWeHaveThisItem())
-      Hud_EquipNextItem();
-
-    Hud_DrawSelectedYButtonItem();
+  if (Hud_HaveAnyItems()) {    
     if (hud_cur_item == kHudItem_BottleOld && !kNewStyleInventory) {
       timer_for_flashing_circle = 16;
       Hud_DrawBottleMenu();
@@ -520,10 +510,10 @@
   if (Hud_HaveAnyItems()) {
     nmi_subroutine_index = 1;
     BYTE(nmi_load_target_addr) = 0x22;
-    if (!Hud_DoWeHaveThisItem())
-      Hud_EquipNextItem();
 
     Hud_DrawSelectedYButtonItem();
+
+    // Pick either the bottle state or normal one
     overworld_map_state = (hud_cur_item == kHudItem_BottleOld && !kNewStyleInventory) ? 10 : 4;
   } else {
     if (filtered_joypad_H)
@@ -531,45 +521,46 @@
   }
 }
 
-bool Hud_DoWeHaveThisItem() {  // 8ddeb0
-  assert(hud_cur_item != 0);
+static bool Hud_DoWeHaveThisItem(uint8 item) {  // 8ddeb0
+  if (item == 0)
+    return true;  // for the x item, 0 is valid
 
-  if (hud_cur_item == kHudItem_Flute && kNewStyleInventory)
+  if (item == kHudItem_Flute && kNewStyleInventory)
     return link_item_flute >= 2;
 
-  if (hud_cur_item == kHudItem_Shovel && kNewStyleInventory)
+  if (item == kHudItem_Shovel && kNewStyleInventory)
     return link_item_flute >= 1;
 
-  if (hud_cur_item >= kHudItem_Bottle1)
-    return link_bottle_info[hud_cur_item - kHudItem_Bottle1] != 0;
+  if (item >= kHudItem_Bottle1)
+    return link_bottle_info[item - kHudItem_Bottle1] != 0;
 
-  return (&link_item_bow)[hud_cur_item - 1] != 0;
+  return (&link_item_bow)[item - 1] != 0;
 }
 
-void Hud_EquipPrevItem() {  // 8dded9
+static void Hud_EquipPrevItem(uint8 *item) {  // 8dded9
   do {
-    Hud_GotoPrevItem();
-  } while (!Hud_DoWeHaveThisItem());
+    Hud_GotoPrevItem(item, item == &hud_cur_item);
+  } while (!Hud_DoWeHaveThisItem(*item));
 }
 
-void Hud_EquipNextItem() {  // 8ddee2
+static void Hud_EquipNextItem(uint8 *item) {  // 8ddee2
   do {
-    Hud_GotoNextItem();
-  } while (!Hud_DoWeHaveThisItem());
+    Hud_GotoNextItem(item, item == &hud_cur_item);
+  } while (!Hud_DoWeHaveThisItem(*item));
 }
 
-void Hud_EquipItemAbove() {  // 8ddeeb
+static void Hud_EquipItemAbove(uint8 *item) {  // 8ddeeb
   do {
     for(int i = 0; i < (kNewStyleInventory ? 6 : 5); i++)
-      Hud_GotoPrevItem();
-  } while (!Hud_DoWeHaveThisItem());
+      Hud_GotoPrevItem(item, 1);
+  } while (!Hud_DoWeHaveThisItem(*item));
 }
 
-void Hud_EquipItemBelow() {  // 8ddf00
+static void Hud_EquipItemBelow(uint8 *item) {  // 8ddf00
   do {
     for (int i = 0; i < (kNewStyleInventory ? 6 : 5); i++)
-      Hud_GotoNextItem();
-  } while (!Hud_DoWeHaveThisItem());
+      Hud_GotoNextItem(item, 1);
+  } while (!Hud_DoWeHaveThisItem(*item));
 }
 
 void Hud_NormalMenu() {  // 8ddf15
@@ -577,13 +568,21 @@
   if (!BYTE(joypad1H_last))
     BYTE(tmp1) = 0;
 
-  if (filtered_joypad_H & 0x10) {
+  if (filtered_joypad_H & 0x10) {  // start
     overworld_map_state = 5;
     sound_effect_2 = 18;
     return;
   }
 
-  if (joypad1H_last & 0x40 && enhanced_features0 & kFeatures0_SwitchLR) {
+  // Allow select to open the save/exit thing
+  if (joypad1H_last & 0x20 && sram_progress_indicator) {  // select
+    BG3VOFS_copy2 = -8;
+    Hud_CloseMenu();
+    DisplaySelectMenu();
+    return;
+  }
+
+  if (joypad1H_last & 0x40 && !(joypad1L_last & 0x40) && (enhanced_features0 & kFeatures0_SwitchLR)) {
     if (filtered_joypad_H & 8) {
       Hud_ReorderItem(kNewStyleInventory ? -6 : -5);
     } else if (filtered_joypad_H & 4) {
@@ -594,18 +593,20 @@
       Hud_ReorderItem(1);
     }
   } else if (!BYTE(tmp1)) {
-    uint16 old_item = hud_cur_item;
+    // If the x button is down, then move the blue circle
+    uint8 *item_p = (joypad1L_last & 0x40 && (enhanced_features0 & kFeatures0_SwitchLR)) ? &hud_cur_item_x : &hud_cur_item;
+    uint16 old_item = *item_p;
     if (filtered_joypad_H & 8) {
-      Hud_EquipItemAbove();
+      Hud_EquipItemAbove(item_p);
     } else if (filtered_joypad_H & 4) {
-      Hud_EquipItemBelow();
+      Hud_EquipItemBelow(item_p);
     } else if (filtered_joypad_H & 2) {
-      Hud_EquipPrevItem();
+      Hud_EquipPrevItem(item_p);
     } else if (filtered_joypad_H & 1) {
-      Hud_EquipNextItem();
+      Hud_EquipNextItem(item_p);
     }
     BYTE(tmp1) = filtered_joypad_H;
-    if (hud_cur_item != old_item) {
+    if (*item_p != old_item) {
       timer_for_flashing_circle = 16;
       sound_effect_2 = 32;
     }
@@ -626,9 +627,9 @@
   Hud_UpdateEquippedItem();
 }
 
-void Hud_UpdateEquippedItem() {  // 8ddfaf
-  static const uint8 kHudItemToItemOrg[21] = { 
-    0, 
+uint8 Hud_LookupInventoryItem(uint8 item) {
+  static const uint8 kHudItemToItemOrg[21] = {
+    0,
     3,  2, 14, 1,  10,  5,
     6, 15, 16, 17,  9,  4,
     8,  7, 12, 11, 18, 13,
@@ -642,12 +643,16 @@
     8,  7, 12, 21, 18, 13, // 8 is ocarina / shovel combined. moved shovel to 21.
     19, 20,11, 11, 11, 11, // 11 means bottle
   };
+  return kNewStyleInventory ? kHudItemToItemNew[item] : kHudItemToItemOrg[item];
+}
 
+void Hud_UpdateEquippedItem() {  // 8ddfaf
+
   if (hud_cur_item >= kHudItem_Bottle1)
     link_item_bottle_index = hud_cur_item - kHudItem_Bottle1 + 1;
 
   assert(hud_cur_item < 25);
-  current_item_y = kNewStyleInventory ? kHudItemToItemNew[hud_cur_item] : kHudItemToItemOrg[hud_cur_item];
+  current_item_y = Hud_LookupInventoryItem(hud_cur_item);
 }
 
 void Hud_CloseMenu() {  // 8ddfba
@@ -712,9 +717,9 @@
     overworld_map_state = 5;
   } else if (filtered_joypad_H & 3) {
     if (filtered_joypad_H & 2) {
-      Hud_EquipPrevItem();
+      Hud_EquipPrevItem(&hud_cur_item);
     } else {
-      Hud_EquipNextItem();
+      Hud_EquipNextItem(&hud_cur_item);
     }
     timer_for_flashing_circle = 16;
     sound_effect_2 = 32;
@@ -793,19 +798,20 @@
   }
 }
 
-static void Hud_DrawFlashingCircle(uint16 *p) {  // new
-  p[HUDXY(0, -1)] = 0x3C61;
-  p[HUDXY(1, -1)] = 0x3C61 | 0x4000;
-  p[HUDXY(-1, 0)] = 0x3C70;
-  p[HUDXY(2, 0)] = 0x3C70 | 0x4000;
-  p[HUDXY(-1, 1)] = 0xBC70;
-  p[HUDXY(2, 1)] = 0xBC70 | 0x4000;
-  p[HUDXY(0, 2)] = 0xBC61;
-  p[HUDXY(1, 2)] = 0xBC61 | 0x4000;
-  p[HUDXY(-1, -1)] = 0x3C60;
-  p[HUDXY(2, -1)] = 0x3C60 | 0x4000;
-  p[HUDXY(2, 2)] = 0x3C60 | 0xC000;
-  p[HUDXY(-1, 2)] = 0x3C60 | 0x8000;
+static void Hud_DrawFlashingCircle(uint16 *p, uint8 palette) {  // new
+  int pp = palette << 10;
+  p[HUDXY(0, -1)] = pp | 0x2061;
+  p[HUDXY(1, -1)] = pp | 0x2061 | 0x4000;
+  p[HUDXY(-1, 0)] = pp | 0x2070;
+  p[HUDXY(2, 0)] = pp | 0x2070 | 0x4000;
+  p[HUDXY(-1, 1)] = pp | 0xa070;
+  p[HUDXY(2, 1)] = pp | 0xa070 | 0x4000;
+  p[HUDXY(0, 2)] = pp | 0xa061;
+  p[HUDXY(1, 2)] = pp | 0xa061 | 0x4000;
+  p[HUDXY(-1, -1)] = pp | 0x2060;
+  p[HUDXY(2, -1)] = pp | 0x2060 | 0x4000;
+  p[HUDXY(2, 2)] = pp | 0x2060 | 0xC000;
+  p[HUDXY(-1, 2)] = pp | 0x2060 | 0x8000;
 }
 
 void Hud_DrawBottleMenu() {  // 8def67
@@ -816,7 +822,7 @@
   const ItemBoxGfx *p = &kHudItemBottles[link_bottle_info[link_item_bottle_index - 1]];
   Hud_DrawItem(uvram_screen.row[0].col + kHudItemInVramPtr[15], p);
   if (timer_for_flashing_circle & 0x10)
-    Hud_DrawFlashingCircle(dst + HUDXY(25, 13 + (link_item_bottle_index - 1) * 4));
+    Hud_DrawFlashingCircle(dst + HUDXY(25, 13 + (link_item_bottle_index - 1) * 4), 7);
 }
 
 
@@ -848,6 +854,14 @@
 }
 
 void Hud_SearchForEquippedItem() {  // 8de399
+  int first_bottle = 0;
+  while (first_bottle < 4 && link_bottle_info[first_bottle] == 0)
+    first_bottle++;
+  if (first_bottle == 4)
+    link_item_bottle_index = 0;
+  else if (link_item_bottle_index == 0)
+    link_item_bottle_index = first_bottle + 1;
+
   if (!Hud_HaveAnyItems()) {
     hud_cur_item = 0;
     hud_var1 = 0;
@@ -854,8 +868,8 @@
   } else {
     if (!hud_cur_item)
       hud_cur_item = 1;
-    if (!Hud_DoWeHaveThisItem())
-      Hud_EquipNextItem();
+    if (!Hud_DoWeHaveThisItem(hud_cur_item))
+      Hud_EquipNextItem(&hud_cur_item);
   }
 }
 
@@ -880,11 +894,18 @@
   uint16 *dst = uvram_screen.row[0].col;
   int x = kNewStyleInventory ? 0 : 1;
 
-  Hud_DrawBox(dst, x, 5, 20 - x, 19, 7);
+  bool is_x = (joypad1L_last & 0x40 && (enhanced_features0 & kFeatures0_SwitchLR));
+  uint8 palette = is_x ? 3 : 7;
+  Hud_DrawBox(dst, x, 5, 20 - x, 19, palette);
 
   if (!kNewStyleInventory) {
-    dst[HUDXY(2, 6)] = 0x3CF0;
-    dst[HUDXY(2, 7)] = 0x3CF1;
+    if (palette == 3) {
+      dst[HUDXY(2, 6)] = 0x2CF0;
+      dst[HUDXY(2, 7)] = 0x2CF0 | 0x8000;
+    } else {
+      dst[HUDXY(2, 6)] = 0x3CF0;
+      dst[HUDXY(2, 7)] = 0x3CF1;
+    }
   }
   dst[HUDXY(x + 2, 5)] = 0x246E;
   dst[HUDXY(x + 3, 5)] = 0x246F;
@@ -1061,7 +1082,8 @@
     0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x2555, 0x255b, 0x2564, 0x2563, 0x2554, 0x24f5, 0x24f5, 0x24f5
   };
   static const uint16 kHudMirrorItemText[16] = {
-    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x255c, 0x2558, 0x2561, 0x2561, 0x255e, 0x2561
+    0x255c, 0x2550, 0x2556, 0x2558, 0x2552, 0x24f5, 0x24f5, 0x24f5,
+    0x24f5, 0x24f5, 0x255c, 0x2558, 0x2561, 0x2561, 0x255e, 0x2561
   };
   static const uint16 kHudBowItemText[48] = {
     0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x256b, 0x256c, 0x256e, 0x256f, 0x257c, 0x257d, 0x257e, 0x257f,
@@ -1092,33 +1114,50 @@
     0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5, 0x24f5,
   };
 
+#define L(x) (x == ' ' ? 0x24f5 : 0x2550 + x - 'A')
+  const uint16 kNotAssignedItemText[16] = {
+    L('N'), L('O'), L('T'), L(' '), L(' '), L(' '), L(' '), L(' '),
+    L('A'), L('S'), L('S'), L('I'), L('G'), L('N'), L('E'), L('D'),
+  };
+#undef L
+
   uint16 *dst_org = uvram_screen.row[0].col;
   uint16 *dst_box = dst_org + (kNewStyleInventory ? 1 : 0);
-  Hud_DrawBox(dst_box, 21, 5, 21 + 9, 10, 7);
 
-  uint16 *p = dst_org + kHudItemInVramPtr[Hud_GetCurrentItemPosition()];
-  Hud_Copy2x2(dst_box + HUDXY(25, 6), p);
+  bool is_x = (joypad1L_last & 0x40 && (enhanced_features0 & kFeatures0_SwitchLR));
+  uint8 palette = is_x ? 3 : 7;
+  Hud_DrawBox(dst_box, 21, 5, 21 + 9, 10, palette);
 
-  if (timer_for_flashing_circle & 0x10)
-    Hud_DrawFlashingCircle(p);
+  // Display either the current item or the item assigned
+  // to the x key.
+  int item = is_x ? hud_cur_item_x : hud_cur_item;
 
+  if (item != 0) {
+    uint16 *p = dst_org + kHudItemInVramPtr[Hud_GetItemPosition(item)];
+    Hud_Copy2x2(dst_box + HUDXY(25, 6), p);
+    if (timer_for_flashing_circle & 0x10)
+      Hud_DrawFlashingCircle(p, palette);
+  }
+
   const uint16 *src_p;
-  if (hud_cur_item == kHudItem_BottleOld && !kNewStyleInventory && link_item_bottle_index) {
+  if (item == kHudItem_BottleOld && !kNewStyleInventory && link_item_bottle_index) {
     src_p = &kHudBottlesItemText[(link_bottle_info[link_item_bottle_index - 1] - 1) * 16];
-  } else if (hud_cur_item == 5 && link_item_mushroom != 1) {
+  } else if (item == 5 && link_item_mushroom != 1) {
     src_p = &kHudMushroomItemText[(link_item_mushroom - 2) * 16];
-  } else if (hud_cur_item == 20 && link_item_mirror != 1) {
+  } else if (item == 20 && link_item_mirror != 1) {
     src_p = &kHudMirrorItemText[(link_item_mirror - 2) * 16];
-  } else if (hud_cur_item == 13 && link_item_flute != 1) {
+  } else if (item == 13 && link_item_flute != 1) {
     src_p = &kHudFluteItemText[(link_item_flute - 2) * 16];
-  } else if (hud_cur_item == 1 && link_item_bow != 1) {
+  } else if (item == 1 && link_item_bow != 1) {
     src_p = &kHudBowItemText[(link_item_bow - 2) * 16];
-  } else if (hud_cur_item >= kHudItem_Bottle1 && hud_cur_item <= kHudItem_Bottle4) {
-    src_p = &kHudBottlesItemText[(link_bottle_info[hud_cur_item - kHudItem_Bottle1] - 1) * 16];
-  } else if (hud_cur_item == kHudItem_Shovel) {
+  } else if (item >= kHudItem_Bottle1 && item <= kHudItem_Bottle4) {
+    src_p = &kHudBottlesItemText[(link_bottle_info[item - kHudItem_Bottle1] - 1) * 16];
+  } else if (item == kHudItem_Shovel) {
     src_p = &kHudItemText[(13 - 1) * 16];
+  } else if (item == 0) {
+    src_p = is_x ? kNotAssignedItemText : &kHudItemText[(20 - 1) * 16];
   } else {
-    src_p = &kHudItemText[(hud_cur_item - 1) * 16];
+    src_p = &kHudItemText[(item - 1) * 16];
   }
   Hud_DrawNxN(dst_box + HUDXY(22, 8), src_p, 8, 2);
 }
@@ -1344,10 +1383,10 @@
         break;
       }
       if (filtered_joypad_L & 0x20)
-        Hud_GotoPrevItem();
+        Hud_GotoPrevItem(&hud_cur_item, 1);
       else
-        Hud_GotoNextItem();
-      if (Hud_DoWeHaveThisItem())
+        Hud_GotoNextItem(&hud_cur_item, 1);
+      if (Hud_DoWeHaveThisItem(hud_cur_item))
         break;
     }
     if (hud_cur_item != old_item) {
@@ -1364,7 +1403,7 @@
     for (int i = 0; i < 24; i++)
       hud_inventory_order[i] = i + 1;
   }
-  int old_pos = Hud_GetCurrentItemPosition(), new_pos = old_pos + direction;
+  int old_pos = Hud_GetItemPosition(hud_cur_item), new_pos = old_pos + direction;
   if (new_pos < 0)
     new_pos += kHudItemCount;
   else if (new_pos >= kHudItemCount)
--- a/hud.h
+++ b/hud.h
@@ -19,8 +19,6 @@
 
 void Hud_RefreshIcon();
 uint8 CheckPalaceItemPosession();
-void Hud_GotoPrevItem();
-void Hud_GotoNextItem();
 void Hud_FloorIndicator();
 void Hud_RemoveSuperBombIndicator();
 void Hud_SuperBombIndicator();
@@ -30,13 +28,10 @@
 void Hud_Init();
 void Hud_BringMenuDown();
 void Hud_ChooseNextMode();
-bool Hud_DoWeHaveThisItem();
-void Hud_EquipPrevItem();
-void Hud_EquipNextItem();
-void Hud_EquipItemAbove();
-void Hud_EquipItemBelow();
+bool Hud_DoWeHaveThisItem(uint8 item);
 void Hud_NormalMenu();
 void Hud_UpdateHud();
+uint8 Hud_LookupInventoryItem(uint8 item);
 void Hud_UpdateEquippedItem();
 void Hud_CloseMenu();
 void Hud_GotoBottleMenu();
--- a/messaging.c
+++ b/messaging.c
@@ -1278,6 +1278,13 @@
     overworld_map_state++;
 }
 
+bool DidPressButtonForMap() {
+  if (hud_cur_item_x != 0)
+    return filtered_joypad_H & 0x20;  // select
+  else
+    return filtered_joypad_L & 0x40;  // x
+}
+
 void WorldMap_PlayerControl() {  // 8abae6
   if (overworld_map_flags & 0x80) {
     overworld_map_flags &= ~0x80;
@@ -1284,13 +1291,15 @@
     OverworldMap_SetupHdma();
   }
 
-  if (!overworld_map_flags && filtered_joypad_L & 0x40) { // X
+  if (!overworld_map_flags && DidPressButtonForMap()) { // X
+    // getout
     overworld_map_state++;
     return;
   }
   if (BYTE(dung_draw_width_indicator)) {
     BYTE(dung_draw_width_indicator)--;
-  } else if (filtered_joypad_L & 0x70) {
+  } else if (filtered_joypad_L & 0x30 || DidPressButtonForMap()) {
+    // next zoom level
     sound_effect_2 = 36;
     BYTE(dung_draw_width_indicator) = 8;
 
@@ -1968,8 +1977,15 @@
   DungeonMap_DrawSprites();
 }
 
+static inline bool WantExitDungeonMap() {
+  if (hud_cur_item_x != 0)
+    return filtered_joypad_H & 0x20;  // Select
+  else
+    return filtered_joypad_L & 0x40;  // X
+}
+
 void DungeonMap_HandleInput() {  // 8ae95b
-  if (filtered_joypad_L & 0x40) {
+  if (WantExitDungeonMap()) {
     overworld_map_state += 2;
     dungmap_init_state = 0;
   } else {
@@ -3070,3 +3086,16 @@
   index_of_changable_dungeon_objs[0] = index_of_changable_dungeon_objs[1] = 0;
 }
 
+
+
+void DisplaySelectMenu() {
+  choice_in_multiselect_box_bak = choice_in_multiselect_box;
+  dialogue_message_index = 0x186;
+  uint8 bak = main_module_index;
+  Main_ShowTextMessage();
+  main_module_index = bak;
+  subsubmodule_index = 0;
+  submodule_index = 11;
+  saved_module_for_menu = main_module_index;
+  main_module_index = 14;
+}
--- a/messaging.h
+++ b/messaging.h
@@ -137,3 +137,5 @@
 void DungMap_RestoreOld();
 void Death_PlayerSwoon();
 void Death_PrepFaint();
+void DisplaySelectMenu();
+bool DidPressButtonForMap();
--- a/overworld.c
+++ b/overworld.c
@@ -760,7 +760,8 @@
       main_module_index = 14;
       return;
     }
-    if (filtered_joypad_L & 0x40) {
+
+    if (DidPressButtonForMap()) {
       overworld_map_state = 0;
       submodule_index = 7;
       saved_module_for_menu = main_module_index;
@@ -768,15 +769,7 @@
       return;
     }
     if (joypad1H_last & 0x20) {
-      choice_in_multiselect_box_bak = choice_in_multiselect_box;
-      dialogue_message_index = 0x186;
-      int bak = main_module_index;
-      Main_ShowTextMessage();
-      main_module_index = bak;
-      subsubmodule_index = 0;
-      submodule_index = 11;
-      saved_module_for_menu = main_module_index;
-      main_module_index = 14;
+      DisplaySelectMenu();
       return;
     }
     Hud_HandleItemSwitchInputs();
--- a/player.c
+++ b/player.c
@@ -1932,7 +1932,9 @@
   if (button_b_frames && button_b_frames < 9)
     return;
 
-  if (link_is_bunny_mirror && (current_item_y != 11 && current_item_y != 20))
+  uint8 item = current_item_y;
+
+  if (link_is_bunny_mirror && (item != 11 && item != 20))
     return;
 
   if (is_archer_or_shovel_game && !link_is_bunny_mirror) {
@@ -1943,7 +1945,21 @@
     return;
   }
 
-  if (current_item_y != current_item_active) {
+  uint8 old_down = joypad1H_last, old_pressed = filtered_joypad_H, old_bottle = link_item_bottle_index;
+  if ((link_item_in_hand | link_position_mode) == 0) {
+    // Is X held down?
+    if (joypad1L_last & 0x40 && !(old_down & 0x40) && hud_cur_item_x != 0) {
+      
+      if (hud_cur_item_x >= kHudItem_Bottle1)
+        link_item_bottle_index = hud_cur_item_x - kHudItem_Bottle1 + 1;
+      item = Hud_LookupInventoryItem(hud_cur_item_x);
+      // Pretend it's actually Y that's down
+      joypad1H_last = old_down | 0x40;
+      filtered_joypad_H = old_pressed | filtered_joypad_L & 0x40;
+    }
+  }
+
+  if (item != current_item_active) {
     if (current_item_active == 8 && (link_item_flute & 2))
       button_mask_b_y &= ~0x40;
     if (current_item_active == 19 && link_cape_mode)
@@ -1950,8 +1966,9 @@
       Link_ForceUnequipCape();
   }
 
+
   if ((link_item_in_hand | link_position_mode) == 0)
-    current_item_active = current_item_y;
+    current_item_active = item;
 
   if (current_item_active == 5 || current_item_active == 6)
     eq_selected_rod = current_item_active - 5 + 1;
@@ -1983,6 +2000,10 @@
   default:
     assert(0);
   }
+
+  joypad1H_last = old_down;
+  filtered_joypad_H = old_pressed;
+  link_item_bottle_index = old_bottle;
 }
 
 void Link_HandleAPress() {  // 879baa
--- a/zelda_cpu_infra.c
+++ b/zelda_cpu_infra.c
@@ -748,6 +748,9 @@
     return turbo;
   }
 
+  if (g_fail)
+    return false;
+
   MakeSnapshot(&g_snapshot_before);
   MakeMySnapshot(&g_snapshot_mine);
   MakeSnapshot(&g_snapshot_theirs);
@@ -756,8 +759,8 @@
   VerifySnapshotsEq(&g_snapshot_mine, &g_snapshot_theirs, &g_snapshot_before);
   if (g_fail) {
     printf("early fail\n");
-    assert(0);
-    return turbo;
+    //assert(0);
+    //return turbo;
   }
 
   // Run orig version then snapshot
@@ -776,13 +779,19 @@
   VerifySnapshotsEq(&g_snapshot_mine, &g_snapshot_theirs, &g_snapshot_before);
   
   if (g_fail) {
-    g_fail = false;
-    RestoreMySnapshot(&g_snapshot_before);
-    //SaveLoadSlot(kSaveLoad_Save, 0);
-    if (0) 
-      goto again_mine;
-    RestoreSnapshot(&g_snapshot_before);
-    goto again_theirs;
+//    g_fail = false;
+    if (1) {
+      RestoreMySnapshot(&g_snapshot_before);
+      //SaveLoadSlot(kSaveLoad_Save, 0);
+      if (0)
+        goto again_mine;
+      RestoreSnapshot(&g_snapshot_before);
+      goto again_theirs;
+    }
+    if (1) {
+      MakeSnapshot(&g_snapshot_theirs);
+      RestoreMySnapshot(&g_snapshot_theirs);      
+    }
   }
 
   return turbo;
--- a/zelda_rtl.h
+++ b/zelda_rtl.h
@@ -127,6 +127,8 @@
 #define msu_curr_sample (*(uint32*)(g_ram+0x650))
 #define msu_volume (*(uint8*)(g_ram+0x654))
 #define msu_track (*(uint8*)(g_ram+0x655))
+#define hud_cur_item_x (*(uint8*)(g_ram+0x656))
+
 
 #define hud_inventory_order ((uint8*)(g_ram + 0x225)) // 4x6 bytes