shithub: zelda3

Download patch

ref: 6297be577d985375af5c416da898a78ba6ddf6b5
parent: 5ae8a5cc7145fdfec335d20ee22029059f7ce94c
author: Snesrev <snesrev@protonmail.com>
date: Mon Oct 10 22:22:20 EDT 2022

Asset compiler now uses PNG-images as input

Also renamed variables
Fix so it won't decompress sheets < 12

diff: cannot open b/tables/sprites//null: file does not exist: 'b/tables/sprites//null'
--- a/ancilla.c
+++ b/ancilla.c
@@ -3742,7 +3742,7 @@
     }
     if (!ancilla_arr3[k] && ancilla_item_to_link[k] == 0x20) {
       ancilla_arr3[k] = 1;
-      palette_sp6 = 4;
+      palette_sp6r_indoors = 4;
       overworld_palette_aux_or_main = 0x200;
       Palette_Load_SpriteEnvironment_Dungeon();
       flag_update_cgram_in_nmi++;
@@ -3902,7 +3902,7 @@
     ancilla_x_lo[k] = bak0;
     ancilla_x_hi[k] = bak1;
     if (breaktowerseal_var4 >= 240) {
-      palette_sp6 = 0;
+      palette_sp6r_indoors = 0;
       overworld_palette_aux_or_main = 0x200;
       Palette_Load_SpriteEnvironment_Dungeon();
       flag_update_cgram_in_nmi++;
@@ -6716,7 +6716,7 @@
   for (int i = 0x17; i >= 0; i--)
     breaktowerseal_sparkle_var1[i] = 0xff;
   DecodeAnimatedSpriteTile_variable(0x28);
-  palette_sp6 = 4;
+  palette_sp6r_indoors = 4;
   overworld_palette_aux_or_main = 0x200;
   Palette_Load_SpriteEnvironment_Dungeon();
   flag_update_cgram_in_nmi++;
--- a/attract.c
+++ b/attract.c
@@ -360,10 +360,10 @@
   overworld_palette_aux_or_main = 0x200;
   flag_update_cgram_in_nmi++;
   Palette_BgAndFixedColor_Black();
-  Palette_Load_SpritePal0Left();
+  Palette_Load_Sp0L();
   Palette_Load_SpriteMain();
-  Palette_Load_SpriteAux1();
-  Palette_Load_SpriteAux2();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
   Palette_Load_SpriteEnvironment_Dungeon();
   Palette_Load_HUD();
   Palette_Load_DungeonSet();
@@ -524,10 +524,10 @@
   Dungeon_LoadAndDrawEntranceRoom(0x74);
   WORD(attract_state) = bak1;
   attract_var12 = bak0;
-  dung_hdr_palette_1 = 0;
-  overworld_palette_sp0 = 0;
-  sprite_aux1_palette = 14;
-  sprite_aux2_palette = 3;
+  palette_main_indoors = 0;
+  palette_sp0l = 0;
+  palette_sp5l = 14;
+  palette_sp6l = 3;
   Dungeon_SaveAndLoadLoadAllPalettes(0, 0x7e);
 
   main_palette_buffer[0x1d] = 0x3800;
@@ -560,10 +560,10 @@
   WORD(attract_state) = bak1;
   attract_var12 = bak0;
 
-  dung_hdr_palette_1 = 2;
-  overworld_palette_sp0 = 0;
-  sprite_aux1_palette = 14;
-  sprite_aux2_palette = 3;
+  palette_main_indoors = 2;
+  palette_sp0l = 0;
+  palette_sp5l = 14;
+  palette_sp6l = 3;
   Dungeon_SaveAndLoadLoadAllPalettes(1, 0x7f);
   main_palette_buffer[0x1d] = 0x3800;
 
@@ -589,16 +589,16 @@
   WORD(attract_state) = bak1;
   attract_var12 = bak0;
 
-  dung_hdr_palette_1 = 0;
-  overworld_palette_sp0 = 0;
-  sprite_aux1_palette = 14;
-  sprite_aux2_palette = 3;
+  palette_main_indoors = 0;
+  palette_sp0l = 0;
+  palette_sp5l = 14;
+  palette_sp6l = 3;
 
   overworld_palette_aux_or_main = 0;
-  Palette_Load_SpritePal0Left();
+  Palette_Load_Sp0L();
   Palette_Load_SpriteMain();
-  Palette_Load_SpriteAux1();
-  Palette_Load_SpriteAux2();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
   Palette_Load_SpriteEnvironment_Dungeon();
   Palette_Load_HUD();
   Palette_Load_DungeonSet();
--- a/dungeon.c
+++ b/dungeon.c
@@ -3702,10 +3702,10 @@
   dung_want_lights_out_copy = dung_want_lights_out;
   dung_want_lights_out = hdr_ptr[0] & 1;
   const DungPalInfo *dpi = &kDungPalinfos[hdr_ptr[1]];
-  dung_hdr_palette_1 = dpi->pal0;
-  overworld_palette_sp0 = dpi->pal1;
-  sprite_aux1_palette = dpi->pal2;
-  sprite_aux2_palette = dpi->pal3;
+  palette_main_indoors = dpi->pal0;
+  palette_sp0l = dpi->pal1;
+  palette_sp5l = dpi->pal2;
+  palette_sp6l = dpi->pal3;
   aux_tile_theme_index = hdr_ptr[2];
   sprite_graphics_index = hdr_ptr[3] + 0x40;
   dung_hdr_collision_2 = hdr_ptr[4];
@@ -6432,7 +6432,7 @@
   Dungeon_LoadAttributeTable();
   misc_sprites_graphics_index = 10;
   InitializeTilesets();
-  palette_sp6 = 10;
+  palette_sp6r_indoors = 10;
   Dungeon_LoadPalettes();
   if (link_is_bunny_mirror | link_is_bunny)
     LoadGearPalettes_bunny();
@@ -7743,7 +7743,7 @@
     submodule_index = 0;
     nmi_load_bg_from_vram = 0;
     last_music_control = music_unk1;
-    if (overworld_palette_swap_flag)
+    if (palette_swap_flag)
       Palette_RevertTranslucencySwap();
   }
 }
@@ -7861,7 +7861,7 @@
   subsubmodule_index = bak + 1;
   misc_sprites_graphics_index = 10;
   InitializeTilesets();
-  palette_sp6 = 10;
+  palette_sp6r_indoors = 10;
   Dungeon_LoadPalettes();
   Hud_RestoreTorchBackground();
   button_mask_b_y = 0;
--- a/ending.c
+++ b/ending.c
@@ -246,11 +246,11 @@
   int i = submodule_index >> 1;
   sprite_graphics_index = kEnding_SpritePack[i];
   const DungPalInfo *dpi = GetDungPalInfo(kEnding_SpritePal[i] & 0x3f);
-  sprite_aux1_palette = dpi->pal2;
-  sprite_aux2_palette = dpi->pal3;
+  palette_sp5l = dpi->pal2;
+  palette_sp6l = dpi->pal3;
   misc_sprites_graphics_index = 10;
   InitializeTilesets();
-  palette_sp6 = 10;
+  palette_sp6r_indoors = 10;
   Dungeon_LoadPalettes();
   BGMODE_copy = 9;
   R16 = 0;
@@ -578,7 +578,7 @@
   DecompressAnimatedDungeonTiles(0x5d);
   bg_tile_animation_countdown = 2;
   BYTE(overworld_screen_index) = 0;
-  dung_hdr_palette_1 = 0;
+  palette_main_indoors = 0;
   overworld_palette_aux3_bp7_lo = 0;
   R16 = 0;
   R18 = 0;
--- a/load_gfx.c
+++ b/load_gfx.c
@@ -877,9 +877,9 @@
 
   int8 sp6 = kGraphicsLoadSp6[k - 1];
   if (sp6 >= 0) {
-    palette_sp6 = sp6;
+    palette_sp6r_indoors = sp6;
     if (k == 1) {
-      palette_sp6 = 10;
+      palette_sp6r_indoors = 10;
       overworld_palette_aux_or_main = 0x200;
       Palette_Load_SpriteEnvironment();
       flag_update_cgram_in_nmi++;
@@ -989,7 +989,14 @@
 }
 
 int Decomp_spr(uint8 *dst, int gfx) {  // 80e772
-  return Decompress(dst, GetCompSpritePtr(gfx));
+  if (gfx < 12)
+    gfx = 12; // ensure it wont decode bad sheets.
+  const uint8 *sprite_data = GetCompSpritePtr(gfx);
+  // If the size is not 0x600 then it's compressed
+  if (gfx >= 103 || (((uint32 *)kSprGfx)[gfx + 1] - ((uint32 *)kSprGfx)[gfx]) != 0x600)
+    return Decompress(dst, sprite_data);
+  memcpy(dst, sprite_data, 0x600);
+  return 0x600;
 }
 
 int Decomp_bg(uint8 *dst, int gfx) {  // 80e78f
@@ -1649,7 +1656,7 @@
 }
 
 void Dungeon_HandleTranslucencyAndPalette() {  // 82a1e9
-  if (overworld_palette_swap_flag)
+  if (palette_swap_flag)
     Palette_RevertTranslucencySwap();
 
   CGWSEL_copy = 2;
@@ -1683,9 +1690,9 @@
   darkening_or_lightening_screen = 2;
   overworld_palette_aux_or_main = 0;
   Palette_Load_DungeonSet();
-  Palette_Load_SpritePal0Left();
-  Palette_Load_SpriteAux1();
-  Palette_Load_SpriteAux2();
+  Palette_Load_Sp0L();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
   subsubmodule_index += 1;
 }
 
@@ -1697,12 +1704,12 @@
   overworld_palette_aux1_bp2to4_hi = 3;
   overworld_palette_aux2_bp5to7_hi = 3;
   overworld_palette_aux3_bp7_lo = 0;
-  palette_sp6 = 5;
-  overworld_palette_sp0 = 11;
-  overworld_palette_swap_flag = 0;
+  palette_sp6r_indoors = 5;
+  palette_sp0l = 11;
+  palette_swap_flag = 0;
   overworld_palette_aux_or_main = 0;
   Palette_BgAndFixedColor_Black();
-  Palette_Load_SpritePal0Left();
+  Palette_Load_Sp0L();
   Palette_Load_SpriteMain();
   Palette_Load_OWBGMain();
   Palette_Load_OWBG1();
@@ -1718,10 +1725,10 @@
 void Dungeon_LoadPalettes() {  // 82c630
   overworld_palette_aux_or_main = 0;
   Palette_BgAndFixedColor_Black();
-  Palette_Load_SpritePal0Left();
+  Palette_Load_Sp0L();
   Palette_Load_SpriteMain();
-  Palette_Load_SpriteAux1();
-  Palette_Load_SpriteAux2();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
   Palette_Load_Sword();
   Palette_Load_Shield();
   Palette_Load_SpriteEnvironment();
@@ -1732,7 +1739,7 @@
 }
 
 void Overworld_LoadPalettesInner() {  // 82c65f
-  overworld_pal_unk1 = dung_hdr_palette_1;
+  overworld_pal_unk1 = palette_main_indoors;
   overworld_pal_unk2 = overworld_palette_aux3_bp7_lo;
   overworld_pal_unk3 = byte_7E0AB7;
   darkening_or_lightening_screen = 2;
@@ -1753,13 +1760,13 @@
   overworld_palette_aux_or_main &= 0xff;
   Palette_Load_SpriteMain();
   Palette_Load_SpriteEnvironment();
-  Palette_Load_SpriteAux1();
-  Palette_Load_SpriteAux2();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
   Palette_Load_Sword();
   Palette_Load_Shield();
   Palette_Load_LinkArmorAndGloves();
-  overworld_palette_sp0 = (savegame_is_darkworld & 0x40) ? 3 : 1;
-  Palette_Load_SpritePal0Left();
+  palette_sp0l = (savegame_is_darkworld & 0x40) ? 3 : 1;
+  Palette_Load_Sp0L();
   Palette_Load_HUD();
   Palette_Load_OWBGMain();
 }
@@ -1800,14 +1807,14 @@
 
   d = kOwSprPalInfo + spr * 2;
   if (d[0] >= 0)
-    sprite_aux1_palette = d[0];
+    palette_sp5l = d[0];
   if (d[1] >= 0)
-    sprite_aux2_palette = d[1];
+    palette_sp6l = d[1];
   Palette_Load_OWBG1();
   Palette_Load_OWBG2();
   Palette_Load_OWBG3();
-  Palette_Load_SpriteAux1();
-  Palette_Load_SpriteAux2();
+  Palette_Load_Sp5L();
+  Palette_Load_Sp6L();
 }
 
 void Palette_BgAndFixedColor_Black() {  // 8ed5f4
@@ -1852,7 +1859,7 @@
 }
 
 void Palette_SetTranslucencySwap(bool v) {  // 8ed65c
-  overworld_palette_swap_flag = v;
+  palette_swap_flag = v;
   uint16 a, b;
   for (int i = 0; i < 8; i++) {
     a = aux_palette_buffer[i + 0x80];
@@ -1959,35 +1966,64 @@
   Palette_Restore_Coldata();
 }
 
-void Palette_Load_SpritePal0Left() {  // 9bec77
-  const uint16 *src = kPalette_SpriteAux3 + overworld_palette_sp0 * 7;
-  Palette_LoadSingle(src, overworld_palette_swap_flag ? 0x1e2 : 0x102, 6);
+/* Summary of sprite palette usage 
+0l: kPalette_SpriteAux3[palette_sp0l]
+0r: kPalette_MiscSprite[7 / 9] or kPalette_DungBgMain[(palette_main_indoors >> 1) * 90]
+1 : common sprites
+2 :      -"-
+3 :      -"-
+4 :      -"-
+5l: palette_sp5l
+5r: link sword/shield
+6l: palette_sp6l
+6r: kPalette_MiscSprite[6 / 8] or kPalette_MiscSprite[palette_sp6r_indoors]
+7 : link armor and gloves
+*/
+
+enum {
+  kPal_sp0l = 0x102,
+  kPal_sp0r = 0x112,
+  kPal_sp1to4 = 0x122,   // This is used for 64 colors, colors switched if in darkworld mode
+  kPal_sp5l = 0x1a2,
+  kPal_Sword = 0x1b2,
+  kPal_Shield = 0x1b8,
+  kPal_sp6l = 0x1c2,
+  kPal_sp6r = 0x1d2,
+  kPal_sp7l = 0x1e2,
+  kPal_sp7r = 0x1f2,
+  kPal_ArmorGloves = 0x1e2,
+  kPal_PalaceMap = 0x182,
+};
+
+void Palette_Load_Sp0L() {  // 9bec77
+  const uint16 *src = kPalette_SpriteAux3 + palette_sp0l * 7;
+  Palette_LoadSingle(src, palette_swap_flag ? kPal_sp7l : kPal_sp0l, 6);
 }
 
 void Palette_Load_SpriteMain() {  // 9bec9e
   const uint16 *src = kPalette_MainSpr + (overworld_screen_index & 0x40 ? 60 : 0);
-  Palette_LoadMultiple(src, 0x122, 14, 3);
+  Palette_LoadMultiple(src, kPal_sp1to4, 14, 3);
 }
 
-void Palette_Load_SpriteAux1() {  // 9becc5
-  const uint16 *src = kPalette_SpriteAux1 + (sprite_aux1_palette) * 7;
-  Palette_LoadSingle(src, 0x1A2, 6);
+void Palette_Load_Sp5L() {  // 9becc5
+  const uint16 *src = kPalette_SpriteAux1 + (palette_sp5l) * 7;
+  Palette_LoadSingle(src, kPal_sp5l, 6);
 }
 
-void Palette_Load_SpriteAux2() {  // 9bece4
-  const uint16 *src = kPalette_SpriteAux1 + (sprite_aux2_palette) * 7;
-  Palette_LoadSingle(src, 0x1C2, 6);
+void Palette_Load_Sp6L() {  // 9bece4
+  const uint16 *src = kPalette_SpriteAux1 + (palette_sp6l) * 7;
+  Palette_LoadSingle(src, kPal_sp6l, 6);
 }
 
 void Palette_Load_Sword() {  // 9bed03
   const uint16 *src = kPalette_Sword + ((int8)link_sword_type > 0 ? link_sword_type - 1 : 0) * 3;  // wtf: zelda reads offset 0xff
-  Palette_LoadMultiple_Arbitrary(src, 0x1b2, 2);
+  Palette_LoadMultiple_Arbitrary(src, kPal_Sword, 2);
   flag_update_cgram_in_nmi += 1;
 }
 
 void Palette_Load_Shield() {  // 9bed29
   const uint16 *src = kPalette_Shield + (link_shield_type ? link_shield_type - 1 : 0) * 4;
-  Palette_LoadMultiple_Arbitrary(src, 0x1b8, 3);
+  Palette_LoadMultiple_Arbitrary(src, kPal_Shield, 3);
   flag_update_cgram_in_nmi += 1;
 }
 
@@ -1998,26 +2034,28 @@
     Palette_MiscSprite_Outdoors();
 }
 
+// avoid renaming in assets.dat
+#define kPalette_MiscSprite kPalette_MiscSprite_Indoors
+
 void Palette_Load_SpriteEnvironment_Dungeon() {  // 9bed72
-  const uint16 *src = kPalette_MiscSprite_Indoors + palette_sp6 * 7;
-  Palette_LoadSingle(src, 0x1d2, 6);
+  const uint16 *src = kPalette_MiscSprite + palette_sp6r_indoors * 7;
+  Palette_LoadSingle(src, kPal_sp6r, 6);
 }
 
 void Palette_MiscSprite_Outdoors() {  // 9bed91
   int t = (overworld_screen_index & 0x40) ? 9 : 7;
-  const uint16 *src = kPalette_MiscSprite_Indoors + t * 7;
-  Palette_LoadSingle(src, overworld_palette_swap_flag ? 0x1f2 : 0x112, 6);
-  src = kPalette_MiscSprite_Indoors + (t - 1) * 7;
-  Palette_LoadSingle(src, 0x1d2, 6);
+  const uint16 *src = kPalette_MiscSprite + t * 7;
+  Palette_LoadSingle(src, palette_swap_flag ? kPal_sp7r : kPal_sp0r, 6);
+  Palette_LoadSingle(src - 7, kPal_sp6r, 6);
 }
 
 void Palette_Load_DungeonMapSprite() {  // 9beddd
-  Palette_LoadMultiple(kPalette_PalaceMapSpr, 0x182, 6, 2);
+  Palette_LoadMultiple(kPalette_PalaceMapSpr, kPal_PalaceMap, 6, 2);
 }
 
 void Palette_Load_LinkArmorAndGloves() {  // 9bedf9
   const uint16 *src = kPalette_ArmorAndGloves + link_armor * 15;
-  Palette_LoadMultiple_Arbitrary(src, 0x1e2, 14);
+  Palette_LoadMultiple_Arbitrary(src, kPal_ArmorGloves, 14);
   Palette_UpdateGlovesColor();
 }
 
@@ -2037,9 +2075,9 @@
 }
 
 void Palette_Load_DungeonSet() {  // 9bee74
-  const uint16 *src = kPalette_DungBgMain + (dung_hdr_palette_1 >> 1) * 90;
+  const uint16 *src = kPalette_DungBgMain + (palette_main_indoors >> 1) * 90;
   Palette_LoadMultiple(src, 0x42, 14, 5);
-  Palette_LoadSingle(src, overworld_palette_swap_flag ? 0x1f2 : 0x112, 6);
+  Palette_LoadSingle(src, palette_swap_flag ? kPal_sp7r : kPal_sp0r, 6);
 }
 
 void Palette_Load_OWBG3() {  // 9beea8
--- a/load_gfx.h
+++ b/load_gfx.h
@@ -132,10 +132,10 @@
 void Palette_Restore_BG_From_Flash();
 void Palette_Restore_Coldata();
 void Palette_Restore_BG_And_HUD();
-void Palette_Load_SpritePal0Left();
+void Palette_Load_Sp0L();
 void Palette_Load_SpriteMain();
-void Palette_Load_SpriteAux1();
-void Palette_Load_SpriteAux2();
+void Palette_Load_Sp5L();
+void Palette_Load_Sp6L();
 void Palette_Load_Sword();
 void Palette_Load_Shield();
 void Palette_Load_SpriteEnvironment();
--- a/main.c
+++ b/main.c
@@ -25,7 +25,10 @@
 #include "assets.h"
 #include "load_gfx.h"
 
+static bool g_run_without_emu = 0;
 
+
+
 // Forwards
 static bool LoadRom(const char *filename);
 static void LoadLinkGraphics();
@@ -60,7 +63,6 @@
 static bool g_display_perf;
 static int g_curr_fps;
 static int g_ppu_render_flags = 0;
-static bool g_run_without_emu = false;
 static int g_snes_width, g_snes_height;
 static int g_sdl_audio_mixer_volume = SDL_MIX_MAXVOLUME;
 
--- a/messaging.c
+++ b/messaging.c
@@ -829,7 +829,7 @@
   load_chr_halfslot_even_odd = 15;
   Graphics_LoadChrHalfSlot();
   load_chr_halfslot_even_odd = 0;
-  palette_sp6 = 5;
+  palette_sp6r_indoors = 5;
   overworld_palette_aux_or_main = 0x200;
   Palette_Load_SpriteEnvironment_Dungeon();
   Palette_Load_SpriteMain();
@@ -2036,7 +2036,7 @@
     if (a >= 0)
       r3 -= a;
   }
-  SetOamPlain(&oam_buf[spr_pos], 0x19, kDungMap_Tab33[r3] - 4, 0, overworld_palette_swap_flag ? 0x30 : 0x3e, 2);
+  SetOamPlain(&oam_buf[spr_pos], 0x19, kDungMap_Tab33[r3] - 4, 0, palette_swap_flag ? 0x30 : 0x3e, 2);
 }
 
 int DungeonMap_DrawBlinkingIndicator(int spr_pos) {  // 8aeb50
binary files /dev/null b/other/3x5_font.png differ
--- a/overworld.c
+++ b/overworld.c
@@ -1449,7 +1449,7 @@
     overworld_palette_aux_or_main = 0;
     Palette_Load_SpriteMain();
     Palette_Load_SpriteEnvironment();
-    Palette_Load_SpritePal0Left();
+    Palette_Load_Sp0L();
     Palette_Load_HUD();
     Palette_Load_OWBGMain();
     uint8 sc = overworld_screen_index;
--- a/player.c
+++ b/player.c
@@ -177,7 +177,6 @@
   }
   if (link_player_handler_state)
     Player_CheckHandleCapeStuff();
-
   kPlayerHandlers[link_player_handler_state]();
 }
 
@@ -6518,7 +6517,7 @@
   byte_7E03F3 = 0;
   byte_7E0322 = 0;
   flag_is_link_immobilized = 0;
-  overworld_palette_swap_flag = 0;
+  palette_swap_flag = 0;
   player_unk1 = 0;
   link_give_damage = 0;
   link_actual_vel_y = 0;
--- a/player_oam.c
+++ b/player_oam.c
@@ -927,7 +927,7 @@
   int r2 = kPlayerOamOtherOffs[dir * 40 + yt] + rt;
   int r4loc = kPlayerOamSpriteLocs[r2];
 
-  link_palette_bits_of_oam = overworld_palette_swap_flag ? 0 : 0xe00;
+  link_palette_bits_of_oam = palette_swap_flag ? 0 : 0xe00;
   link_dma_var1 = link_dma_var2 = 0;
 
   int xt = FindInByteArray(kPlayerOam_Tab5, yt, 7);
--- a/select_file.c
+++ b/select_file.c
@@ -211,7 +211,7 @@
   music_control = 11;
   submodule_index++;
   overworld_palette_aux_or_main = 0x200;
-  dung_hdr_palette_1 = 6;
+  palette_main_indoors = 6;
   nmi_disable_core_updates = 6;
   Palette_Load_DungeonSet();
   Palette_Load_OWBG3();
--- a/sprite_main.c
+++ b/sprite_main.c
@@ -73,58 +73,6 @@
   0x09, 0x13, 0x14, 0x4a, 0x21, 0x1d, 0x15, 0x18, 0x19, 0x31, 0x1a, 0x1a, 0x1b, 0x1c, 0x4b, 0x1e,
   0x1f, 0x49, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x22, 0x23, 0x29, 0x16, 0x2b, 0x2c, 0x2d, 0x3d, 0x3c, 0x48
 };
-static const DrawMultipleData kUncleDraw_Table[48] = {
-  {  0, -10, 0x0e00, 2},
-  {  0,   0, 0x0c06, 2},
-  {  0, -10, 0x0e00, 2},
-  {  0,   0, 0x0c06, 2},
-  {  0, -10, 0x0e00, 2},
-  {  0,   0, 0x0c06, 2},
-  {  0, -10, 0x0e02, 2},
-  {  0,   0, 0x0c06, 2},
-  {  0, -10, 0x0e02, 2},
-  {  0,   0, 0x0c06, 2},
-  {  0, -10, 0x0e02, 2},
-  {  0,   0, 0x0c06, 2},
-  { -7,   2, 0x0d07, 2},
-  { -7,   2, 0x0d07, 2},
-  { 10,  12, 0x8d05, 0},
-  { 10,   4, 0x8d15, 0},
-  {  0, -10, 0x0e00, 2},
-  {  0,   0, 0x0c04, 2},
-  { -7,   1, 0x0d07, 2},
-  { -7,   1, 0x0d07, 2},
-  { 10,  13, 0x8d05, 0},
-  { 10,   5, 0x8d15, 0},
-  {  0,  -9, 0x0e00, 2},
-  {  0,   1, 0x4c04, 2},
-  { -7,   8, 0x8d05, 0},
-  {  1,   8, 0x8d06, 0},
-  {  0, -10, 0x0e02, 2},
-  { -6,  -1, 0x4d07, 2},
-  {  0,   0, 0x0c23, 2},
-  {  0,   0, 0x0c23, 2},
-  { -9,   7, 0x8d05, 0},
-  { -1,   7, 0x8d06, 0},
-  {  0,  -9, 0x0e02, 2},
-  { -6,   0, 0x4d07, 2},
-  {  0,   1, 0x0c25, 2},
-  {  0,   1, 0x0c25, 2},
-  {-10, -17, 0x0d07, 2},
-  { 15, -12, 0x8d15, 0},
-  { 15,  -4, 0x8d05, 0},
-  {  0, -28, 0x0e08, 2},
-  { -8, -19, 0x0c20, 2},
-  {  8, -19, 0x4c20, 2},
-  {  0, -28, 0x0e08, 2},
-  {  0, -28, 0x0e08, 2},
-  { -8, -19, 0x0c20, 2},
-  {  8, -19, 0x4c20, 2},
-  { -8, -19, 0x0c20, 2},
-  {  8, -19, 0x4c20, 2},
-};
-static const uint8 kUncleDraw_Dma3[8] = {8, 8, 0, 0, 6, 6, 0, 0};
-static const uint8 kUncleDraw_Dma4[8] = {0, 0, 0, 0, 4, 4, 0, 0x8b}; // wtf
 static const uint8 kUncle_LeaveHouse_Delay[2] = {64, 224};
 static const uint8 kUncle_LeaveHouse_Dir[2] = {2, 1};
 static const int8 kUncle_LeaveHouse_Xvel[4] = {0, 0, -12, 12};
@@ -535,7 +483,7 @@
   &Sprite_11_Hinox,
   &Sprite_12_Moblin,
   &Sprite_13_MiniHelmasaur,
-  &Sprite_14_ThievesTownGrate_bounce,
+  &Sprite_14_ThievesTownGrate,
   &Sprite_15_Antifairy,
   &Sprite_16_Elder_bounce,
   &Sprite_17_Hoarder,
@@ -552,7 +500,7 @@
   &Sprite_22_Ropa,
   &Sprite_23_RedBari,
   &Sprite_23_RedBari,
-  &Sprite_25_TalkingTree_bounce,
+  &Sprite_25_TalkingTree,
   &Sprite_26_HardhatBeetle,
   &Sprite_27_Deadrock,
   &Sprite_28_DarkWorldHintNPC,
@@ -560,32 +508,32 @@
   &Sprite_SweepingLady,
   &Sprite_2B_Hobo,
   &Sprite_Lumberjacks,
-  &Sprite_2D_TelepathicTile_bounce,
+  &Sprite_2D_TelepathicTile,
   &Sprite_2E_FluteKid,
   &Sprite_MazeGameLady,
   &Sprite_MazeGameGuy,
   &Sprite_FortuneTeller,
   &Sprite_QuarrelBros,
-  &Sprite_33_RupeePull_bounce,
+  &Sprite_33_RupeePull,
   &Sprite_YoungSnitchLady,
   &Sprite_InnKeeper,
   &Sprite_Witch,
-  &Sprite_37_Waterfall_bounce,
-  &Sprite_38_EyeStatue_bounce,
+  &Sprite_37_Waterfall,
+  &Sprite_38_EyeStatue,
   &Sprite_39_Locksmith,
-  &Sprite_3A_MagicBat_bounce,
+  &Sprite_3A_MagicBat,
   &Sprite_DashItem,
   &Sprite_TroughBoy,
   &Sprite_OldSnitchLady,
   &Sprite_17_Hoarder,
-  &Sprite_TutorialGuardOrBarrier_bounce,
-  &Sprite_TutorialGuardOrBarrier_bounce,
+  &Sprite_TutorialGuardOrBarrier,
+  &Sprite_TutorialGuardOrBarrier,
   // Trampoline 48 entries
   &Sprite_41_BlueGuard,
   &Sprite_41_BlueGuard,
   &Sprite_41_BlueGuard,
   &Sprite_44_BluesainBolt,
-  &Sprite_45_UsainBolt,
+  &Sprite_45_HogSpearMan,
   &Sprite_46_BlueArcher,
   &Sprite_47_GreenBushGuard,
   &Sprite_48_RedJavelinGuard,
@@ -623,20 +571,20 @@
   &Sprite_66_WallCannonVerticalLeft,
   &Sprite_66_WallCannonVerticalLeft,
   &Sprite_6A_BallNChain,
-  &Sprite_CannonTrooper,
+  &Sprite_6B_CannonTrooper,
   &Sprite_6C_MirrorPortal,
   &Sprite_6D_Rat,
   &Sprite_6E_Rope,
   &Sprite_6F_Keese,
-  &Sprite_70_KingHelmasaurFireball_bounce,
+  &Sprite_70_KingHelmasaurFireball,
   &Sprite_71_Leever,
   &Sprite_72_FairyPond,
-  &Sprite_73_UncleAndPriest_bounce,
+  &Sprite_73_UncleAndPriest,
   &Sprite_RunningMan,
   &Sprite_BottleVendor,
   &Sprite_76_Zelda,
   &Sprite_15_Antifairy,
-  &Sprite_78_MrsSahasrahla_bounce,
+  &Sprite_78_MrsSahasrahla,
   // Trampoline 68 entries
   &Sprite_79_Bee,
   &Sprite_7A_Agahnim,
@@ -749,18 +697,18 @@
   &Sprite_E4_SmallKey,
   &Sprite_E4_SmallKey,
   &Sprite_D9_GreenRupee,
-  &Sprite_Mushroom,
-  &Sprite_FakeSword,
-  &Sprite_PotionShop,
+  &Sprite_E7_Mushroom,
+  &Sprite_E8_FakeSword,
+  &Sprite_E9_PotionShop,
   &Sprite_HeartContainer,
   &Sprite_HeartPiece,
   &Sprite_EC_ThrownItem,
-  &Sprite_SomariaPlatform,
-  &Sprite_MovableMantleTrampoline,
-  &Sprite_SomariaPlatform,
-  &Sprite_SomariaPlatform,
-  &Sprite_SomariaPlatform,
-  &Sprite_F2_MedallionTablet_bounce,
+  &Sprite_ED_SomariaPlatform,
+  &Sprite_EE_MovableMantle,
+  &Sprite_ED_SomariaPlatform,
+  &Sprite_ED_SomariaPlatform,
+  &Sprite_ED_SomariaPlatform,
+  &Sprite_F2_MedallionTablet,
 };
 static HandlerFuncK *const kSpritePrep_Main[243] = {
   &SpritePrep_Raven,
@@ -772,7 +720,7 @@
   &SpritePrep_Switch,
   &SpritePrep_SwitchFacingUp,
   &SpritePrep_Octorok,
-  &SpritePrep_Moldorm_bounce,
+  &SpritePrep_Moldorm,
   &SpritePrep_Octorok,
   &SpritePrep_DoNothingA,
   &SpritePrep_DoNothingA,
@@ -847,7 +795,7 @@
   &SpritePrep_DoNothingD,
   &SpritePrep_KingZora,
   &SpritePrep_ArmosKnight,
-  &SpritePrep_Lanmolas_bounce,
+  &SpritePrep_Lanmolas,
   &SpritePrep_SwimmingZora,
   &SpritePrep_WalkingZora,
   &SpritePrep_DesertStatue,
@@ -1371,7 +1319,7 @@
   }
 }
 
-void Sprite_MovableMantleTrampoline(int k) {
+void Sprite_EE_MovableMantle(int k) {
   MovableMantle_Draw(k);
   if (Sprite_ReturnIfInactive(k))
     return;
@@ -1467,7 +1415,7 @@
     SpriteDraw_Shadow_custom(k, &info, kSoldier_DrawShadow[sprite_D[k]]);
 }
 
-void Sprite_CannonTrooper(int k) {
+void Sprite_6B_CannonTrooper(int k) {
   if (sprite_C[k] != 0) {
     Sprite_Cannonball(k);
     return;
@@ -1716,7 +1664,7 @@
   garnish_countdown[j] = 15;
 }
 
-void Sprite_70_KingHelmasaurFireball_bounce(int k) {  // 85807f
+void Sprite_70_KingHelmasaurFireball(int k) {  // 85807f
   static const uint8 kHelmasaurFireball_Char[3] = {0xcc, 0xcc, 0xca};
   static const uint8 kHelmasaurFireball_Flags[2] = {0x33, 0x73};
   static const uint8 kHelmasaurFireball_Gfx[4] = {2, 2, 1, 0};
@@ -2590,8 +2538,6 @@
 }
 
 void Sprite_Beamos_Laser(int k) {  // 8591b5
-
-
   if (sprite_delay_aux1[k])
     return;
   BeamosLaser_Draw(k);
@@ -4918,7 +4864,7 @@
   }
 }
 
-void Sprite_45_UsainBolt(int k) {  // 85cbe0
+void Sprite_45_HogSpearMan(int k) {  // 85cbe0
   Guard_HandleAllAnimation(k);
   if (Sprite_ReturnIfInactive(k))
     return;
@@ -6427,7 +6373,7 @@
   }
 }
 
-void Sprite_Mushroom(int k) {  // 85ee78
+void Sprite_E7_Mushroom(int k) {  // 85ee78
   SpriteDraw_SingleLarge(k);
   if (Sprite_CheckIfLinkIsBusy())
     return;
@@ -6445,7 +6391,7 @@
   }
 }
 
-void Sprite_FakeSword(int k) {  // 85eeaf
+void Sprite_E8_FakeSword(int k) {  // 85eeaf
   FakeSword_Draw(k);
   if (Sprite_ReturnIfPaused(k))
     return;
@@ -6826,7 +6772,7 @@
   sprite_defl_bits[j] |= 0x20;
 }
 
-void Sprite_PotionShop(int k) {  // 85f633
+void Sprite_E9_PotionShop(int k) {  // 85f633
   switch(sprite_subtype2[k]) {
   case 0: Sprite_MagicShopAssistant_Main(k); return;
   case 1: Sprite_BagOfPowder(k); return;
@@ -7996,7 +7942,7 @@
   sprite_delay_main[k] = GetRandomNumber() & 127;
 }
 
-void SpritePrep_Moldorm_bounce(int k) {  // 868f8a
+void SpritePrep_Moldorm(int k) {  // 868f8a
   if (Sprite_ReturnIfBossFinished(k))
     return;
   sprite_ignore_projectile[k]++;
@@ -8003,7 +7949,7 @@
   Sprite_InitializedSegmented(k);
 }
 
-void SpritePrep_Lanmolas_bounce(int k) {  // 868f95
+void SpritePrep_Lanmolas(int k) {  // 868f95
   static const uint8 kLanmola_InitDelay[3] = {128, 192, 255};
 
   if (Sprite_ReturnIfBossFinished(k))
@@ -10586,7 +10532,7 @@
   if (Sprite_PrepOamCoordOrDoubleRet(k, &info))
     return;
   uint8 flags;
-  sprite_oam_flags[k] = flags = overworld_palette_swap_flag ? sprite_oam_flags[k] | 0xe : sprite_oam_flags[k] & ~0xe;
+  sprite_oam_flags[k] = flags = palette_swap_flag ? sprite_oam_flags[k] | 0xe : sprite_oam_flags[k] & ~0xe;
   uint8 r1 = sprite_B[k] >> 2 & 3;
 
   oam_cur_ptr += 4, oam_ext_cur_ptr += 1;
@@ -10899,7 +10845,7 @@
   }
 }
 
-void Sprite_73_UncleAndPriest_bounce(int k) {  // 86bfe0
+void Sprite_73_UncleAndPriest(int k) {  // 86bfe0
   switch (sprite_E[k]) {
   case 0:
     Sprite_Uncle(k);
@@ -10980,7 +10926,7 @@
   }
 }
 
-void Sprite_TutorialGuardOrBarrier_bounce(int k) {  // 86bffe
+void Sprite_TutorialGuardOrBarrier(int k) {  // 86bffe
   if (sprite_type[k] == 0x40) {
     Sprite_EvilBarrier(k);
     return;
@@ -11013,7 +10959,7 @@
   }
 }
 
-void Sprite_F2_MedallionTablet_bounce(int k) {  // 86c00d
+void Sprite_F2_MedallionTablet(int k) {  // 86c00d
   switch (sprite_subtype2[k]) {
   case 0:
     MedallionTablet_Main(k);
@@ -11024,7 +10970,7 @@
   }
 }
 
-void Sprite_33_RupeePull_bounce(int k) {  // 86c017
+void Sprite_33_RupeePull(int k) {  // 86c017
   PrepOamCoordsRet info;
   Sprite_PrepOamCoord(k, &info);
   if (Sprite_ReturnIfInactive(k))
@@ -11046,7 +10992,7 @@
   }
 }
 
-void Sprite_14_ThievesTownGrate_bounce(int k) {  // 86c01c
+void Sprite_14_ThievesTownGrate(int k) {  // 86c01c
   PrepOamCoordsRet info;
   Sprite_PrepOamCoord(k, &info);
   if (Sprite_ReturnIfInactive(k))
@@ -11079,7 +11025,7 @@
   SpritePrep_Snitches(k);
 }
 
-void Sprite_37_Waterfall_bounce(int k) {  // 86c03a
+void Sprite_37_Waterfall(int k) {  // 86c03a
   switch (sprite_subtype2[k]) {
   case 0: Waterfall(k); break;
   case 1: Sprite_BatCrash(k); break;
@@ -11086,7 +11032,7 @@
   }
 }
 
-void Sprite_38_EyeStatue_bounce(int k) {  // 86c03f
+void Sprite_38_EyeStatue(int k) {  // 86c03f
   if (!sprite_B[k]) {
     PrepOamCoordsRet info;
     Sprite_PrepOamCoord(k, &info);
@@ -11099,7 +11045,7 @@
   }
 }
 
-void Sprite_3A_MagicBat_bounce(int k) {  // 86c044
+void Sprite_3A_MagicBat(int k) {  // 86c044
   if (sprite_head_dir[k]) {
     Sprite_MadBatterBolt(k);
     return;
@@ -11206,7 +11152,7 @@
   }
 }
 
-void Sprite_78_MrsSahasrahla_bounce(int k) {  // 86c071
+void Sprite_78_MrsSahasrahla(int k) {  // 86c071
   ElderWife_Draw(k);
   if (Sprite_ReturnIfInactive(k))
     return;
@@ -11259,11 +11205,11 @@
   HeartUpgrade_CheckIfAlreadyObtained(k);
 }
 
-void Sprite_2D_TelepathicTile_bounce(int k) {  // 86c0b2
+void Sprite_2D_TelepathicTile(int k) {  // 86c0b2
   assert(0);
 }
 
-void Sprite_25_TalkingTree_bounce(int k) {  // 86c0d5
+void Sprite_25_TalkingTree(int k) {  // 86c0d5
   switch (sprite_subtype2[k]) {
   case 0: TalkingTree_Mouth(k); break;
   case 1: TalkingTree_Eye(k); break;
@@ -13176,6 +13122,59 @@
 }
 
 void Uncle_Draw(int k) {  // 8dd391
+  static const DrawMultipleData kUncleDraw_Table[48] = {
+    {  0, -10, 0x0e00, 2},
+    {  0,   0, 0x0c06, 2},
+    {  0, -10, 0x0e00, 2},
+    {  0,   0, 0x0c06, 2},
+    {  0, -10, 0x0e00, 2},
+    {  0,   0, 0x0c06, 2},
+    {  0, -10, 0x0e02, 2},
+    {  0,   0, 0x0c06, 2},
+    {  0, -10, 0x0e02, 2},
+    {  0,   0, 0x0c06, 2},
+    {  0, -10, 0x0e02, 2},
+    {  0,   0, 0x0c06, 2},
+    { -7,   2, 0x0d07, 2},
+    { -7,   2, 0x0d07, 2},
+    { 10,  12, 0x8d05, 0},
+    { 10,   4, 0x8d15, 0},
+    {  0, -10, 0x0e00, 2},
+    {  0,   0, 0x0c04, 2},
+    { -7,   1, 0x0d07, 2},
+    { -7,   1, 0x0d07, 2},
+    { 10,  13, 0x8d05, 0},
+    { 10,   5, 0x8d15, 0},
+    {  0,  -9, 0x0e00, 2},
+    {  0,   1, 0x4c04, 2},
+    { -7,   8, 0x8d05, 0},
+    {  1,   8, 0x8d06, 0},
+    {  0, -10, 0x0e02, 2},
+    { -6,  -1, 0x4d07, 2},
+    {  0,   0, 0x0c23, 2},
+    {  0,   0, 0x0c23, 2},
+    { -9,   7, 0x8d05, 0},
+    { -1,   7, 0x8d06, 0},
+    {  0,  -9, 0x0e02, 2},
+    { -6,   0, 0x4d07, 2},
+    {  0,   1, 0x0c25, 2},
+    {  0,   1, 0x0c25, 2},
+    {-10, -17, 0x0d07, 2},
+    { 15, -12, 0x8d15, 0},
+    { 15,  -4, 0x8d05, 0},
+    {  0, -28, 0x0e08, 2},
+    { -8, -19, 0x0c20, 2},
+    {  8, -19, 0x4c20, 2},
+    {  0, -28, 0x0e08, 2},
+    {  0, -28, 0x0e08, 2},
+    { -8, -19, 0x0c20, 2},
+    {  8, -19, 0x4c20, 2},
+    { -8, -19, 0x0c20, 2},
+    {  8, -19, 0x4c20, 2},
+  };
+  static const uint8 kUncleDraw_Dma3[8] = { 8, 8, 0, 0, 6, 6, 0, 0 };
+  static const uint8 kUncleDraw_Dma4[8] = { 0, 0, 0, 0, 4, 4, 0, 0x8b }; // wtf
+
   Oam_AllocateFromRegionB(0x18);
   const DrawMultipleData *src = &kUncleDraw_Table[sprite_D[k] * 12 + sprite_graphics[k] * 6];
 
@@ -13210,6 +13209,7 @@
     {-8, 14, 0x840a, 2},
     { 8, 14, 0xc40a, 2},
   };
+  sprite_graphics[k] = 0;
   Sprite_DrawMultiplePlayerDeferred(k, &kBugNetKid_Dmd[sprite_graphics[k] * 6], 6, NULL);
 }
 
@@ -22816,7 +22816,7 @@
   }
 
   sprite_obj_prio[k] |= kYellowStalfos_ObjPrio[sprite_ai_state[k]];
-  YellowStalfos_Draw(k);
+  YellowStalfos_Draw(k);  
   if (Sprite_ReturnIfInactive(k))
     return;
   if (link_sword_type >= 3) {
@@ -25466,7 +25466,7 @@
   sprite_graphics[k]++;
 }
 
-void Sprite_SomariaPlatform(int k) {  // 9ef6d4
+void Sprite_ED_SomariaPlatform(int k) {  // 9ef6d4
   switch(sprite_graphics[k]) {
   case 0: {
     SomariaPlatform_LocatePath(k);
--- a/sprite_main.h
+++ b/sprite_main.h
@@ -20,10 +20,10 @@
 void Sprite_WishPond3(int k);
 int Sprite_SpawnSmallSplash(int k);
 void HeartUpgrade_CheckIfAlreadyObtained(int k);
-void Sprite_MovableMantleTrampoline(int k);
+void Sprite_EE_MovableMantle(int k);
 void Sprite_GoodOrBadArcheryTarget(int k);
 void ChainBallTrooper_Draw(int k);
-void Sprite_CannonTrooper(int k);
+void Sprite_6B_CannonTrooper(int k);
 void Bee_PutInBottle(int k);
 void Sprite_Wizzbeam(int k);
 void Kiki_LyingInwait(int k);
@@ -37,7 +37,7 @@
 bool Landmine_CheckDetonationFromHammer(int k);
 void Sprite_DrawLargeWaterTurbulence(int k);
 void Sprite_SpawnSparkleGarnish(int k);
-void Sprite_70_KingHelmasaurFireball_bounce(int k);
+void Sprite_70_KingHelmasaurFireball(int k);
 void Sprite_66_WallCannonVerticalLeft(int k);
 void Sprite_65_ArcheryGame(int k);
 void ArcheryGame_Host(int k);
@@ -142,7 +142,7 @@
 void Guard_AnimateHead(int k, int oam_offs, const PrepOamCoordsRet *poc);
 void Guard_AnimateBody(int k, int oam_idx, const PrepOamCoordsRet *poc);
 void Guard_AnimateWeapon(int k, const PrepOamCoordsRet *poc);
-void Sprite_45_UsainBolt(int k);
+void Sprite_45_HogSpearMan(int k);
 void BoltGuard_TriggerChaseTheme(int k);
 void Sprite_44_BluesainBolt(int k);
 void PsychoTrooper_Draw(int k);
@@ -200,8 +200,8 @@
 void Zelda_EnteringSanctuary(int k);
 void Zelda_AtSanctuary(int k);
 void SpritePrep_Mushroom(int k);
-void Sprite_Mushroom(int k);
-void Sprite_FakeSword(int k);
+void Sprite_E7_Mushroom(int k);
+void Sprite_E8_FakeSword(int k);
 void FakeSword_Draw(int k);
 void SpritePrep_HeartContainer(int k);
 void Sprite_HeartContainer(int k);
@@ -222,7 +222,7 @@
 void MagicShopAssistant_SpawnGreenCauldron(int k);
 void MagicShopAssistant_SpawnBlueCauldron(int k);
 void MagicShopAssistant_SpawnRedCauldron(int k);
-void Sprite_PotionShop(int k);
+void Sprite_E9_PotionShop(int k);
 void Sprite_BagOfPowder(int k);
 void MagicPowderItem_Draw(int k);
 void Sprite_GreenCauldron(int k);
@@ -331,8 +331,8 @@
 void SpritePrep_DesertStatue(int k);
 void SpritePrep_DoNothingD(int k);
 void SpritePrep_Octorok(int k);
-void SpritePrep_Moldorm_bounce(int k);
-void SpritePrep_Lanmolas_bounce(int k);
+void SpritePrep_Moldorm(int k);
+void SpritePrep_Lanmolas(int k);
 void SpritePrep_BigSpike(int k);
 void SpritePrep_SwimmingZora(int k);
 void SpritePrep_Geldman(int k);
@@ -459,24 +459,24 @@
 void SpritePrep_Hobo_SpawnFire(int k);
 void Sprite_Hobo_Smoke(int k);
 void Hobo_SpawnSmoke(int k);
-void Sprite_73_UncleAndPriest_bounce(int k);
+void Sprite_73_UncleAndPriest(int k);
 void SpritePrep_UncleAndPriest_bounce(int k);
 void SpritePrep_OldMan_bounce(int k);
-void Sprite_TutorialGuardOrBarrier_bounce(int k);
-void Sprite_F2_MedallionTablet_bounce(int k);
-void Sprite_33_RupeePull_bounce(int k);
-void Sprite_14_ThievesTownGrate_bounce(int k);
+void Sprite_TutorialGuardOrBarrier(int k);
+void Sprite_F2_MedallionTablet(int k);
+void Sprite_33_RupeePull(int k);
+void Sprite_14_ThievesTownGrate(int k);
 void SpritePrep_Snitch_bounce_2(int k);
 void SpritePrep_Snitch_bounce_3(int k);
-void Sprite_37_Waterfall_bounce(int k);
-void Sprite_38_EyeStatue_bounce(int k);
-void Sprite_3A_MagicBat_bounce(int k);
+void Sprite_37_Waterfall(int k);
+void Sprite_38_EyeStatue(int k);
+void Sprite_3A_MagicBat(int k);
 void SpritePrep_Zelda_bounce(int k);
-void Sprite_78_MrsSahasrahla_bounce(int k);
+void Sprite_78_MrsSahasrahla(int k);
 void Sprite_16_Elder_bounce(int k);
 void SpritePrep_HeartPiece(int k);
-void Sprite_2D_TelepathicTile_bounce(int k);
-void Sprite_25_TalkingTree_bounce(int k);
+void Sprite_2D_TelepathicTile(int k);
+void Sprite_25_TalkingTree(int k);
 void Sprite_1C_Statue(int k);
 bool Statue_CheckForSwitch(int k);
 void MovableStatue_Draw(int k);
@@ -939,7 +939,7 @@
 void Sprite_Apple(int k);
 void Sprite_BC_Drunkard(int k);
 void SomariaPlatform_LocatePath(int k);
-void Sprite_SomariaPlatform(int k);
+void Sprite_ED_SomariaPlatform(int k);
 void SomariaPlatformAndPipe_HandleMovement(int k);
 uint8 SomariaPlatformAndPipe_CheckTile(int k);
 void SomariaPlatform_Draw(int k);
--- a/tables/compile_resources.py
+++ b/tables/compile_resources.py
@@ -6,11 +6,9 @@
 import tables
 import compile_music
 import array, hashlib, struct
+from functools import cache
+import sprite_sheets
 
-print_int_array = util.print_int_array
-
-PATH = ''
-
 def flatten(xss):
     return [x for xs in xss for x in xs]
   
@@ -19,7 +17,6 @@
 
 assets = {}
 
-
 def add_asset_uint8(name, data):
   assert name not in assets
   assets[name] = ('uint8', bytes(array.array('B', data)))
@@ -38,7 +35,7 @@
 
 def print_map32_to_map16():
   tab = {}
-  for line in open(PATH + 'map32_to_map16.txt'):
+  for line in open('map32_to_map16.txt'):
     line = line.strip()
     x, xs = line.split(':', 1)
     tab[int(x)] = [int(t) for t in xs.split(',')]
@@ -67,7 +64,7 @@
 def print_dialogue():
   new_r = []
   offs = []
-  for line in open(PATH + 'dialogue.txt'):
+  for line in open('dialogue.txt'):
     line = line.strip('\n')
     a, b = line.split(': ', 1)
     index = int(a)
@@ -80,41 +77,6 @@
 
 ROM = util.LoadedRom(sys.argv[1] if len(sys.argv) >= 2 else None)
 
-kCompSpritePtrs = [
-  0x10f000,0x10f600,0x10fc00,0x118200,0x118800,0x118e00,0x119400,0x119a00,
-  0x11a000,0x11a600,0x11ac00,0x11b200,0x14fffc,0x1585d4,0x158ab6,0x158fbe,
-  0x1593f8,0x1599a6,0x159f32,0x15a3d7,0x15a8f1,0x15aec6,0x15b418,0x15b947,
-  0x15bed0,0x15c449,0x15c975,0x15ce7c,0x15d394,0x15d8ac,0x15ddc0,0x15e34c,
-  0x15e8e8,0x15ee31,0x15f3a6,0x15f92d,0x15feba,0x1682ff,0x1688e0,0x168e41,
-  0x1692df,0x169883,0x169cd0,0x16a26e,0x16a275,0x16a787,0x16aa06,0x16ae9d,
-  0x16b3ff,0x16b87e,0x16be6b,0x16c13d,0x16c619,0x16cbbb,0x16d0f1,0x16d641,
-  0x16d95a,0x16dd99,0x16e278,0x16e760,0x16ed25,0x16f20f,0x16f6b7,0x16fa5f,
-  0x16fd29,0x1781cd,0x17868d,0x178b62,0x178fd5,0x179527,0x17994b,0x179ea7,
-  0x17a30e,0x17a805,0x17acf8,0x17b2a2,0x17b7f9,0x17bc93,0x17c237,0x17c78e,
-  0x17cd55,0x17d2bc,0x17d82f,0x17dcec,0x17e1cc,0x17e36b,0x17e842,0x17eb38,
-  0x17ed58,0x17f06c,0x17f4fd,0x17fa39,0x17ff86,0x18845c,0x1889a1,0x188d64,
-  0x18919d,0x189610,0x189857,0x189b24,0x189dd2,0x18a03f,0x18a4ed,0x18a7ba,
-  0x18aedf,0x18af0d,0x18b520,0x18b953,
-]
-
-kCompBgPtrs = [
-  0x11b800,0x11bce2,0x11c15f,0x11c675,0x11cb84,0x11cf4c,0x11d2ce,0x11d726,
-  0x11d9cf,0x11dec4,0x11e393,0x11e893,0x11ed7d,0x11f283,0x11f746,0x11fc21,
-  0x11fff2,0x128498,0x128a0e,0x128f30,0x129326,0x129804,0x129d5b,0x12a272,
-  0x12a6fe,0x12aa77,0x12ad83,0x12b167,0x12b51d,0x12b840,0x12bd54,0x12c1c9,
-  0x12c73d,0x12cc86,0x12d198,0x12d6b1,0x12db6a,0x12e0ea,0x12e6bd,0x12eb51,
-  0x12f135,0x12f6c5,0x12fc71,0x138129,0x138693,0x138bad,0x139117,0x139609,
-  0x139b21,0x13a074,0x13a619,0x13ab2b,0x13b00c,0x13b4f5,0x13b9eb,0x13bebf,
-  0x13c3ce,0x13c817,0x13cb68,0x13cfb5,0x13d460,0x13d8c2,0x13dd7a,0x13e266,
-  0x13e7af,0x13ece5,0x13f245,0x13f6f0,0x13fc30,0x1480e9,0x14863b,0x148a7c,
-  0x148f2a,0x149346,0x1497ed,0x149cc2,0x14a173,0x14a61d,0x14ab5d,0x14b083,
-  0x14b4bd,0x14b94e,0x14be0e,0x14c291,0x14c7ba,0x14cce4,0x14d1db,0x14d6bd,
-  0x14db77,0x14ded1,0x14e2ac,0x14e754,0x14ebae,0x14ef4e,0x14f309,0x14f6f4,
-  0x14fa55,0x14ff8c,0x14ff93,0x14ff9a,0x14ffa1,0x14ffa8,0x14ffaf,0x14ffb6,
-  0x14ffbd,0x14ffc4,0x14ffcb,0x14ffd2,0x14ffd9,0x14ffe0,0x14ffe7,0x14ffee,
-  0x14fff5,0x18b520,0x18b953,
-]
-
 def compress_store(r):
   rr = []
   j, jend = 0, len(r)
@@ -135,19 +97,23 @@
   return b''.join([struct.pack('I', i) for i in all_offs] + arr)
 
 def print_images():
-  lengths = b''
+  sprsheet = sprite_sheets.load_sprite_sheets()
+
   all = []
-  for i in range(12):
-    all.append(bytes(ROM.get_bytes(kCompSpritePtrs[i], 0x600)))
-  for i in range(12, 108):
-    decomp, comp_len = util.decomp(kCompSpritePtrs[i], ROM.get_byte, False, True)
-    all.append(bytes(ROM.get_bytes(kCompSpritePtrs[i], comp_len)))
+  for i in range(108):
+    if sprsheet != None and i < 103:
+      all.append(sprsheet.encode_sheet_in_snes_format(i))
+    elif i < 12:
+      all.append(bytes(ROM.get_bytes(tables.kCompSpritePtrs[i], 0x600)))   
+    else:
+      decomp, comp_len = util.decomp(tables.kCompSpritePtrs[i], ROM.get_byte, False, True)
+      all.append(bytes(ROM.get_bytes(tables.kCompSpritePtrs[i], comp_len)))
   add_asset_uint8('kSprGfx', pack_u32_arrays(all))
 
   all = []
-  for i in range(len(kCompBgPtrs)):
-    decomp, comp_len = util.decomp(kCompBgPtrs[i], ROM.get_byte, False, True)
-    all.append(bytes(ROM.get_bytes(kCompBgPtrs[i], comp_len)))
+  for i in range(len(tables.kCompBgPtrs)):
+    decomp, comp_len = util.decomp(tables.kCompBgPtrs[i], ROM.get_byte, False, True)
+    all.append(bytes(ROM.get_bytes(tables.kCompBgPtrs[i], comp_len)))
   add_asset_uint8('kBgGfx', pack_u32_arrays(all))
 
 
@@ -193,13 +159,10 @@
 
   add_asset_uint16('kOverworldMapPaletteData', ROM.get_words(0x8ADB27, 256))
 
-g_overworld_yaml_cache = {}
+@cache
 def load_overworld_yaml(room):
-  if room not in g_overworld_yaml_cache:
-    g_overworld_yaml_cache[room] = yaml.safe_load(open(PATH+'overworld/overworld-%d.yaml' % room, 'r'))
-  return g_overworld_yaml_cache[room]
+  return yaml.safe_load(open('overworld/overworld-%d.yaml' % room, 'r'))
     
-
 def print_overworld():
   r = []
   for i in range(160):
@@ -465,11 +428,9 @@
   add_asset_uint8('kDungMap_Tiles', pack_u32_arrays(r2))
 
 
-g_dungeon_yaml_cache = {}
+@cache
 def load_dungeon_yaml(room):
-  if room not in g_dungeon_yaml_cache:
-    g_dungeon_yaml_cache[room] = yaml.safe_load(open(PATH+'dungeon/dungeon-%d.yaml' % room, 'r'))
-  return g_dungeon_yaml_cache[room]
+  return yaml.safe_load(open('dungeon/dungeon-%d.yaml' % room, 'r'))
   
 def print_dungeon_sprites():
   offsets=[0 for i in range(320)]
@@ -700,7 +661,7 @@
 
   data = []
   offsets = [0] * 8
-  default_yaml = yaml.safe_load(open(PATH+'dungeon/default_rooms.yaml', 'r'))
+  default_yaml = yaml.safe_load(open('dungeon/default_rooms.yaml', 'r'))
   for i in range(len(offsets)):
     offsets[i] = len(data)
     print_layer(default_yaml['Default%d' % i], None)
@@ -709,7 +670,7 @@
 
   data = []
   offsets = [0] * 19
-  overlay_yaml = yaml.safe_load(open(PATH+'dungeon/overlay_rooms.yaml', 'r'))
+  overlay_yaml = yaml.safe_load(open('dungeon/overlay_rooms.yaml', 'r'))
   for i in range(len(offsets)):
     offsets[i] = len(data)
     print_layer(overlay_yaml['Overlay%d' % i], None)
@@ -746,7 +707,7 @@
     add_asset_uint8('kBgTilemap_%d' % i, ROM.get_bytes(s, l))
 
 def print_link_graphics():
-  image = Image.open(PATH+'linksprite.png')
+  image = Image.open('linksprite.png')
   data = image.tobytes()
   def encode_4bit_sprite(data, offset, pitch):
     b = [0] * 32
@@ -768,7 +729,6 @@
   for song in ['intro', 'indoor', 'ending']:
     name, data = compile_music.print_song(song)
     add_asset_uint8(name, data)
-
 
 def print_all():
   print_sound_banks()
--- a/tables/extract_resources.py
+++ b/tables/extract_resources.py
@@ -2,31 +2,14 @@
 import sys
 import text_compression
 import util
-from PIL import Image
+from util import get_bytes, get_words, get_byte, get_word, get_int8, get_int16
 import tables
 import yaml
 import extract_music
 import os
+import sprite_sheets
+from functools import cache
 
-PATH=''
-
-ROM = util.LoadedRom(sys.argv[1] if len(sys.argv) >= 2 else None)
-
-get_byte = ROM.get_byte
-get_word = ROM.get_word
-get_bytes = ROM.get_bytes
-
-def get_int8(ea):
-  b = get_byte(ea)
-  if b & 0x80: b -= 256
-  return b
-
-def get_int16(ea):
-  b = get_word(ea)
-  if b & 0x8000: b -= 65536
-  return b
-
-
 def print_map32_to_map16(f):
   for i in range(2218):
     def getit(ea):
@@ -44,6 +27,7 @@
     for j in range(4):
       print('%5d: %4d, %4d, %4d, %4d' % (i * 4 + j, t0[j], t1[j], t2[j], t3[j]), file = f)
 
+@cache
 def get_exit_datas():
   r = {}
   for i in range(79):
@@ -99,7 +83,6 @@
       y['door'] = ['palace' if fdoor & 0x8000 else 'sanctuary', (fdoor & 0x7e) >> 1, (fdoor & 0x3f80) >> 7]
     r.setdefault(screen_index, []).append(y)
   return r
-EXIT_DATAS = get_exit_datas()
 
 def get_loadoffs(c, d):
   x, y = c[0] >> 4, c[1] >> 4
@@ -107,6 +90,7 @@
   y += d[1]
   return (y&0x3f) << 7 | (x&0x3f) << 1
 
+@cache
 def get_ow_travel_infos():
   r = {}
   for i in range(17):
@@ -138,8 +122,8 @@
     y['unk'] = [unk1, unk3]
     r.setdefault(screen_index, []).append(y)
   return r
-OW_TRAVEL_INFOS = get_ow_travel_infos()
 
+@cache
 def get_ow_entrance_info():
   r = {}
   for i in range(129):
@@ -148,8 +132,8 @@
     entrance_id = get_byte(0x9BBB73 + i)
     r.setdefault(area, []).append({'index' : i, 'x' : (pos >> 1) & 0x3f, 'y' : (pos >> 7) & 0x3f, 'entrance_id' : entrance_id})
   return r
-OW_ENTRANCE_INFO = get_ow_entrance_info()
 
+@cache
 def get_hole_infos():
   r = {}
   for i in range(19):
@@ -158,7 +142,6 @@
     entrance_id = get_byte(0x9BB84C + i)
     r.setdefault(area, []).append({'x' : (pos >> 1) & 0x3f, 'y' : (pos >> 7) & 0x3f, 'entrance_id' : entrance_id})
   return r
-HOLE_INFO = get_hole_infos()
 
 def print_overworld_area(overworld_area):
   is_small = get_bytes(0x82F88D, 192)
@@ -204,11 +187,12 @@
   }
       
   y['Header'] = header
-  y['Travel'] = OW_TRAVEL_INFOS.get(overworld_area, [])
-  y['Entrances'] = OW_ENTRANCE_INFO.get(overworld_area, [])
-  if overworld_area in HOLE_INFO:
-    y['Holes'] = HOLE_INFO[overworld_area]
-  y['Exits'] = EXIT_DATAS.get(overworld_area, [])
+  y['Travel'] = get_ow_travel_infos().get(overworld_area, [])
+  y['Entrances'] = get_ow_entrance_info().get(overworld_area, [])
+  hole_infos = get_hole_infos()
+  if overworld_area in hole_infos:
+    y['Holes'] = hole_infos[overworld_area]
+  y['Exits'] = get_exit_datas().get(overworld_area, [])
   y['Items'] = get_items()
   
   def decode_sprites(base_addr):
@@ -247,10 +231,10 @@
     }
     
   s = yaml.dump(y, default_flow_style=None, sort_keys=False)
-  open(PATH+'overworld/overworld-%d.yaml' % overworld_area, 'w').write(s)
+  open('overworld/overworld-%d.yaml' % overworld_area, 'w').write(s)
 
 def print_all_overworld_areas():
-  area_heads = ROM.get_bytes(0x82A5EC, 64)
+  area_heads = get_bytes(0x82A5EC, 64)
   
   for i in range(160):
     if i >= 128 or area_heads[i&63] == (i&63):
@@ -259,124 +243,6 @@
 def print_dialogue():
   text_compression.print_strings(open('dialogue.txt', 'w'), get_byte)
 
-def decomp_one_spr_2bit(data, offs, target, toffs, pitch):
-  for y in range(8):
-    d0, d1 = data[offs + y * 2], data[offs + y * 2 + 1]
-    for x in range(8):
-      t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2
-      target[toffs + y * pitch + (7 - x)] = t * 255 // 3
-
-def decomp_one_spr_3bit(data, offs, target, toffs, pitch):
-  for y in range(8):
-    d0, d1, d2 = data[offs + y * 2], data[offs + y * 2 + 1], data[offs + y + 16]
-    for x in range(8):
-      t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2 + ((d2 >> x) & 1) * 4
-      target[toffs + y * pitch + (7 - x)] = t * 255 // 7
-
-def decomp_one_spr_4bit(data, offs, target, toffs, pitch):
-  for y in range(8):
-    d0, d1, d2, d3 = data[offs + y * 2 + 0], data[offs + y * 2 + 1], data[offs + y * 2 + 16], data[offs + y * 2 + 17]
-    for x in range(8):
-      t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2 + ((d2 >> x) & 1) * 4 + ((d3 >> x) & 1) * 8
-      target[toffs + y * pitch + (7 - x)] = t
-
-def save_array_as_image(dimensions, data, fname, palette = None):
-  img = Image.new('L' if palette == None else 'P', dimensions)
-  img.putdata(data)
-  if palette != None:
-    img.putpalette(palette)
-  img.save(fname)
-
-
-def decomp_save(data, fname, func, step, height=32, palette=None):
-  dst=[0]*128*height
-  for i in range(16*height//8):
-    x = i % 16
-    y = i // 16
-    func(data, i * step, dst, x * 8 + y * 8 * 128, 128)
-  save_array_as_image((128, height), dst, fname, palette)
-
-def convert_snes_palette(v):
-  r=[]
-  for x in v:
-    r.extend(((x & 0x1f) << 3, (x >> 5 & 0x1f) << 3, (x >> 10 & 0x1f) << 3))
-  return r
-
-
-def decode_link_sprites():
-  kLinkPalette = [0, 0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x599d, 0x3647, 0x3b68,  0xa4a, 0x12ef, 0x2a5c, 0x1571, 0x7a18]
-  decomp_save(get_bytes(0x108000, 32768), PATH+'linksprite.png',
-              decomp_one_spr_4bit, 32, 448, convert_snes_palette(kLinkPalette))
-
-def decomp_save_2bit(data, fname):
-  dst=[0]*128*64
-  for i in range(128):
-    x = i % 16
-    y = i // 16
-    decomp_one_spr_2bit(data, i * 16, dst, x * 8 + y * 8 * 128, 128)
-  img = Image.new("L", (128, 64))
-  img.putdata(dst)
-  img.save(fname)
-
-
-gfx_desc = {
-  0x00 : ('3bpp_np', 'Half slot images'),
-  
-  0x01 : ('3bpp_np', 'Half slot images'),
-  0x02 : ('3bpp_np', 'Half slot images'),
-  0x03 : ('3bpp_np', 'Half slot images'),
-  0x04 : ('3bpp_np', 'Half slot images'),
-  0x05 : ('3bpp_np', 'Half slot images'),
-
-  0x06 : ('3bpp_np', 'common spr gfx'),
-  0x07 : ('3bpp_np', 'common spr gfx'),
-
-  0x08 : ('3bpp_np', 'Half slot images'),
-  0x09 : ('3bpp_np', 'Half slot images'),
-  0x0a : ('3bpp_np', 'Half slot images'),
-  0x0b : ('3bpp_np', 'Half slot images'),
-
-  88 : ('3bpp', 'Tagalong gfx'),
-  89 : ('3bpp', 'Tagalong gfx'),
-
-  90 : ('3bpp', 'animated sprites'),
-  91 : ('3bpp', 'animated sprites'),
-  92 : ('3bpp', 'animated sprites'),
-  93 : ('3bpp', 'animated sprites'),
-  94 : ('3bpp', 'sword/shield gfx'),
-  95 : ('3bpp', 'sword/shield gfx'),
-  
-
-  100 : ('3bpp', 'Tagalong gfx'),
-  101 : ('3bpp', 'Tagalong gfx'),
-  102 : ('3bpp', 'Tagalong gfx'),
-  
-  103 : ('2bpp', 'Attract images loaded to 7800'),
-  104 : ('2bpp', 'empty'),
-  105 : ('2bpp', 'hud icons loaded to 7xxx'),
-  106 : ('2bpp', 'hud icons loaded to 7xxx'),
-  107 : ('2bpp', 'hud icons loaded to 7xxx'),
-}
-
-def decomp_generic(k, mode, fname_add = "misc"):
-  fname = 'img/%.3d - %s.png' % (k, fname_add)
-  if mode == '2bpp':
-    r = util.decomp(kCompSpritePtrs[k], get_byte, False)
-    decomp_save_2bit(r, fname)
-  elif mode == '3bpp_np':
-    print(k)
-    r = get_bytes(kCompSpritePtrs[k], 0x600)
-    decomp_save(r, fname, decomp_one_spr_3bit, 24)
-  elif mode== '3bpp':
-    r = util.decomp(kCompSpritePtrs[k], get_byte, False)
-    decomp_save(r, fname, decomp_one_spr_3bit, 24)
-  else:
-    assert 0
-
-if 0:
-  for k, v in gfx_desc.items():
-    decomp_generic(k, v[0])
-
 def decode_room_objects(p):
   objs = []
   j = 0
@@ -418,6 +284,7 @@
     doors.append({'type':get_byte(p + 1), 'pos' : get_byte(p) >> 4, 'dir' : A & 3})
     p += 2
 
+@cache
 def get_chest_info():
   ea = 0x81e96e
   all = {}
@@ -427,8 +294,6 @@
     all.setdefault(room & 0x7fff, []).append((data, (room & 0x8000) != 0))
   return all
 
-CHEST_INFO = get_chest_info()
-
 def _get_entrance_info_one(i, set):
   def get_exit_door(i):
     x = get_word((0x82D724, 0x82DC32)[set] + i * 2)
@@ -498,7 +363,7 @@
     y['associated_entrance_index'] = get_word(0x82DC40 + i * 2)
   return room, y 
 
-
+@cache
 def get_entrance_info(set):
   r = {}
   for i in range(133 if set == 0 else 7):
@@ -506,9 +371,9 @@
     r.setdefault(room, []).append(y)
   return r
 
-ENTRANCE_INFO = get_entrance_info(0)
-STARTING_POINT_INFO = get_entrance_info(1)
-PITS_HURT_PLAYER = set(get_word(0x80990C + i * 2) for i in range(57))
+@cache 
+def pits_hurt_player():
+  return set(get_word(0x80990C + i * 2) for i in range(57))
 
 def print_room(room_index):
   p = 0x1f8000 + room_index * 3
@@ -545,7 +410,7 @@
     'stair3_dest' : [get_byte(p+13),p8 & 3],
     'tele_msg' : get_word(0x87F61D+room_index*2),
     'sort_sprites' : sort_sprites_setting,
-    'pits_hurt_player' : room_index in PITS_HURT_PLAYER
+    'pits_hurt_player' : room_index in pits_hurt_player()
   }
 
   def get_sprites():
@@ -587,7 +452,7 @@
 
   def get_chests():
     r = []
-    for data, big in CHEST_INFO.get(room_index, []):
+    for data, big in get_chest_info().get(room_index, []):
       if big:
         r.append('%d!' % data)
       else:
@@ -598,9 +463,9 @@
   secrets = get_secrets()
 
   data = {'Header' : header, 'Sprites' : sprites, 'Secrets' : secrets, 'Chests' : get_chests()}
-  data['Entrances'] = ENTRANCE_INFO.get(room_index, [])
-  if room_index in STARTING_POINT_INFO:
-    data['StartingPoints'] = STARTING_POINT_INFO[room_index]
+  data['Entrances'] = get_entrance_info(0).get(room_index, [])
+  if room_index in get_entrance_info(1):
+    data['StartingPoints'] = get_entrance_info(1)[room_index]
 
   p = room_addr + 2
   p, objs, doors = decode_room_objects(p)
@@ -615,13 +480,12 @@
   data['Layer3'] = objs
   if doors: data['Layer3.doors'] = doors
   
-  
   return yaml.dump(data, default_flow_style=None, sort_keys=False)
 
 def print_all_dungeon_rooms():
   for i in range(320):
     s = print_room(i)
-    open(PATH + 'dungeon/dungeon-%d.yaml' % i, 'w').write(s)
+    open( 'dungeon/dungeon-%d.yaml' % i, 'w').write(s)
 
 def print_default_rooms():
   def print_default_room(idx):
@@ -634,7 +498,7 @@
   for i in range(8):
     default_rooms['Default%d' % i] = print_default_room(i)
   s = yaml.dump(default_rooms, default_flow_style=None, sort_keys=False)
-  open(PATH + 'dungeon/default_rooms.yaml', 'w').write(s)
+  open('dungeon/default_rooms.yaml', 'w').write(s)
 
 def print_overlay_rooms():
   def print_overlay_room(idx):
@@ -647,21 +511,26 @@
   for i in range(19):
     default_rooms['Overlay%d' % i] = print_overlay_room(i)
   s = yaml.dump(default_rooms, default_flow_style=None, sort_keys=False)
-  open(PATH + 'dungeon/overlay_rooms.yaml', 'w').write(s)
+  open('dungeon/overlay_rooms.yaml', 'w').write(s)
 
-def print_all():
+def make_directories():
   os.makedirs('img', exist_ok=True)
   os.makedirs('overworld', exist_ok=True)
   os.makedirs('dungeon', exist_ok=True)
   os.makedirs('sound', exist_ok=True)
+
+def print_all_text_stuff():
   print_all_overworld_areas()
-  decode_link_sprites()
   print_all_dungeon_rooms()
   print_overlay_rooms()
   print_default_rooms()
   print_dialogue()
-  print_map32_to_map16(open(PATH+'map32_to_map16.txt', 'w'))
-  extract_music.extract_sound_data(ROM)
+  print_map32_to_map16(open('map32_to_map16.txt', 'w'))
+  
+ROM = util.load_rom(sys.argv[1] if len(sys.argv) >= 2 else None)
 
-
-print_all()
+make_directories()
+print_all_text_stuff()
+extract_music.extract_sound_data(ROM)
+sprite_sheets.decode_link_sprites()
+sprite_sheets.decode_sprite_sheets()
--- /dev/null
+++ b/tables/sprite_sheet_info.py
@@ -1,0 +1,1547 @@
+class Entry:
+  def __init__(self, name, dungeon_or_ow, tileset_and_pal, ss_idx, matrix, pal_base):
+    self.name = name
+    self.dungeon_or_ow = dungeon_or_ow
+    self.tileset, self.palset_idx = tileset_and_pal
+    self.ss_idx = ss_idx
+    self.matrix = matrix
+    self.pal_base = pal_base
+
+entries = []
+def add(name, lw = None, dw = None, sheet = None, ow = None, dung = None, ss_1 = None, ss_2 = None, ss_3 = None, ss_4 = None, palette = None):
+  def doit(tileset_and_pal, dungeon_or_ow, suffix = ''):
+    all_chars = sorted(set("".join([ss.lower() for ss in (ss_1, ss_2, ss_3, ss_4) if ss != None])))
+    for ch in all_chars:
+      if ch == '\n' or ch == '.' or ch == 'o': continue
+      for ss_idx, ss in enumerate((ss_1, ss_2, ss_3, ss_4)):
+        if ss == None: continue
+        ss = ss.lower().replace('o', 'x')
+        matrix = ss.splitlines()[1:]
+        assert len(matrix) == 4 and all(len(m) == 16 for m in matrix), name
+        matrix2 = [[('x' if x == ch else '.') for x in m] for m in matrix]
+        if any('x' in m for m in matrix2):
+          entries.append(Entry(name + suffix, dungeon_or_ow, tileset_and_pal, ss_idx, matrix2, palette if ch == 'x' else int(ch)))
+
+  if lw and dw:
+    doit(lw, 0, ' - LW')
+    doit(dw, 1, ' - DW')
+  elif lw:
+    doit(lw, 0)
+  elif dw:
+    doit(dw, 1)
+  elif ow:
+    doit(ow, 0)
+  elif dung:
+    doit(dung, 2)
+  elif sheet:
+    doit(sheet, 3)
+
+
+add("00 - Raven", lw=(4, 3), dw=(23, 13), ss_4 = """
+....XXXXXX......
+....XXXXXX......
+................
+................""")
+
+add("01 - Vulture", ow=(8, 4), ss_3 = """
+XXXXXXXX........
+XXXXXXXX........
+................
+................""")
+
+add("04 - PullSwitch", dung=(6, 29), ss_4 = """
+..............XX
+..............XX
+..............XX
+..............XX""")
+
+add("07 - PullSwitch2", dung=(4, 0), ss_3 = """
+................
+................
+..XXXX..........
+..XXXX..........""")
+
+add("08 - Octorok", lw=(11, 3), dw=(22, 10), ss_3 = """
+XXXXXX..........
+XXXXXX..........
+XXXX.....XXX....
+XXXX....XXXXX...""")
+
+add("09 - Moldorm", dung=(12, 6), ss_3 = """
+5555555555666666
+5555555555666666
+5555555566666666
+5555555566666666""")
+
+add("0b - Chicken", lw=(6, 1), dw=(21, 16), ss_4 = """
+................
+................
+..........XXXX..
+..........XXXX..""")
+
+add("0d - Buzzblob", ow=(7, 6), ss_4 = """
+..........XXXXXX
+..........XXXXXX
+XXXXXX..........
+XXXX............""")
+
+add("0e - SnapDragon", ow=(19, 14), ss_1 = """
+................
+................
+........XXXX....
+........XXXXXXXX""", ss_3 = """
+............XXXX
+............XXXX
+..........XXXXXX
+..........XXXXXX""")
+
+add("0f - Octoballon", ow=(4, 3), ss_3 = """
+......XX....XX..
+......XX....XX..
+............XX..
+.............X..""")
+
+add("11 - Hinox", dw=(19, 14), ss_1 = """
+33333333....3333
+33333333....3333
+333333......3333
+333333..........""")
+
+add("12 - Moblin", ow=(19, 14), ss_3 = """
+XXXXXXXXXXXX....
+XXXXXXXXXXXX....
+XXXXXXXXXX......
+XXXXXXXXXX......""")
+
+add("13 - MiniHelmasaur", dung=(12, 26), ss_2 = """
+..............XX
+............X.XX
+....XXXXXXXXXXXX
+....XXXXXXXXXXXX""")
+
+add("15 - Antifairy", dung=(8, 10), ss_4 = """
+................
+................
+.1.1............
+................""")
+
+# Aginah is (16, 7)
+add("16 - Elder", dung=(16, 28), ss_3 = """
+................
+................
+XXXXXX..........
+XXXXXX..........""")
+
+add("17 - Hoarder", ow=(4, 3), ss_4 = """
+................
+................
+......XXXX......
+......XXXX......""")
+
+
+add("18 - MiniMoldorm", dung=(19, 13), ss_2 = """
+.............X..
+.............X..
+XXXX............
+XXXX............""")
+
+add("19 - Poe", lw=(3, 2), dw=(21, 16), ss_4 = """
+................
+................
+......XX........
+......XX........""")
+
+add("1a - Smithy", dung=(5, 30), ss_2 = """
+XXXXXX..........
+XXXXXX..........
+XXXXXX..........
+XXXXXX..........""")
+
+add("1a - Smithy", ow=(29, 0), ss_4 = """
+........XX......
+........XX......
+................
+................""")
+
+add("1c - Statue", dung=(17, 10), ss_4 = """
+XXX.............
+XX..............
+................
+................""")
+
+add("1e - CrystalSwitch", dung=(8, 15), ss_4 = """
+................
+................
+....11..........
+....11..........""")
+
+add("1f - SickKid", dung=(13, 21), ss_1 = """
+..........6666XX
+..........6666XX
+.......X......XX
+.......X......XX""")
+
+
+add("20 - Sluggula", dung=(29, 17), ss_3 = """
+XXXXXX..........
+XXXXXX..........
+xx........xxxxxx
+xx........xxxxxx""")
+
+
+add("21 - PushSwitch", dung=(17, 10), ss_4 = """
+..........xxxx..
+..........xxxx..
+..........xx....
+..........xx....""")
+
+add("22 - Ropa", ow=(19, 14), ss_1 = """
+........xxxx....
+........xxxx....
+......xx........
+......xx........""")
+
+# also used for blue bari
+add("23 - RedBari", dung=(8, 15), ss_1 = """
+................
+................
+xxxx..xx........
+xxxx..xx........""")
+
+add("25 - TalkingTree (S27)", dw=(19, 16), ss_4 = """
+................
+................
+........xx......
+........xx......""")
+
+add("25 - TalkingTree (S21)", dw=(21, 16), ss_1 = """
+................
+................
+........xx......
+........xx......""")
+
+add("26 - HardhatBeetle", dung=(19, 13), ss_2 = """
+xxxxxxxxxxxxx...
+xxxxxxxxxxxx....
+................
+................""")
+add("27 - Deadrock", ow=(16, 9), ss_4 = """
+..xxxxxx........
+..xxxxxx........
+..xxxx..........
+..xxxx..........""")
+add("28 - DarkWorldHintNpc", dung=(5, 7), ss_2 = """
+..........55....
+..........55....
+..............55
+..............55""")
+add("28 - DarkWorldHintNpc", dung=(5, 7), ss_1 = """
+................
+................
+....55..........
+....55..........""")
+add("28 - DarkWorldHintNpc", dung=(5, 7), ss_1 = """
+....44..........
+....44..........
+................
+................""")
+add("28 - DarkWorldHintNpc", dung=(7, 7), ss_1 = """
+..............55
+..............55
+..............55
+..............55""")
+add("28 - DarkWorldHintNpc", dung=(5, 28), ss_2 = """
+................
+................
+..........5555..
+..........5555..""")
+
+
+add("29 - Human/Woman", dung=(15, 35), ss_1 = """
+............xxxx
+............xxxx
+................
+................""", ss_4 = """
+..........xxxxxx
+..........xxxxxx
+................
+................""")
+
+add("29 - Human/Thief", dung=(40, 7), ss_1 = """
+xxxxxxxx..xx..xx
+xxxxxxxx..xx..xx
+xxxxxx......xx..
+xxxxxx......xx..""", palette = 7)
+
+
+add("29 - Human/Elder", dung=(15, 35), ss_3 = """
+....xxxxxx......
+....xxxxxx......
+..xx............
+..xx............""")
+
+add("2a - SweepingLady", ow=(6, 1), ss_3 = """
+..........xxxxxx
+..........xxxxxx
+................
+................""")
+
+add("2b - Hobo", ow=(12, 8), ss_3 = """
+........xxxx....
+........xxxx....
+......xxxxxxx...
+......xxxxxxx...""")
+
+add("2c - LumberJacks", ow=(26, 6), ss_1 = """
+..............xx
+..............xx
+................
+................""", ss_3 = """
+................
+................
+....xxxxxx......
+....xxxxxx....44""")
+
+add("2e - FluteKid - LW", lw=(15, 1), ss_3= """
+................
+................
+........xxxx...x
+........xxxx..xx""")
+
+
+add("2e - FluteKid - DW", dw=(17,11), ss_4 = """
+........xxxx00..
+........xxxx00..
+......xxxx..00..
+......xxxx..00..""", palette = 3)
+
+
+add("2f - MazeGameLady", ow=(6, 1), ss_4 = """
+xxxx............
+xxxx............
+xxxxxxxxxx......
+xxxxxxxxxx......""")
+
+add("30 - MazeGameGuy", ow=(6, 1), ss_1="""
+xxxx............
+xxxx............
+xx..............
+xx..............""")
+
+add("31 - FortuneTeller", dung=(5, 30), ss_1 = """
+..........xxxx..
+..........xxxx..
+..........x.x...
+................""", ss_2 = """
+................
+................
+......xxxx......
+......xxxx......""")
+
+add("32 - QuarrelBros", dung=(15,2), ss_1 = """
+....XX..XXXX....
+....XX..XXXX....
+................
+................""")
+
+add("34 - YoungSnitchLady", ow=(6,1), ss_1 = """
+................
+................
+....xxxxxx......
+....xxxxxx......""", ss_4 = """
+..xx............
+..xx............
+....xxxxxx......
+....xxxxxx......""")
+
+add("35 - InnKeeper", dung=(15,5), ss_4 = """
+....xxxxxxxxxxxx
+....xxxxxxxxxxxx
+..............xx
+..............xx""")
+
+add("36 - Witch", ow=(13, 6), ss_3 = """
+xxxxxx11........
+xxxxxx11........
+..............xx
+..............xx""")
+
+add("39 - Locksmith", ow=(10, 0), ss_4 = """
+................
+................
+..........xxxx..
+..........xxxx..""")
+
+add("3a - MagicBat", dung=(9, 32), ss_4 = """
+................
+................
+..........xxxx..
+..........xxxx.x""")
+
+add("3b - TreeTop", ow=(26, 6), ss_1 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....""", palette = 0)
+
+add("3c - TroughBoy", ow=(6, 1), ss_3 = """
+4444............
+4444............
+55........55....
+55........55....""")
+
+add("3d - OldSnitchLady", ow=(6, 1), ss_4 = """
+xxxx............
+xxxx............
+xxxxxxxxxx......
+xxxxxxxxxx......""")
+
+# rock crab is included in two sheets
+add("3e - RockCrab", ow=(10, 0), ss_4 = """
+................
+................
+......xxxx......
+......xxxx......""", palette = 0)
+
+add("3e - RockCrab (S16)", ow=(33, 0), ss_4 = """
+................
+................
+......xxxx......
+......xxxx......""", palette = 0)
+
+
+add("3f - PalaceGuard", ow=(2, 1), ss_1 = """
+xx..............
+xx..............
+......xxxxx.....
+......xxxxx.....""", palette = 4)
+
+add("3f - PalaceGuard", ow=(2, 1), ss_2 = """
+xxxxxxxx......xx
+xxxxxxxx......xx
+....xx..........
+....xx..........""")
+
+
+add("40 - ElectricBarrier", ow=(2, 1), ss_4 = """
+..........xxxx..
+..........xxxx..
+......xxxx......
+......xxxx......""")
+
+
+add("41 - Soldier", dung=(3, 0), ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""")
+
+add("41 - Soldier (DW)", dung=(36, 37), ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", ss_3 = """
+................
+................
+......xxxxxxxxx.
+......xxxxxxxxx.
+""")
+
+add("44 - Warrior", dung=(33, 38), ss_1 = """
+xxxxxx..........
+xxxxxx..........
+................
+................""")
+
+add("47 - GrassArcher", ow=(4, 3), ss_1 = """
+..xxxxxxxxxxxxxx
+..xxxxxxxxxxxxxx
+11xxxx..........
+11xxxx..........""")
+
+add("4a - RedBombKnight", ow=(1, 3), ss_1 = """
+xxxxxxxxxxxxxxx.
+xxxxxxxxxxxxxxx.
+..xx........xxxx
+..xx........xxx.""")
+
+add("4b - GreenKnifeGuard", ow=(2, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xx....xxxxxxxxxx
+xx....xxxxxxxxxx""")
+
+add("4c - Geldman", ow=(8, 4), ss_3 = """
+................
+................
+xxxxxxxx........
+xxxxxxxxx.......""")
+
+add("4d - Toppo", ow=(4, 3), ss_4 = """
+xxxx............
+xxxx............
+................
+................""")
+
+add("4e - Popo", dung=(8, 11), ss_2 = """
+xxxx............
+xxxx............
+................
+................""")
+
+add("51 - ArmosStatue", ow=(5, 7), ss_4 = """
+xx..............
+xx..............
+xx..............
+xx..............""", palette = 5)
+
+add("52 - ZoraKing", ow=(14, 8), ss_3 = """
+........2222....
+........2222....
+........2.......
+................""", ss_4 = """
+xxxx2222........
+xxxx2222........
+xxxx2222..xx....
+xxxx2222..xx....""")
+
+add("53 - ArmosKnight", dung=(9, 11), ss_4 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxx..........
+xxxxxx..........""")
+
+add("54 - Lanmolas", dung=(11, 4), ss_4 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""")
+
+add("55 - FireBallZora", lw=(4, 3), dw=(22, 10), ss_3 = """
+........2222....
+........2222....
+....xxxx2.......
+....xxxx........""")
+
+add("56 - WalkingZora", ow=(14, 8), ss_4 = """
+........xxxxxxxx
+........xxxxxxxx
+........xx..xxxx
+........xx..xxxx""")
+
+add("57 - HyliaObstacle", ow=(8, 4), ss_3 = """
+..............xx
+..............xx
+..............xx
+..............xx""")
+
+add("58 - Crab", ow=(4, 3), ss_3 = """
+..............xx
+..............xx
+..............xx
+..............xx""")
+
+add("59 - LostWoodsBird", ow=(12, 1), ss_4 = """
+................
+................
+...xxxx.........
+...xxxx.........""")
+
+add("5a - LostWoodsSquirrel", ow=(12, 1), ss_4 = """
+.....xx.........
+.....xx.........
+.xx.............
+.xx.............""")
+
+add("5b - Spark", dung=(17, 10), ss_1 = """
+................
+................
+........xx......
+........xx......""", palette = 2)
+
+add("5d - Roller", dung=(30, 24), ss_3 = """
+........xxx.....
+........xxx.....
+................
+................""")
+
+add("5f - Roller", dung=(30, 24), ss_3 = """
+..............xx
+..............xx
+..............xx
+................""")
+  
+add("61 - Beamos", dung=(10, 9), ss_2 = """
+........xx555...
+........xx551...
+........xx......
+........xx......""")
+
+add("62 - MasterSword", ow=(12, 1), ss_3 = """
+xxxxxxxx........
+xxxxxxxx........
+xxxxxx..........
+xxxxxx..........""", ss_4 = """
+...xx...........
+...xx...........
+x......xx.......
+x......xx.......""")
+
+add("63 - DebirandoPit", dung=(10, 9), ss_1 = """
+..xxxx..........
+..xxxx..........
+..xx....xxxx....
+..xx....xxxx....""")
+
+add("64 - Debirando", dung=(10, 9), ss_1 = """
+xx..............
+xx..............
+xx..............
+xx..............""", palette = 3)
+
+add("65 - ArcherGame", dung=(5, 30), ss_1 = """
+..xxxxxxxx......
+..xxxxxxxx......
+..xxxxxxxx.x....
+xxxxxxxxxxxx....""", palette = 4)
+
+add("66 - Cannon", dung=(10, 9), ss_1 = """
+..........xxxxxx
+..........xxxxxx
+....44........xx
+....44........xx""")
+
+add("6a - MorningStar", dung=(4, 1), ss_1 = """
+xxxxxxxxxxxxxxx.
+xxxxxxxxxxxxxxx.
+..xx......xxxxxx
+..xx......xxxxxx""", ss_2 = """
+......xxxxxxx.xO
+......xxxxxxx.xO
+xxxxxxxxxxx.....
+xxxxxxxxxxx.....""")
+
+add("6b - CannonTrooper", dung=(4, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxx.""")
+
+add("6d - Rat", dung=(1, 1), ss_3 = """
+......xxxxxxxxxx
+......xxxxxxxxxx
+..xx............
+..xx............""")
+
+add("6d - Rat (DW)", dung=(33, 35), ss_3 = """
+......xxxxxxxxxx
+......xxxxxxxxxx
+xxxx............
+xxxx............""")
+
+
+
+add("6e - Rope", dung=(1, 1), ss_3 = """
+................
+................
+....xxxxxxxx....
+....xxxxxxxx....""")
+
+add("6e - Rope (DW)", dung=(33, 35), ss_3 = """
+................
+................
+....xxxxxxxx....
+....xxxxxxxx....""")
+
+add("6f - Keese", dung=(1, 1), ss_3 = """
+xxxxxx..........
+xxxxxx..........
+................
+................""")
+
+add("6f - Keese (DW)", dung=(33, 35), ss_3 = """
+xxxxxx..........
+xxxxxx..........
+................
+................""")
+
+add("70 - KingHelmasaurFireball", dung=(21, 16), ss_3 = """
+................
+................
+............xx..
+............xx..""", ss_4 = """
+..........xxxx..
+..........xxxx.x
+................
+................""")
+
+add("71 - Leever", dung=(10, 9), ss_1 = """
+......xxxx......
+......xxxx......
+......xxx.......
+......xxx.......""")
+
+add("72 - FairyPond", dung=(7, 7), ss_4 = """
+........xxxxxxxx
+........xxxxxxxx
+................
+................""")
+
+add("72 - FairyPond", dung=(7, 34), ss_4 = """
+................
+................
+.........xxxxxxx
+.........xxxxxxx""")
+
+add("73 - UncleAndPriest", dung=(6, 29), ss_1 = """
+OOOOOOxxxxxxxxxx
+OOOOOOxxxxxxxxxx
+xxxxxxxxxxxx0000
+xxxxxxxxxxxx0000""", palette = 4)
+
+add("73 - UncleAndPriest", dung=(13, 21), ss_1 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxx.xxxxxx..
+xxxxxxx.xxxxxx..""", palette = 4)
+
+
+
+add("74 - RunningMan", ow=(6, 1), ss_1 = """
+................
+................
+..........xxxxxx
+..........xxxxxx""", ss_4 = """
+..........xxxxxx
+..........xxxxxx
+..............xx
+..............xx""")
+
+add("75 - BottleVendor", ow=(6, 1), ss_3 = """
+........xx......
+........xx......
+..xx........xx..
+..xx........xx..""")
+
+add("78 - MrsSahasrahla", dung=(5, 2), ss_1 = """
+................
+................
+........xx......
+........xx......""", ss_3 = """
+..............xx
+..............xx
+................
+................""")
+
+add("7a - Agahnim", dung=(24, 27), ss_1 = """
+............xxxx
+............xxxx
+............xxxx
+............xxxx""", ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", ss_4 = """
+xxxxxx..xxxx...x
+xxxxxx..xxxx..xx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 6)
+
+add("7b - AgahnimBalls", dung=(24, 27), ss_4 = """
+......xx....xxx.
+......xx....xx..
+................
+................""", palette = 2)
+
+add("7c - StalfosHead", dung=(8, 11), ss_1 = """
+xxxxxx..........
+xxxxxx..........
+................
+................""")
+
+add("7d - BigSpikeBlock", dung=(12, 16), ss_4 = """
+....xx..........
+....xx..........
+................
+................""")
+
+add("7e - FireBlade", dung=(17, 10), ss_1 = """
+................
+................
+........xx......
+........xx......""")
+
+add("81 - WaterBug", dung=(17, 10), ss_3 = """
+xxxxxx..........
+xxxxxx..........
+................
+................""")
+
+add("83 - GreenEyegore", dung=(10, 9), ss_3 = """
+..........xxxxxx
+..........xxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxx..""")
+
+add("83 - GreenEyegore", dung=(8, 39), ss_2 = """
+....xxxx......xx
+....xxxx......xx
+..xxxxxx..xxxxxx
+..xxxxxx..xxxxxx""")
+
+add("85 - YellowStalfos", dung=(25, 15), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+....xx....xxxxxx
+....xx....xxxxxx""")
+
+add("86 - Kodongo", dung=(25, 6), ss_3 = """
+............xx..
+............xx..
+xxxxxxxxxxxxxx..
+xxxxxxxxxxxxxx..""")
+
+add("88 - Mothula", dung=(26, 14), ss_3 = """
+xxxxxxxxxx.xxxxx
+xxxxxxxxxx.xxxxx
+xxxxxxxxxx..xxxx
+xxxxxxxxxx..xxxx""")
+
+add("89 - MothulaRing", dung=(26, 14), ss_3 = """
+..........x.....
+..........x.....
+..........xx....
+..........xx....""")
+
+add("8a - SpikeBlock", dung=(8, 15), ss_4 = """
+................
+................
+......xx........
+......xx........""")
+
+add("8b - Gibdo", dung=(19, 13), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxx..........
+xxxxxx..........""")
+
+add("8c - Arrghus", dung=(20, 8), ss_3 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxxxxx......""")
+
+add("8e - TerrorPin", dung=(25, 15), ss_3 = """
+..........xx..xx
+..........xx..xx
+..............xx
+..............xx""")
+
+add("8f - Blob", dung=(17, 8), ss_2 = """
+xxxxxx..........
+xxxxxx..........
+x...............
+x...............""")
+
+add("90 - WallMaster", dung=(19, 13), ss_3 = """
+................
+................
+......xxxxxxxxxx
+......xxxxxxxxxx""")
+
+add("91 - StalfosKnight", dung=(28, 19), ss_2 = """
+......xxxxxxxx..
+......xxxxxxxx..
+.xxxxxxxxxx.....
+.xxxxxxxxxx.....""")
+
+add("92 - HelmasaurKing", dung=(21, 16), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxx66
+xxxxxxxxxxxxxx66""", ss_4 = """
+6666666666xxxxxx
+6666666666xxxxxx
+6666xxOOOOOOOOOO
+6666xxOOOOOOOOOO""", palette = 5)
+
+add("93 - Bumper", dung=(12, 26), ss_4 = """
+................
+................
+............xx..
+............xx..""")
+
+add("94 - Pirogusu", dung=(17, 10), ss_3 = """
+.......x....xxxx
+.......x....xxxx
+..........xxxxxx
+..........xxxxxx""")
+
+add("95 - LaserEye", dung=(29, 17), ss_4 = """
+......xxxx......
+..2...xxxx......
+................
+...2............""")
+
+add("99 - Pengator", dung=(28, 19), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxx..........
+xxxxxx..........""")
+
+add("9a - Kyameron", dung=(17, 10), ss_3 = """
+......x.xxxx....
+......x.xxxx....
+xxxxxxxxxx......
+xxxxxxxxxx......""")
+
+add("9b - Wizzrobe", dung=(29, 17), ss_3 = """
+......xxxxxxxxxx
+......xxxxxxxxxx
+....xx..........
+..xxxx..........""")
+
+add("9b - Wizzrobe (DW)", dung=(36, 37), ss_3 = """
+......xxxxxxxxxx
+......xxxxxxxxxx
+....xx..........
+..xxxx..........""")
+
+
+
+add("9c - Babasu", dung=(17, 10), ss_2 = """
+..............xx
+..............xx
+...........xxxxx
+...........xxxxx""", palette=1)
+
+add("9e - HauntedGroveOstrich", ow=(15, 1), ss_3 = """
+xxxxxx..........
+xxxxxx..........
+xxxxxx..........
+xxxxxx..........""")
+
+add("9f - HauntedGroveRabbit", ow=(15, 1), ss_3 = """
+........xxxxxx..
+........xxxxxx..
+......xx........
+......xx........""")
+
+add("A0 - HauntedGroveBird", ow=(15, 1), ss_3 = """
+......xx......xx
+......xx......xx
+............xxx.
+............xx..""")
+
+add("A1 - Freezor", dung=(28, 19), ss_3 = """
+................
+................
+......xxxxxxxxxx
+......xxxxxxxxxx""")
+
+add("A2 - Kholdstare", dung=(22, 20), ss_3 = """
+xxxxxxxx....xx..
+xxxxxxxx....xx..
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""")
+
+add("A4 - FallingIce", dung=(22, 20), ss_3 = """
+........xxxx..xx
+........xxxx..xx
+................
+................""")
+
+add("A5 - Zazak", dung=(27, 23), ss_3 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxxxxx......
+xxxxxxxxxx......""")
+
+add("A8 - GreenZirro", ow=(19, 14), ss_4 = """
+xxxxxxxx........
+xxxxxxxx........
+xxxxxxxx........
+xxxxxxxx.......7""")
+
+add("AA - Pikit", ow=(19, 14), ss_4 = """
+........xxxxxxxx
+........xxxxxxxx
+..........xxxxx.
+..........xxxxx.""")
+
+add("AD - OldMan", dung=(1, 7), ss_3 = """
+................
+................
+............xxxx
+............xxxx""")
+
+
+add("B4 - PurpleChest", ow=(21, 16), ss_1 = """
+................
+................
+..............xx
+..............xx""", ss_4 = """
+................
+................
+..............xx
+..............xx""")
+
+add("B5 - BombShop", dung=(5, 31), ss_2 = """
+........xx..xxxx
+........xx..xx44
+................
+................""", palette = 1)
+
+add("B6 - Kiki", ow=(23, 13), ss_4 = """
+..........xxx.xx
+..........xxxxxx
+............xxxx
+............xxxx""")
+
+add("B9 - BullyAndPinkBall", dw=(20, 12), ss_4 = """
+....xx..........
+....xx..........
+xxxx............
+xxxx............""", palette = 6)
+
+add("B9 - BullyAndPinkBall", dw=(20, 12), ss_4 = """
+xxxx............
+xxxx............
+................
+................""")
+
+add("BB - Shopkeeper", dung=(5, 7), ss_1 = """
+xxxx............
+xxxx............
+xxxx............
+xxxx............""", palette = 5)
+
+add("BB - Shopkeeper", dung=(5, 7), ss_4 = """
+11..22......4422
+11..22......4422
+........22......
+........22......""")
+
+add("BB - Shopkeeper", dung=(15, 31), ss_2 = """
+......xx........
+......xx........
+................
+................""", palette = 6)
+
+add("BB - Shopkeeper", dung=(40, 5), ss_1 = """
+xxxxxxxx..xx..xx
+xxxxxxxx..xx..xx
+xxxxxx......xx..
+xxxxxx......xx..""", palette = 6)
+
+add("BB - Shopkeeper", dung=(15, 5), ss_1 = """
+xxxx............
+xxxx............
+xx..............
+xx..............""", palette = 6)
+
+add("BB - Shopkeeper", dung=(42, 32), ss_1 = """
+xxxxxxxx..xx..xx
+xxxxxxxx..xx..xx
+xxxxxx..........
+xxxxxx..........""", palette = 6)
+
+add("BC - Drunkard", dung=(15, 5), ss_1 = """
+......xx........
+......xx........
+..xx............
+..xx............""", ss_3 = """
+................
+................
+..............xx
+................""", palette = 4)
+
+add("BD - Viterous", dung=(22, 18), ss_4 = """
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....""")
+
+add("BF - ViterousLightning", dung=(22, 18), ss_4 = """
+............xxxx
+............xxxx
+............xxxx
+............xxxx""")
+
+add("C0 - Catfish", ow=(22, 10), ss_3 = """
+......xxxxxxxxx.
+......xxxxxxxxx.
+........x...xxx.
+.............xx.""")
+
+add("C1 - CutsceneAgahnim", dung=(18, 12), ss_1 = """
+xxxxxx..........
+xxxxxx..........
+xxxxxxxx........
+xxxxxxx.........""", ss_3 = """
+xxxx............
+xxxx............
+xxxx............
+xxxx............""", ss_4 = """
+..............2.
+...............x
+............xxxx
+............xxxx""", palette = 5)
+
+add("C3 - Gibo", dung=(27, 23), ss_3 = """
+..........xxxxxx
+..........xxxxxx
+..........xxxxxx
+..........xxxxxx""")
+
+add("C7 - Pokey", dung=(30, 24), ss_3 = """
+xxxx............
+xxxx............
+xxxx............
+xxxx............""")
+
+add("C8 - BigFairy", dung=(7, 7), ss_3 = """
+..........xxxxxx
+..........xxxxxx
+..........xxxxxx
+..........xxxxxx""")
+
+add("C9 - Tektite", dw=(5, 7), ss_4 = """
+........xxxx....
+........xxxx....
+..........xx....
+..........xx....""", palette = 4)
+
+add("CA - ChainChomp", dung=(30, 24), ss_3 = """
+......xx...xxx..
+......xx....xx..
+......xxxxxx....
+......xxxxxx....""")
+
+add("CB - Trinexx", dung=(23, 25), ss_1 = """
+xxxx55xx55xxxxXX
+xxxx55xx55xxxxXX
+xxxx55xxxxxxxxXX
+xxxx55xxxxxxxxXX""", ss_4 = """
+xxxxxxXXXXXXXXXX
+xxxxxxXXXXXXXXXX
+xxxxxxxxxxXXXXxx
+xxxxxxxxxxXXXXxx""")
+
+add("CE - Blind", dung=(32, 23), ss_3 = """
+xxxxxxxxxxxxxx66
+xxxxxxxxxxxxxx66
+666666xxxxxx6666
+666666xxxxxx6666""", palette = 5)
+
+add("CF - Swamola", ow=(22, 15), ss_4 = """
+xxxx............
+xxxx............
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....""")
+
+add("D0 - Lynel", ow=(20, 12), ss_4 = """
+......xxxxxxxxxx
+......xxxxxxxxxx
+....xxxxxxxxxxxx
+....xxxxxxxxxxxx""")
+
+add("D5 - DigGameGuy", ow=(27, 18), ss_2 = """
+xxxxxxx.........
+xxxxxxx.........
+................
+................""", palette = 5)
+
+add("D6 - Ganon", dung=(34, 33), ss_2 = """
+....xx..........
+....xx..........
+xxxxxx..........
+xxxxxx..........""", palette = 4)
+
+add("D6 - Ganon", dung=(34, 33), ss_1 = """
+xx5555xxxxxxxx55
+xx5555xxxxxxxx55
+xx5555xxxxxxxxxx
+xx5555xxxxxxxxxx""", ss_2 = """
+xxxx..xxxxxxxx55
+xxxx..xxxxxxxx55
+......xxxxxxxx55
+......xxxxxxxx55""", ss_3 = """
+xxxx55xxxxxxxxxx
+xxxx55xxxxxxxxxx
+xxxx55xxxxxxxxxx
+xxxx55xxxxxxxxxx""", ss_4 = """
+xxxxxx5555xxxx55
+xxxxxx5555xxxx55
+xxxxxx5555xxxx55
+xxxxxx5555xxxx55""", palette = 6)
+
+add("E7 - Mushroom", ow=(7, 5), ss_4 = """
+................
+................
+..............xx
+..............xx""", palette = 3)
+
+add("E8 - FakeSword", ow=(7, 5), ss_4 = """
+................
+................
+................
+....xx..........""")
+
+add("E9 - PotionShop", dung=(5, 5), ss_4 = """
+................
+................
+......xx........
+......xx........""", palette = 2)
+
+add("ED - SomariaPlatform", dung=(30, 24), ss_3 = """
+................
+................
+............XX..
+............XX..""")
+
+add("EE - MovableMantle", dung=(3, 0), ss_1 = """
+............xxxx
+............xxxx
+............xxxx
+............xxxx""")
+
+add("F2 - MedallionTablet", ow=(8, 4), ss_3 = """
+..........xxxx..
+..........xxxx..
+..........xxxx..
+..........xxxx..""")
+
+add("F4 - FallingRocks", ow=(5, 7), ss_4 = """
+............xxxx
+............xxxx
+............xxxx
+............xxxx""")
+
+add("XX - Unknown Sheet 00", sheet=(0, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 01", sheet=(1, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 02", sheet=(2, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 03", sheet=(3, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 04", sheet=(4, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 05", sheet=(5, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 06", sheet=(6, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 07", sheet=(7, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 08", sheet=(8, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 09", sheet=(9, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 10", sheet=(10, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 11", sheet=(11, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 14", ow=(37, 1), ss_1 = """
+........xx..xx..
+........xx..xx..
+........xxxx..xx
+........xxxx..xx""", palette = 4)
+
+
+add("XX - Unknown Sheet 15", ow=(26, 1), ss_1 = """
+..........xxxx..
+..........xxxx..
+............xxxx
+............xxxx""", palette = 4)
+
+
+add("XX - Unknown Sheet 21", ow=(21, 1), ss_1 = """
+............xx..
+............xx..
+................
+................""", palette = 4)
+
+add("XX - Unknown Sheet 27", ow=(25, 1), ss_4 = """
+................
+................
+...............x
+................""", palette = 4)
+
+add("XX - Unknown Sheet 37", ow=(93, 1), ss_3 = """
+................
+................
+..xx..xxxx......
+......xxxx......""", palette = 4)
+
+
+add("XX - Unknown Sheet 39", ow=(94, 1), ss_3 = """
+....xx..........
+....xx.....x....
+....xx..........
+....xx........xx""", palette = 4)
+
+add("XX - Unknown Sheet 41", dung=(36, 1), ss_3 = """
+xxxxxx..........
+xxxxxx..........
+xxxx...........x
+xx.............x""", palette = 4)
+
+
+add("XX - Unknown Sheet 42", ow=(107, 1), ss_3 = """
+.......xxx......
+.......xxx......
+................
+................""", palette = 4)
+
+add("XX - Unknown Sheet 43", dung=(16, 1), ss_4 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 44", ow=(72, 1), ss_2 = """
+.............x..
+.............x..
+xx..............
+xx..............""", palette = 4)
+
+add("XX - Unknown Sheet 45", ow=(45, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 46", ow=(73, 1), ss_3 = """
+xxxxxxxxxx......
+xxxxxxxxxx......
+................
+..............xx""", palette = 4)
+
+add("XX - Intro Sheet 50", sheet=(50, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Ending Sheet 52", sheet=(52, 1), ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Ending Sheet 53", sheet=(53, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 54", ow=(40, 1), ss_4 = """
+xxx....x........
+xxx....x........
+................
+................""", palette = 4)
+
+add("XX - Unknown Sheet 55", ow=(12, 1), ss_3 = """
+............xxxx
+............xxxx
+.............xxx
+.............xxx""", palette = 4)
+
+add("XX - Unknown Sheet 72", ow=(2, 1), ss_1 = """
+................
+................
+...........xxxxx
+...........xxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 75", ow=(27, 1), ss_1 = """
+................
+................
+.............x..
+............xx..""", palette = 4)
+
+
+add("XX - Unknown Sheet 76", ow=(13, 1), ss_3 = """
+..............xx
+..............xx
+..........xx....
+..........xx....""", palette = 4)
+
+add("XX - Unknown Sheet 82", dung=(19, 1), ss_4 = """
+xxxx......xxxx..
+xx.x......xxxx..
+x.x.....xxxx....
+xxx.....xxxx....""", palette = 4)
+
+add("XX - Unknown Sheet 83", dung=(38, 1), ss_4 = """
+...xxxxxxx....xx
+..xxxxxxxx....xx
+xxxxxxxxxx..xxxx
+xxxxxxxxxx..xxxx""", palette = 4)
+
+add("XX - Unknown Sheet 84", sheet=(84, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 85", dung=(63, 1), ss_1 = """
+......xxxxxx....
+......xxxxxx....
+........xxxx....
+.......xxxxx....""", palette = 4)
+
+add("XX - Map Sheet 86", sheet=(86, 1), ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Map Sheet 87", sheet=(87, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 88", sheet=(88, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Tagalong S89", sheet=(89, 1), ss_4 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 90", dung=(5, 1), ss_4 = """
+..xx..xxxxxx....
+..xx..xxxxxx....
+xxxxxx....xxxxxx
+xxxxxx....xxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 91", sheet=(91, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 92", sheet=(92, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 93", ow=(43, 1), ss_3 = """
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....
+xxxxxxxxxxxx....""", palette = 4)
+
+add("XX - Unknown Sheet 94", sheet=(94, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 95", sheet=(95, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Unknown Sheet 96", sheet=(96, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Map Sheet 97", sheet=(97, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Map Sheet 98", sheet=(98, 1), ss_2 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Map Sheet 99", sheet=(99, 1), ss_3 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Tagalong S100", sheet=(100, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+add("XX - Tagalong S101", sheet=(101, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
+
+
+add("XX - Tagalong S102", sheet=(102, 1), ss_1 = """
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx
+xxxxxxxxxxxxxxxx""", palette = 4)
--- /dev/null
+++ b/tables/sprite_sheets.py
@@ -1,0 +1,503 @@
+from PIL import Image
+import sprite_sheet_info
+import util
+from util import get_bytes, get_words, get_byte
+import array
+import tables
+from functools import cache
+
+def save_as_png(dimensions, data, fname, palette = None):
+  img = Image.new('L' if palette == None else 'P', dimensions)
+  img.putdata(data)
+  if palette != None:
+    img.putpalette(palette)
+  img.save(fname)
+
+def save_as_24bpp_png(dimensions, data, fname):
+  img = Image.new("RGB", dimensions)
+  img.putdata(data)
+  img.save(fname)
+
+@cache
+def decode_2bit_tileset(tileset):
+  data = util.decomp(tables.kCompSpritePtrs[tileset], get_byte, False)
+  assert len(data) == 0x400
+  height = 32
+  dst = bytearray(128*height)
+  def decode_2bit(offs, toffs):
+    for y in range(8):
+      d0, d1 = data[offs + y * 2], data[offs + y * 2 + 1]
+      for x in range(8):
+        t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2
+        dst[toffs + y * 128 + (7 - x)] = t * 255 // 3
+  for i in range(16*height//8):
+    x = i % 16
+    y = i // 16
+    decode_2bit(i * 16, x * 8 + y * 8 * 128)
+  return dst
+
+def is_high_3bit_tileset(tileset):
+  # is 0x5c, 0x5e, 0x5f included or not?
+  return tileset in (0x52, 0x53, 0x5a, 0x5b, 0x5c, 0x5e, 0x5f)
+
+def get_unpacked_snes_tileset(tileset):
+  if tileset < 12:
+    return get_bytes(tables.kCompSpritePtrs[tileset], 0x600)
+  else:
+    return util.decomp(tables.kCompSpritePtrs[tileset], get_byte, False)
+
+@cache
+def decode_3bit_tileset(tileset):
+  data = get_unpacked_snes_tileset(tileset)
+  assert len(data) == 0x600
+  base = 8 if is_high_3bit_tileset(tileset) else 0
+  height = 32
+  dst = bytearray(128*height)
+  def decode_3bit(offs, toffs):
+    for y in range(8):
+      d0, d1, d2 = data[offs + y * 2], data[offs + y * 2 + 1], data[offs + y + 16]
+      for x in range(8):
+        t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2 + ((d2 >> x) & 1) * 4
+        dst[toffs + y * 128 + (7 - x)] = base + t
+  for i in range(16*height//8):
+    x, y = i % 16, i // 16
+    decode_3bit(i * 24, x * 8 + y * 8 * 128)
+  return dst
+
+def decode_4bit_tileset_link():
+  height = 448
+  data = get_bytes(0x108000, 0x800 * height // 32) # only link sprites for now
+  dst = bytearray(128*height)
+  def decode_4bit(offs, toffs):
+    for y in range(8):
+      d0, d1, d2, d3 = data[offs + y * 2 + 0], data[offs + y * 2 + 1], data[offs + y * 2 + 16], data[offs + y * 2 + 17]
+      for x in range(8):
+        t = ((d0 >> x) & 1) * 1 + ((d1 >> x) & 1) * 2 + ((d2 >> x) & 1) * 4 + ((d3 >> x) & 1) * 8
+        dst[toffs + y * 128 + (7 - x)] = t
+  for i in range(16*height//8):
+    x, y = i % 16, i // 16
+    decode_4bit(i * 32, x * 8 + y * 8 * 128)
+  return dst
+
+def convert_snes_palette(v):
+  rr=bytearray()
+  for x in v:
+    r, g, b = x & 0x1f, x >> 5 & 0x1f, x >> 10 & 0x1f
+    rr.extend((r << 3 | r >> 2, g << 3 | g >> 2, b << 3 | b >> 2))
+  return rr
+
+def convert_int24_palette_to_bytes(v):
+  rr=bytearray()
+  for x in v:
+    rr.extend((x & 0xff, x >> 8 & 0xff, x >> 16 & 0xff))
+  return rr
+
+def convert_snes_palette_to_int(v):
+  rr=[]
+  for x in v:
+    r, g, b = x & 0x1f, x >> 5 & 0x1f, x >> 10 & 0x1f
+    rr.append((r << 3 | r >> 2) | (g << 3 | g >> 2) << 8 | (b << 3 | b >> 2) << 16)
+  return rr
+
+def decode_link_sprites():
+  kLinkPalette = [0, 0x7fff, 0x237e, 0x11b7, 0x369e, 0x14a5,  0x1ff, 0x1078, 0x599d, 0x3647, 0x3b68,  0xa4a, 0x12ef, 0x2a5c, 0x1571, 0x7a18]
+  save_as_png((128, 448), decode_4bit_tileset_link(), 'linksprite.png', convert_snes_palette(kLinkPalette))
+
+# Returns the dungeon palette for the specified palette index
+# 0 = lightworld, 1 = darkworld, 2 = dungeon
+@cache
+def get_palette_subidx(palset_idx, dungeon_or_ow, which_palette):
+  spmain = 1 if (dungeon_or_ow == 1) else 0
+  if dungeon_or_ow == 2:
+    main, sp0l, sp5l, sp6l = tables.kDungPalinfos[palset_idx]
+    sp0r = (main // 2) + 11
+    sp6r = 10
+  else:
+    sp5l, sp6l = tables.kOwSprPalInfo[palset_idx * 2 : palset_idx * 2 + 2]
+    sp0l = 3 if dungeon_or_ow == 1 else 1
+    sp0r = 9 if dungeon_or_ow == 1 else 7
+    sp6r = 8 if dungeon_or_ow == 1 else 6
+  pal_defs = (sp0l, sp0r, 
+    spmain, None, spmain, None, spmain, None, None, None,
+    sp5l, None,
+    sp6l, sp6r,
+    None, None)
+  return pal_defs[which_palette]
+
+@cache
+def get_palette_subset(pal_idx, j):
+  if j == None: j = 0
+  pal = [0] * 7
+  if pal_idx == 0: # 0
+    kPalette_SpriteAux3 = get_words(0x9BD39E, 84)
+    return kPalette_SpriteAux3[j * 7 : j * 7 + 7]
+  if pal_idx == 1: # 0R
+    if j < 11:
+      kPalette_MiscSprite = get_words(0x9BD446, 77)
+      return kPalette_MiscSprite[j * 7 : j * 7 + 7]
+    else:
+      kPalette_DungBgMain = get_words(0x9BD734, 1800)
+      return kPalette_DungBgMain[(j - 11) * 90 : (j - 11) * 90 + 7]
+  if pal_idx in (2, 3, 4, 5, 6, 7, 8, 9):
+    o = j * 60 + ((pal_idx - 2) >> 1) * 15 + (pal_idx & 1) * 8
+    kPalette_MainSpr = get_words(0x9BD218, 120)
+    return kPalette_MainSpr[o : o + 7]
+  if pal_idx in (10, 12):
+    kPalette_SpriteAux1 = get_words(0x9BD4E0, 168)
+    return kPalette_SpriteAux1[j * 7 : j * 7 + 7]
+  assert pal_idx != 11
+  if pal_idx == 13:
+    kPalette_MiscSprite = get_words(0x9BD446, 77)
+    return kPalette_MiscSprite[j * 7 : j * 7 + 7]
+  elif pal_idx == 14:
+    kPalette_ArmorAndGloves = get_words(0x9BD308, 75)
+    return kPalette_ArmorAndGloves[1:8]
+  elif pal_idx == 15:
+    kPalette_ArmorAndGloves = get_words(0x9BD308, 75)
+    return kPalette_ArmorAndGloves[9:16]
+
+@cache
+def get_full_palette(pal_idx, pal_subidx):
+  rv = []
+  if pal_idx & 1:
+    rv.extend([0x00fe00] * 9)
+  else:
+    rv.extend([0x00fe00] * 1)
+  rv.extend(convert_snes_palette_to_int(get_palette_subset(pal_idx, pal_subidx)))
+  rv += [0xe000e0] * (256 - len(rv))
+  # change the transparent to teal #008080
+  for i in range(0, 128, 8):
+    rv[i] = 0x808000
+  rv[252] = 0xc0c0c0 # palette text
+  rv[253] = 0xf0f0f0 # unallocated
+  rv[254] = 0x404040 # lines
+  rv[255] = 0xe0e0e0 # bg
+  return rv
+
+@cache
+def get_font_3x5():
+  return Image.open('../other/3x5_font.png').tobytes()
+
+def draw_letter3x5(dst, dst_pitch, dx, dy, ch, color):
+  font = get_font_3x5()
+  dst_offs = dy * dst_pitch + dx
+  src_offs = (ord(ch) & 31) * 4 + (ord(ch) // 32) * 6 * 128
+  for y in range(6):
+    for x in range(3):
+      if font[src_offs + y * 128 + x] == 0:
+        dst[dst_offs + y * dst_pitch + x] = color
+
+def draw_string3x5(dst, dst_pitch, dx, dy, s, color):
+  for ch in s:
+    draw_letter3x5(dst, dst_pitch, dx, dy, ch, color)
+    dx += 4
+
+def convert_to_24bpp(data, palette):
+  out = [0] * len(data)
+  for i in range(len(data)):
+    out[i] = palette[data[i]]
+  return out
+
+def concat_byte_arrays(ar):
+  r = bytearray()
+  for a in ar:
+    r += a
+  return r
+
+def fixup_sprite_set_entry(e, e_prev):
+  sprite_index = int(e.name[:2], 16) if e.name[0] != 'X' else 10000
+
+  if e.dungeon_or_ow != 3:
+    e.tileset = tables.kSpriteTilesets[e.tileset + (64 if e.dungeon_or_ow == 2 else 0)][e.ss_idx]
+  e.high_palette = is_high_3bit_tileset(e.tileset)
+  e.skip_header = False
+  if e.pal_base == None:
+    if sprite_index < len(tables.kSpriteInit_Flags3):
+      e.pal_base = (tables.kSpriteInit_Flags3[sprite_index] >> 1) & 7
+    else:
+      e.pal_base = 4 # just default to some palette
+
+  e.pal_idx = e.pal_base * 2 + e.high_palette
+  e.pal_subidx = get_palette_subidx(e.palset_idx, e.dungeon_or_ow, e.pal_idx)
+
+  if e_prev != None and e_prev.name == e.name and e_prev.pal_idx == e.pal_idx and e_prev.pal_subidx == e.pal_subidx:
+    e.skip_header = True
+
+  # the (pal_idx, pal_subidx) tuple identifies the palette
+  e.encoded_id = e.pal_base | e.tileset << 3 | e.skip_header << 10 | (e.pal_subidx or 0) << 11 
+  e.encoded_id = e.encoded_id << 8 | ((e.encoded_id + 41) % 255)
+
+
+BIGW = 148
+def save_sprite_set_entry(finaldst, e, master_tilesheets = None):
+  empty_253 = [253] * 8
+  def fill_with_empty(dst, dst_offs):
+    for y in range(8):
+      o = dst_offs + y * BIGW
+      dst[o : o + 8] = empty_253
+
+  def copy_8x8(dst, dst_offs, src, src_offs, base):
+    for y in range(8):
+      for x in range(8):
+        dst[dst_offs + y * BIGW + x] = src[src_offs + y * 128 + x] + base
+
+  def hline(dst, x1, x2, y, color):
+    for x in range(x1, x2 + 1):
+      dst[y * BIGW + x] = color
+
+  def vline(dst, x, y1, y2, color):
+    for y in range(y1, y2 + 1):
+      dst[y * BIGW + x] = color
+  
+  def fillrect(dst, x1, x2, y1, y2, color):
+    for y in range(y1, y2 + 1):
+      hline(dst, x1, x2, y, color)
+
+  def encode_id(dst, x, y, v):
+    while v:
+      if v & 1:
+        dst[y * BIGW + x] = 253
+      x -= 1
+      v >>= 1
+
+  palette = get_full_palette(e.pal_idx, e.pal_subidx)
+
+  if not e.skip_header:
+    pal_subidx = e.pal_subidx
+    if e.high_palette:
+      pal_name = '%sR' % e.pal_base
+    else:
+      pal_name = ' %s' % e.pal_base
+      if e.pal_base in (1, 2, 3):
+        assert e.pal_subidx in (0, 1)
+        pal_subidx = 'LW' if pal_subidx == 0 else 'DW'
+
+    header = bytearray([255] * BIGW * 9)
+    draw_string3x5(header, BIGW, 1, 3, e.name[:22], 254)
+
+    for i in range(7):
+      xx = BIGW - 37 + i * 5 - 9
+      fillrect(header, xx, xx + 4, 3, 7, i + (9 if e.high_palette else 1))
+
+    if pal_subidx != None:
+      draw_string3x5(header, BIGW, BIGW - 9, 3, '%2s' % pal_subidx, 252)
+
+    draw_string3x5(header, BIGW, BIGW - 45 - 9, 3, pal_name, 252)
+    finaldst.extend(convert_to_24bpp(header, palette))
+
+  bigdst = bytearray([255] * BIGW * 36)
+  hline(bigdst, 1, 137, 0, 254)
+  hline(bigdst, 1, 137, 34, 254)
+  vline(bigdst, 1, 0, 34, 254)
+  vline(bigdst, 137, 0, 34, 254)
+
+  encode_id(bigdst, 137, 35, e.encoded_id << 9 | 0x55)
+
+  src = decode_3bit_tileset(e.tileset) # returns 128x64
+
+  for i in range(16*4):
+    x, y = i % 16, i // 16
+    dst_offs = (y * 8 + 1 + (y >> 1)) * BIGW + x * 8 + 2 + (x >> 1)
+    if x & 8: dst_offs
+    m = e.matrix[y][x]
+    if m == '.':
+      fill_with_empty(bigdst, dst_offs)
+    else:
+      copy_8x8(bigdst, dst_offs, src, x * 8 + y * 8 * 128, 0)
+      if master_tilesheets:
+        master_tilesheets.insert(e.tileset, src, x, y, palette, 0)
+
+  # collapse unused matrix sections
+  if all(m=='.' for m in e.matrix[0]) and all(m=='.' for m in e.matrix[1]):
+    del bigdst[1*BIGW:17*BIGW]
+  elif all(m=='.' for m in e.matrix[2]) and all(m=='.' for m in e.matrix[3]):
+    del bigdst[18*BIGW:34*BIGW]
+
+  draw_string3x5(bigdst, BIGW, BIGW - 9, 2, ' %d' % e.ss_idx, 252)
+  draw_string3x5(bigdst, BIGW, BIGW - 9, 2 + 9, '%.2d' % e.tileset, 252)
+  
+  finaldst.extend(convert_to_24bpp(bigdst, palette))
+
+def fixup_entries():
+  e_prev = None
+  for e in sprite_sheet_info.entries:
+    fixup_sprite_set_entry(e, e_prev)
+    e_prev = e
+
+class MasterTilesheets:
+  def __init__(self):
+    self.sheets = {}
+
+  def insert(self, tileset, src, xp, yp, palette, pal_base):
+    sheet = self.sheets.get(tileset)
+    if sheet == None:
+      sheet = (array.array('I', [0x00f000] * 128 * 32), None)
+      self.sheets[tileset] = sheet
+    sheet24 = sheet[0]
+    for y in range(yp * 8, yp * 8 + 8):
+      for x in range(xp * 8, xp * 8 + 8):
+        o = y * 128 + x
+        sheet24[o] = palette[pal_base + src[o]]
+
+  def add_verify_8x8(self, tileset, pal_lut, img_data, pitch, dst_pos, src_pos):
+    # add to the master sheet
+    sheet = self.sheets.get(tileset)
+    if sheet == None:
+      sheet = (array.array('I', [0x00f000] * 128 * 32), bytearray([248] * 128 * 32))
+      self.sheets[tileset] = sheet
+    sheet24, sheet8 = sheet[0], sheet[1]
+    for y in range(8):
+      for x in range(8):
+        pixel = img_data[src_pos + y * pitch + x]
+        o = dst_pos + y * 128 + x 
+        sheet24[o] = pixel
+        pixel8 = pal_lut.get(pixel)
+        if pixel8 == None:
+          raise Exception('Pixel #%.6x not found' % pixel)
+        if sheet8[o] != 248 and pixel8 != sheet8[o]:
+          raise Exception('Pixel has more than one value')
+        sheet8[o] = pixel8
+
+  def save_to_all_sheets(self):
+    rv = array.array('I')
+    rv8 = bytearray()
+
+    def extend_with_string_line(text):
+      header = array.array('I', [0xf0f0f0] * 128 * 8)
+      draw_string3x5(header, 128, 1, 2, text, 0x404040)
+      rv.extend(header)
+      header8 = bytearray([255] * 128 * 8)
+      draw_string3x5(header8, 128, 1, 2, text, 254)
+      rv8.extend(header8)
+    extend_with_string_line('AUTO GENERATED DO NOT EDIT')
+    kk = 0
+    for k in sorted(self.sheets.keys()):
+      extend_with_string_line('Sheet %d' % k)
+      rv.extend(self.sheets[k][0])
+      rv8.extend(self.sheets[k][1])
+      if k != kk:
+        print('Missing %d' % kk)
+      kk = k + 1
+    palette8 = get_full_palette(4, 0)
+    for i, v in enumerate(convert_snes_palette_to_int(get_palette_subset(5, 0))):
+      palette8[i + 9] = v
+    palette8[248] = 0x00f000
+    save_as_png((128, len(rv)//128), rv8, 'sprites/all_sheets_8bit.png', palette = convert_int24_palette_to_bytes(palette8))
+    save_as_24bpp_png((128, len(rv)//128), rv, 'sprites/all_sheets.png')
+    self.verify_identical_to_snes()
+
+  def verify_identical_to_snes(self):
+    for tileset in range(103):
+      a = self.encode_sheet_in_snes_format(tileset)
+      b = get_unpacked_snes_tileset(tileset)
+      if a != b:
+        print('Sheet %d mismatch' % tileset)
+        break
+
+  # convert a tileset to the 8bit snes format, 24 bytes per tile
+  def encode_sheet_in_snes_format(self, tileset):
+    sheet8 = self.sheets[tileset][1]
+    result = bytearray(24 * 16 * 4)
+    def encode_into(dst_pos, src_pos):
+      for y in range(8):
+        for x in range(8):
+          b = sheet8[src_pos + 128 * y + 7 - x]
+          result[dst_pos+2*y] |= (b & 1) << x
+          result[dst_pos+2*y+1] |= ((b & 2) >> 1) << x
+          result[dst_pos+y+16] |= ((b & 4) >> 2) << x
+    for y in range(4):
+      for x in range(16):
+        encode_into((y * 16 + x) * 24, y * 8 * 128 + x * 8)
+    return result
+
+
+def decode_sprite_sheets():
+  master_tilesheets = MasterTilesheets()
+
+  fixup_entries()
+  for char in "0123456789ABCDEFX":
+    dst = []
+    for e in sprite_sheet_info.entries:
+      if e.name[0].upper() == char:
+        save_sprite_set_entry(dst, e, master_tilesheets)
+    if len(dst):
+      save_as_24bpp_png((BIGW, len(dst) // BIGW), dst, 'sprites/sprites_%s.png' % char)
+  master_tilesheets.save_to_all_sheets()
+
+def load_sprite_sheets():
+  master_tilesheets = MasterTilesheets()
+  for char in "0123456789ABCDEFX":
+    img = Image.open('sprites/sprites_%s.png' % char)
+    img_size = img.size
+    img_data = array.array('I', (a[0] | a[1] << 8 | a[2] << 16 for a in img.getdata()))
+    pitch = img.size[0]
+
+    def find_next_tag(start_pos):
+      for i in range(start_pos, len(img_data) - pitch * 2, pitch if start_pos != 0 else 1):
+        if img_data[i+0] == 0x404040 and img_data[i+pitch] == 0x404040 and \
+          img_data[i+pitch * 2 + 0] == 0xf0f0f0 and img_data[i+pitch * 2 - 1] == 0xe0e0e0 and \
+          img_data[i+pitch * 2 - 2] == 0xf0f0f0 and img_data[i+pitch * 2 - 3] == 0xe0e0e0 and \
+          img_data[i+pitch * 2 - 4] == 0xf0f0f0 and img_data[i+pitch * 2 - 5] == 0xe0e0e0 and \
+          img_data[i+pitch * 2 - 6] == 0xf0f0f0 and img_data[i+pitch * 2 - 7] == 0xe0e0e0:
+          return i + pitch * 2
+      else:
+        return None
+
+    def decode_tag(pos):
+      r = 0
+      for i in range(64):
+        v = img_data[pos - 63 + i]
+        assert v in (0xe0e0e0, 0xf0f0f0)
+        r = r * 2 + (v == 0xf0f0f0)
+      if (r & 0x1ff) != 0x55:
+        raise Exception('Invalid tag')
+      r >>= 9
+      if (((r >> 8) + 41) % 255) != (r & 0xff):
+        raise Exception('Invalid checksum')
+      r >>= 8
+      return r & 7, (r >> 3) & 127, (r >> 10) & 1, (r >> 11) & 31
+
+    def determine_image_rects(tag_pos):
+      h = 1
+      while (img_data[tag_pos - pitch * (h + 1)] == 0x404040):
+        h += 1
+      if h == 19:
+        if img_data[tag_pos - pitch * 2 - 1] == 0xe0e0e0:
+          image_rects = ((0, tag_pos - 135 - pitch * 18), )
+        elif img_data[tag_pos - pitch * 18 - 1] == 0xe0e0e0:
+          image_rects = ((1, tag_pos - 135 - pitch * 17), )
+        else:
+          raise Exception('cant uncompact')
+      elif h == 35:
+        image_rects = ((0, tag_pos - 135 - pitch * 34), (1, tag_pos - 135 - pitch * 17))
+      else:
+        raise Exception('height not found')
+      return image_rects, h
+
+    def get_pal_lut(tag_pos, is_high):
+      # read palette colors from the image pixels
+      pal_lut = {img_data[tag_pos + 5 * i] : i + (9 if is_high else 1) for i in range(7)}
+      pal_lut[0x808000] = 0 # transparent color
+      return pal_lut
+
+    def is_empty(pos):
+      return all(img_data[pos+y*pitch+x] == 0xf0f0f0 for x in range(8) for y in range(8))
+
+    pal_lut = None
+    tag_pos = 0
+    while True:
+      tag_pos = find_next_tag(tag_pos)
+      if tag_pos == None:
+        break
+      pal_base, tileset, headerless, pal_subidx = decode_tag(tag_pos)
+      image_rects, box_height = determine_image_rects(tag_pos)
+      if not headerless:
+        pal_lut = get_pal_lut(tag_pos - pitch * (box_height + 3) - 34, is_high_3bit_tileset(tileset))
+      for idx, sheet_pos in image_rects:
+        for y in range(2):
+          for x in range(16):
+            src_pos = sheet_pos + (y * 8 + (y >> 1)) * pitch + (x * 8 + (x >> 1))
+            dst_pos = (y + idx * 2) * 8 * 128 + x * 8
+            if not is_empty(src_pos):
+              master_tilesheets.add_verify_8x8(tileset, pal_lut, img_data, pitch, dst_pos, src_pos)
+  return master_tilesheets
--- /dev/null
+++ b/tables/sprites/.gitignore
@@ -1,0 +1,1 @@
+/*.png
--- a/tables/tables.py
+++ b/tables/tables.py
@@ -880,3 +880,253 @@
 82 : "Warp", 0x84 : "Staircase", 0x86 : 'Bombable', 0x88 : 'Switch' }
   for k,v in kSpecialSecret.items():
     r[k] = '%.2X-%s' % (k, v)
+n kSpecialSecret.items():
+    r[k] = '%.2X-%s' % (k, v)
+  return r
+
+kSecretNames = get_secret_names()
+kSecretNamesRev = invert_dict(kSecretNames)
+
+kCompSpritePtrs = [
+  0x10f000,0x10f600,0x10fc00,0x118200,0x118800,0x118e00,0x119400,0x119a00,
+  0x11a000,0x11a600,0x11ac00,0x11b200,0x14fffc,0x1585d4,0x158ab6,0x158fbe,
+  0x1593f8,0x1599a6,0x159f32,0x15a3d7,0x15a8f1,0x15aec6,0x15b418,0x15b947,
+  0x15bed0,0x15c449,0x15c975,0x15ce7c,0x15d394,0x15d8ac,0x15ddc0,0x15e34c,
+  0x15e8e8,0x15ee31,0x15f3a6,0x15f92d,0x15feba,0x1682ff,0x1688e0,0x168e41,
+  0x1692df,0x169883,0x169cd0,0x16a26e,0x16a275,0x16a787,0x16aa06,0x16ae9d,
+  0x16b3ff,0x16b87e,0x16be6b,0x16c13d,0x16c619,0x16cbbb,0x16d0f1,0x16d641,
+  0x16d95a,0x16dd99,0x16e278,0x16e760,0x16ed25,0x16f20f,0x16f6b7,0x16fa5f,
+  0x16fd29,0x1781cd,0x17868d,0x178b62,0x178fd5,0x179527,0x17994b,0x179ea7,
+  0x17a30e,0x17a805,0x17acf8,0x17b2a2,0x17b7f9,0x17bc93,0x17c237,0x17c78e,
+  0x17cd55,0x17d2bc,0x17d82f,0x17dcec,0x17e1cc,0x17e36b,0x17e842,0x17eb38,
+  0x17ed58,0x17f06c,0x17f4fd,0x17fa39,0x17ff86,0x18845c,0x1889a1,0x188d64,
+  0x18919d,0x189610,0x189857,0x189b24,0x189dd2,0x18a03f,0x18a4ed,0x18a7ba,
+  0x18aedf,0x18af0d,0x18b520,0x18b953,
+]
+
+kCompBgPtrs = [
+  0x11b800,0x11bce2,0x11c15f,0x11c675,0x11cb84,0x11cf4c,0x11d2ce,0x11d726,
+  0x11d9cf,0x11dec4,0x11e393,0x11e893,0x11ed7d,0x11f283,0x11f746,0x11fc21,
+  0x11fff2,0x128498,0x128a0e,0x128f30,0x129326,0x129804,0x129d5b,0x12a272,
+  0x12a6fe,0x12aa77,0x12ad83,0x12b167,0x12b51d,0x12b840,0x12bd54,0x12c1c9,
+  0x12c73d,0x12cc86,0x12d198,0x12d6b1,0x12db6a,0x12e0ea,0x12e6bd,0x12eb51,
+  0x12f135,0x12f6c5,0x12fc71,0x138129,0x138693,0x138bad,0x139117,0x139609,
+  0x139b21,0x13a074,0x13a619,0x13ab2b,0x13b00c,0x13b4f5,0x13b9eb,0x13bebf,
+  0x13c3ce,0x13c817,0x13cb68,0x13cfb5,0x13d460,0x13d8c2,0x13dd7a,0x13e266,
+  0x13e7af,0x13ece5,0x13f245,0x13f6f0,0x13fc30,0x1480e9,0x14863b,0x148a7c,
+  0x148f2a,0x149346,0x1497ed,0x149cc2,0x14a173,0x14a61d,0x14ab5d,0x14b083,
+  0x14b4bd,0x14b94e,0x14be0e,0x14c291,0x14c7ba,0x14cce4,0x14d1db,0x14d6bd,
+  0x14db77,0x14ded1,0x14e2ac,0x14e754,0x14ebae,0x14ef4e,0x14f309,0x14f6f4,
+  0x14fa55,0x14ff8c,0x14ff93,0x14ff9a,0x14ffa1,0x14ffa8,0x14ffaf,0x14ffb6,
+  0x14ffbd,0x14ffc4,0x14ffcb,0x14ffd2,0x14ffd9,0x14ffe0,0x14ffe7,0x14ffee,
+  0x14fff5,0x18b520,0x18b953,
+]
+
+kSpriteTilesets = [
+  ( 0, 73,   0,  0),
+  (70, 73,  12, 29),
+  (72, 73,  19, 29),
+  (70, 73,  19, 14),
+  (72, 73,  12, 17),
+  (72, 73,  12, 16),
+  (79, 73,  74, 80),
+  (14, 73,  74, 17),
+  (70, 73,  18,  0),
+  ( 0, 73,   0, 80),
+  ( 0, 73,   0, 17),
+  (72, 73,  12,  0),
+  ( 0,  0,  55, 54),
+  (72, 73,  76, 17),
+  (93, 44,  12, 68),
+  ( 0,  0,  78,  0),
+  (15,  0,  18, 16),
+  ( 0,  0,   0, 76),
+  ( 0, 13,  23,  0),
+  (22, 13,  23, 27),
+  (22, 13,  23, 20),
+  (21, 13,  23, 21),
+  (22, 13,  24, 25),
+  (22, 13,  23, 25),
+  (22, 13,   0,  0),
+  (22, 13,  24, 27),
+  (15, 73,  74, 17),
+  (75, 42,  92, 21),
+  (22, 73,  23, 29),
+  ( 0,  0,   0, 21),
+  (22, 13,  23, 16),
+  (22, 73,  18,  0),
+  (22, 73,  12, 17),
+  ( 0,  0,  18, 16),
+  (22, 13,   0, 17),
+  (22, 73,  12,  0),
+  (22, 13,  76, 17),
+  (14, 13,  74, 17),
+  (22, 26,  23, 27),
+  (79, 52,  74, 80),
+  (53, 77, 101, 54),
+  (74, 52,  78,  0),
+  (14, 52,  74, 17),
+  (81, 52,  93, 89),
+  (75, 73,  76, 17),
+  (45,  0,   0,  0),
+  (93,  0,  18, 89),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  (71, 73,  43, 45),
+  (70, 73,  28, 82),
+  ( 0, 73,  28, 82),
+  (93, 73,   0, 82),
+  (70, 73,  19, 82),
+  (75, 77,  74, 90),
+  (71, 73,  28, 82),
+  (75, 77,  57, 54),
+  (31, 44,  46, 82),
+  (31, 44,  46, 29),
+  (47, 44,  46, 82),
+  (47, 44,  46, 49),
+  (31, 30,  48, 82),
+  (81, 73,  19,  0),
+  (79, 73,  19, 80),
+  (79, 77,  74, 80),
+  (75, 73,  76, 43),
+  (31, 32,  34, 83),
+  (85, 61,  66, 67),
+  (31, 30,  35, 82),
+  (31, 30,  57, 58),
+  (31, 30,  58, 62),
+  (31, 30,  60, 61),
+  (64, 30,  39, 63),
+  (85, 26,  66, 67),
+  (31, 30,  42, 82),
+  (31, 30,  56, 82),
+  (31, 32,  40, 82),
+  (31, 32,  38, 82),
+  (31, 44,  37, 82),
+  (31, 32,  39, 82),
+  (31, 30,  41, 82),
+  (31, 44,  59, 82),
+  (70, 73,  36, 82),
+  (33, 65,  69, 51),
+  (31, 44,  40, 49),
+  (31, 13,  41, 82),
+  (31, 30,  39, 82),
+  (31, 32,  39, 83),
+  (72, 73,  19, 82),
+  (14, 30,  74, 80),
+  (31, 32,  38, 83),
+  (21,  0,   0,  0),
+  (31,  0,  42, 82),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  ( 0,  0,   0,  0),
+  (50,  0,   0,  8),
+  (93, 73,   0, 82),
+  (85, 73,  66, 67),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 86,  87, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+  (97, 86,  87, 80),
+  (97, 86,  99, 80),
+  (97, 86,  87, 80),
+  (97, 86,  51, 80),
+  (97, 86,  87, 80),
+  (97, 98,  99, 80),
+  (97, 98,  99, 80),
+]
+
+kDungPalinfos = [
+  ( 0,  0,  3,  1),
+  ( 2,  0,  3,  1),
+  ( 4,  0, 10,  1),
+  ( 6,  0,  1,  7),
+  (10,  2,  2,  7),
+  ( 4,  4,  3, 10),
+  (12,  5,  8, 20),
+  (14,  0,  3, 10),
+  ( 2,  0, 15, 20),
+  (10,  2,  0,  7),
+  ( 2,  0, 15, 12),
+  ( 6,  0,  6,  7),
+  ( 0,  0, 14, 18),
+  (18,  5,  5, 11),
+  (18,  0,  2, 12),
+  (16,  5, 10,  7),
+  (16,  0, 16, 12),
+  (22,  7,  2,  7),
+  (22,  0,  7, 15),
+  ( 8,  0,  4, 12),
+  ( 8,  0,  4,  9),
+  ( 4,  0,  3,  1),
+  (20,  0,  4,  4),
+  (20,  0, 20, 12),
+  (24,  5,  7, 11),
+  (24,  6, 16, 12),
+  (26,  5,  8, 20),
+  (26,  2,  0,  7),
+  ( 6,  0,  3, 10),
+  (28,  0,  3,  1),
+  (30,  0, 11, 17),
+  ( 4,  0, 11, 17),
+  (14,  0,  0,  2),
+  (32,  8, 19, 13),
+  (10,  0,  3, 10),
+  (20,  0,  4,  4),
+  (26,  2,  2,  7),
+  (26, 10,  0,  0),
+  ( 0,  0,  3,  2),
+  (14,  0,  3,  7),
+  (26,  5,  5, 11),
+]
+
+kOwSprPalInfo = [
+  -1, -1, 3, 10, 3, 6, 3, 1, 0, 2, 3, 14, 3, 2, 19, 1, 11, 12, 17, 1, 7, 5, 17, 0,
+  9, 11, 15, 5, 3, 5, 3, 7, 15, 2, 10, 2, 5, 1, 12, 14,
+]
+
+kSpriteInit_Flags3 = [
+  0x19,  0xb, 0x1b, 0x4b, 0x41, 0x41, 0x41, 0x4d, 0x1d,    1, 0x1d, 0x19, 0x8d, 0x1b,    9, 0x9d,
+  0x3d,    1,    9, 0x11, 0x40,    1, 0x4d, 0x19,    7, 0x1d, 0x59, 0x80, 0x4d, 0x40,    1, 0x49,
+  0x1b, 0x41,    3, 0x13, 0x15, 0x41, 0x18, 0x1b, 0x41, 0x47,  0xf, 0x49, 0x4b, 0x4d, 0x41, 0x47,
+  0x49, 0x4d, 0x49, 0x40, 0x4d, 0x47, 0x49, 0x41, 0x74, 0x47, 0x5b, 0x58, 0x51, 0x49, 0x1d, 0x5d,
+     3, 0x19, 0x1b, 0x17, 0x19, 0x17, 0x19, 0x1b, 0x17, 0x17, 0x17, 0x1b,  0xd,    9, 0x19, 0x19,
+  0x49, 0x5d, 0x5b, 0x49,  0xd,    3, 0x13, 0x41, 0x1b, 0x5b, 0x5d, 0x43, 0x43, 0x4d, 0x4d, 0x4d,
+  0x4d, 0x4d, 0x49,    1,    0, 0x41, 0x4d, 0x4d, 0x4d, 0x4d, 0x1d,    9, 0xc4,  0xd,  0xd,    9,
+     3,    3, 0x4b, 0x47, 0x47, 0x49, 0x49, 0x41, 0x47, 0x36, 0x8b, 0x49, 0x1d, 0x49, 0x43, 0x43,
+  0x43,  0xb, 0x41,  0xd,    7,  0xb, 0x1d, 0x43,  0xd, 0x43,  0xd, 0x1d, 0x4d, 0x4d, 0x1b, 0x1b,
+   0xa,  0xb,    0,    5,  0xd,    1,    1,    1,    1,  0xb,    5,    1,    1,    1,    7, 0x17,
+  0x19,  0xd,  0xd, 0x80, 0x4d, 0x19, 0x17, 0x19,  0xb,    9,  0xd, 0x4a, 0x12, 0x49, 0xc3, 0xc3,
--- a/tables/util.py
+++ b/tables/util.py
@@ -2,6 +2,7 @@
 import sys
 import hashlib
 import os
+from functools import cache
 
 # Both are common SNES rom extensions. For Zelda3 (NA), they are equivalent files.
 COMMON_ROM_NAMES = ['zelda3.sfc', 'zelda3.smc']
@@ -8,6 +9,36 @@
 DEFAULT_ROM_DIRECTORY = os.path.dirname(__file__)
 ZELDA3_SHA256 = '66871d66be19ad2c34c927d6b14cd8eb6fc3181965b6e517cb361f7316009cfb'
 
+def load_rom(filename):
+  global ROM
+  ROM = LoadedRom(filename)
+  return ROM
+
+def get_byte(addr):
+  return ROM.get_byte(addr)
+
+@cache
+def get_bytes(addr, n):
+  return ROM.get_bytes(addr, n)
+
+@cache
+def get_words(addr, n):
+  return ROM.get_words(addr, n)
+
+def get_int8(ea):
+  b = get_byte(ea)
+  if b & 0x80: b -= 256
+  return b
+
+def get_int16(ea):
+  b = get_word(ea)
+  if b & 0x8000: b -= 65536
+  return b
+
+def get_word(addr):
+  return ROM.get_word(addr)
+
+
 class LoadedRom:
   def __init__(self, path = None):
     rom_path = self.__get_rom_path(path)
@@ -28,7 +59,7 @@
     return self.get_byte(ea) + self.get_byte(ea + 1) * 256 + self.get_byte(ea + 2) * 65536
 
   def get_bytes(self, addr, n):
-    r = []
+    r = bytearray()
     for i in range(n):
       r.append(self.get_byte(addr))
       addr += 1
--- a/tagalong.c
+++ b/tagalong.c
@@ -662,7 +662,7 @@
  uint8 pal;
 skip_first_sprites:
   pal = kTagalongDraw_Pals[follower_indicator];
-  if (pal == 7 && overworld_palette_swap_flag)
+  if (pal == 7 && palette_swap_flag)
     pal = 0;
 
   if (follower_indicator == 13) {
--- a/variables.h
+++ b/variables.h
@@ -603,19 +603,19 @@
 #define unused_config_gfx (*(uint16*)(g_ram+0xAA6))
 #define overworld_palette_aux_or_main (*(uint16*)(g_ram+0xAA8))
 #define load_chr_halfslot_even_odd (*(uint8*)(g_ram+0xAAA))
-#define overworld_palette_sp0 (*(uint8*)(g_ram+0xAAC))
-#define sprite_aux1_palette (*(uint8*)(g_ram+0xAAD))
-#define sprite_aux2_palette (*(uint8*)(g_ram+0xAAE))
+#define palette_sp0l (*(uint8*)(g_ram+0xAAC))
+#define palette_sp5l (*(uint8*)(g_ram+0xAAD))
+#define palette_sp6l (*(uint8*)(g_ram+0xAAE))
 #define byte_7E0AB0 (*(uint8*)(g_ram+0xAB0))
-#define palette_sp6 (*(uint8*)(g_ram+0xAB1))
+#define palette_sp6r_indoors (*(uint8*)(g_ram+0xAB1))
 #define hud_palette (*(uint8*)(g_ram+0xAB2))
 #define overworld_palette_mode (*(uint8*)(g_ram+0xAB3))
 #define overworld_palette_aux1_bp2to4_hi (*(uint8*)(g_ram+0xAB4))
 #define overworld_palette_aux2_bp5to7_hi (*(uint8*)(g_ram+0xAB5))
-#define dung_hdr_palette_1 (*(uint8*)(g_ram+0xAB6))
+#define palette_main_indoors (*(uint8*)(g_ram+0xAB6))
 #define byte_7E0AB7 (*(uint8*)(g_ram+0xAB7))
 #define overworld_palette_aux3_bp7_lo (*(uint8*)(g_ram+0xAB8))
-#define overworld_palette_swap_flag (*(uint8*)(g_ram+0xABD))
+#define palette_swap_flag (*(uint8*)(g_ram+0xABD))
 #define flag_overworld_area_did_change (*(uint8*)(g_ram+0xABF))
 #define dma_source_addr_6 (*(uint16*)(g_ram+0xAC0))
 #define dma_source_addr_11 (*(uint16*)(g_ram+0xAC2))
--- a/zelda_cpu_infra.c
+++ b/zelda_cpu_infra.c
@@ -382,7 +382,15 @@
   WORD(rom[(addr >> 16) << 15 | (addr & 0x7fff)]) = value;
 }
 
+static void PatchRomArray(uint8_t *rom, uint32_t addr, const uint8 *values, int n) {
+  for (int i = 0; i < n; i++) {
+    rom[(addr >> 16) << 15 | (addr & 0x7fff)] = values[i];
+    addr += 1;
+  }
+}
 
+
+
 static void PatchRom(uint8_t *rom) {
   //  fix a bug with unitialized memory
   {
@@ -552,6 +560,10 @@
 
   PatchRomWord(rom, 0xddfac + 1, 0xfa85, 0xfa70); // call Hud_Rebuild instead of Hud_UpdateOnly
 
+  // Make sure it's not calling Decomp_spr on tilesheets less than 12
+  PatchRomWord(rom, 0xe589, 0xe772, 0xe852);  // call New addr
+  static const uint8 kFixSoItWontDecodeSheetLessThan12[] = { 0xc0, 0x0c, 0xb0, 0x02, 0xa0, 0x0c, 0x4c, 0x72, 0xe7 };
+  PatchRomArray(rom, 0xe852, kFixSoItWontDecodeSheetLessThan12, sizeof(kFixSoItWontDecodeSheetLessThan12));
 }